• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // WebAssembly C++ API
2 
3 #ifndef __WASM_HH
4 #define __WASM_HH
5 
6 #include <cassert>
7 #include <cstddef>
8 #include <cstdint>
9 #include <cstring>
10 #include <memory>
11 #include <limits>
12 #include <string>
13 
14 
15 ///////////////////////////////////////////////////////////////////////////////
16 // Auxiliaries
17 
18 // Machine types
19 
20 static_assert(sizeof(float) == sizeof(int32_t), "incompatible float type");
21 static_assert(sizeof(double) == sizeof(int64_t), "incompatible double type");
22 static_assert(sizeof(intptr_t) == sizeof(int32_t) ||
23               sizeof(intptr_t) == sizeof(int64_t), "incompatible pointer type");
24 
25 using byte_t = char;
26 using float32_t = float;
27 using float64_t = double;
28 
29 
30 namespace wasm {
31 
32 // Vectors
33 
34 template<class T>
35 class vec {
36   static const size_t invalid_size = SIZE_MAX;
37 
38   size_t size_;
39   std::unique_ptr<T[]> data_;
40 
41 #ifdef WASM_API_DEBUG
42   void make_data();
43   void free_data();
44 #else
make_data()45   void make_data() {}
free_data()46   void free_data() {}
47 #endif
48 
vec(size_t size)49   vec(size_t size) : vec(size, size ? new(std::nothrow) T[size] : nullptr) {
50     make_data();
51   }
52 
vec(size_t size,T * data)53   vec(size_t size, T* data) : size_(size), data_(data) {
54     assert(!!size_ == !!data_ || size_ == invalid_size);
55   }
56 
57 public:
58   using elem_type = T;
59 
vec(vec<T> && that)60   vec(vec<T>&& that) : vec(that.size_, that.data_.release()) {}
61 
~vec()62   ~vec() {
63     free_data();
64   }
65 
operator bool() const66   operator bool() const {
67     return bool(size_ != invalid_size);
68   }
69 
size() const70   auto size() const -> size_t {
71     return size_;
72   }
73 
get() const74   auto get() const -> const T* {
75     return data_.get();
76   }
77 
get()78   auto get() -> T* {
79     return data_.get();
80   }
81 
release()82   auto release() -> T* {
83     return data_.release();
84   }
85 
reset()86   void reset() {
87     free_data();
88     size_ = invalid_size;
89     data_.reset();
90   }
91 
reset(vec & that)92   void reset(vec& that) {
93     free_data();
94     size_ = that.size_;
95     data_.reset(that.data_.release());
96   }
97 
operator =(vec && that)98   auto operator=(vec&& that) -> vec& {
99     reset(that);
100     return *this;
101   }
102 
operator [](size_t i)103   auto operator[](size_t i) -> T& {
104     assert(i < size_);
105     return data_[i];
106   }
107 
operator [](size_t i) const108   auto operator[](size_t i) const -> const T& {
109     assert(i < size_);
110     return data_[i];
111   }
112 
copy() const113   auto copy() const -> vec {
114     auto v = vec(size_);
115     if (v) for (size_t i = 0; i < size_; i++) v.data_[i] = data_[i];
116     return v;
117   }
118 
119   // TODO: This can't be used for e.g. vec<Val>
deep_copy() const120   auto deep_copy() const -> vec {
121     auto v = vec(size_);
122     if (v) for (size_t i = 0; i < size_; ++i) v.data_[i] = data_[i]->copy();
123     return v;
124   }
125 
make_uninitialized(size_t size=0)126   static auto make_uninitialized(size_t size = 0) -> vec {
127     return vec(size);
128   }
129 
make(size_t size,T init[])130   static auto make(size_t size, T init[]) -> vec {
131     auto v = vec(size);
132     if (v) for (size_t i = 0; i < size; ++i) v.data_[i] = std::move(init[i]);
133     return v;
134   }
135 
make(std::string s)136   static auto make(std::string s) -> vec<char> {
137     auto v = vec(s.length() + 1);
138     if (v) std::strcpy(v.get(), s.data());
139     return v;
140   }
141 
142   // TODO(mvsc): MVSC requires this special case:
make()143   static auto make() -> vec {
144     return vec(0);
145   }
146 
147   template<class... Ts>
make(Ts &&...args)148   static auto make(Ts&&... args) -> vec {
149     T data[] = { std::move(args)... };
150     return make(sizeof...(Ts), data);
151   }
152 
adopt(size_t size,T data[])153   static auto adopt(size_t size, T data[]) -> vec {
154     return vec(size, data);
155   }
156 
invalid()157   static auto invalid() -> vec {
158     return vec(invalid_size, nullptr);
159   }
160 };
161 
162 
163 // Ownership
164 
165 template<class T> using own = std::unique_ptr<T>;
166 template<class T> using ownvec = vec<own<T>>;
167 
168 template<class T>
make_own(T * x)169 auto make_own(T* x) -> own<T> { return own<T>(x); }
170 
171 
172 ///////////////////////////////////////////////////////////////////////////////
173 // Runtime Environment
174 
175 // Configuration
176 
177 class Config {
178 public:
179   Config() = delete;
180   ~Config();
181   void operator delete(void*);
182 
183   static auto make() -> own<Config>;
184 
185   // Implementations may provide custom methods for manipulating Configs.
186 };
187 
188 
189 // Engine
190 
191 class Engine {
192 public:
193   Engine() = delete;
194   ~Engine();
195   void operator delete(void*);
196 
197   static auto make(own<Config>&& = Config::make()) -> own<Engine>;
198 };
199 
200 
201 // Store
202 
203 class Store {
204 public:
205   Store() = delete;
206   ~Store();
207   void operator delete(void*);
208 
209   static auto make(Engine*) -> own<Store>;
210 };
211 
212 
213 ///////////////////////////////////////////////////////////////////////////////
214 // Type Representations
215 
216 // Type attributes
217 
218 enum Mutability : uint8_t { CONST, VAR };
219 
220 struct Limits {
221   uint32_t min;
222   uint32_t max;
223 
Limitswasm::Limits224   Limits(uint32_t min, uint32_t max = std::numeric_limits<uint32_t>::max()) :
225     min(min), max(max) {}
226 };
227 
228 
229 // Value Types
230 
231 enum ValKind : uint8_t {
232   I32, I64, F32, F64,
233   ANYREF = 128, FUNCREF,
234 };
235 
is_num(ValKind k)236 inline bool is_num(ValKind k) { return k < ANYREF; }
is_ref(ValKind k)237 inline bool is_ref(ValKind k) { return k >= ANYREF; }
238 
239 
240 class ValType {
241 public:
242   ValType() = delete;
243   ~ValType();
244   void operator delete(void*);
245 
246   static auto make(ValKind) -> own<ValType>;
247   auto copy() const -> own<ValType>;
248 
249   auto kind() const -> ValKind;
is_num() const250   auto is_num() const -> bool { return wasm::is_num(kind()); }
is_ref() const251   auto is_ref() const -> bool { return wasm::is_ref(kind()); }
252 };
253 
254 
255 // External Types
256 
257 enum ExternKind : uint8_t {
258   EXTERN_FUNC, EXTERN_GLOBAL, EXTERN_TABLE, EXTERN_MEMORY
259 };
260 
261 class FuncType;
262 class GlobalType;
263 class TableType;
264 class MemoryType;
265 
266 class ExternType {
267 public:
268   ExternType() = delete;
269   ~ExternType();
270   void operator delete(void*);
271 
272   auto copy() const-> own<ExternType>;
273 
274   auto kind() const -> ExternKind;
275 
276   auto func() -> FuncType*;
277   auto global() -> GlobalType*;
278   auto table() -> TableType*;
279   auto memory() -> MemoryType*;
280 
281   auto func() const -> const FuncType*;
282   auto global() const -> const GlobalType*;
283   auto table() const -> const TableType*;
284   auto memory() const -> const MemoryType*;
285 };
286 
287 
288 // Function Types
289 
290 class FuncType : public ExternType {
291 public:
292   FuncType() = delete;
293   ~FuncType();
294 
295   static auto make(
296     ownvec<ValType>&& params = ownvec<ValType>::make(),
297     ownvec<ValType>&& results = ownvec<ValType>::make()
298   ) -> own<FuncType>;
299 
300   auto copy() const -> own<FuncType>;
301 
302   auto params() const -> const ownvec<ValType>&;
303   auto results() const -> const ownvec<ValType>&;
304 };
305 
306 
307 // Global Types
308 
309 class GlobalType : public ExternType {
310 public:
311   GlobalType() = delete;
312   ~GlobalType();
313 
314   static auto make(own<ValType>&&, Mutability) -> own<GlobalType>;
315   auto copy() const -> own<GlobalType>;
316 
317   auto content() const -> const ValType*;
318   auto mutability() const -> Mutability;
319 };
320 
321 
322 // Table Types
323 
324 class TableType : public ExternType {
325 public:
326   TableType() = delete;
327   ~TableType();
328 
329   static auto make(own<ValType>&&, Limits) -> own<TableType>;
330   auto copy() const -> own<TableType>;
331 
332   auto element() const -> const ValType*;
333   auto limits() const -> const Limits&;
334 };
335 
336 
337 // Memory Types
338 
339 class MemoryType : public ExternType {
340 public:
341   MemoryType() = delete;
342   ~MemoryType();
343 
344   static auto make(Limits) -> own<MemoryType>;
345   auto copy() const -> own<MemoryType>;
346 
347   auto limits() const -> const Limits&;
348 };
349 
350 
351 // Import Types
352 
353 using Name = vec<byte_t>;
354 
355 class ImportType {
356 public:
357   ImportType() = delete;
358   ~ImportType();
359   void operator delete(void*);
360 
361   static auto make(Name&& module, Name&& name, own<ExternType>&&) ->
362     own<ImportType>;
363   auto copy() const -> own<ImportType>;
364 
365   auto module() const -> const Name&;
366   auto name() const -> const Name&;
367   auto type() const -> const ExternType*;
368 };
369 
370 
371 // Export Types
372 
373 class ExportType {
374 public:
375   ExportType() = delete;
376   ~ExportType();
377   void operator delete(void*);
378 
379   static auto make(Name&&, own<ExternType>&&) -> own<ExportType>;
380   auto copy() const -> own<ExportType>;
381 
382   auto name() const -> const Name&;
383   auto type() const -> const ExternType*;
384 };
385 
386 
387 ///////////////////////////////////////////////////////////////////////////////
388 // Runtime Objects
389 
390 // References
391 
392 class Ref {
393 public:
394   Ref() = delete;
395   ~Ref();
396   void operator delete(void*);
397 
398   auto copy() const -> own<Ref>;
399   auto same(const Ref*) const -> bool;
400 
401   auto get_host_info() const -> void*;
402   void set_host_info(void* info, void (*finalizer)(void*) = nullptr);
403 };
404 
405 
406 // Values
407 
408 class Val {
409   ValKind kind_;
410   union impl {
411     int32_t i32;
412     int64_t i64;
413     float32_t f32;
414     float64_t f64;
415     Ref* ref;
416   } impl_;
417 
Val(ValKind kind,impl impl)418   Val(ValKind kind, impl impl) : kind_(kind), impl_(impl) {}
419 
420 public:
Val()421   Val() : kind_(ANYREF) { impl_.ref = nullptr; }
Val(int32_t i)422   Val(int32_t i) : kind_(I32) { impl_.i32 = i; }
Val(int64_t i)423   Val(int64_t i) : kind_(I64) { impl_.i64 = i; }
Val(float32_t z)424   Val(float32_t z) : kind_(F32) { impl_.f32 = z; }
Val(float64_t z)425   Val(float64_t z) : kind_(F64) { impl_.f64 = z; }
Val(own<Ref> && r)426   Val(own<Ref>&& r) : kind_(ANYREF) { impl_.ref = r.release(); }
427 
Val(Val && that)428   Val(Val&& that) : kind_(that.kind_), impl_(that.impl_) {
429     if (is_ref()) that.impl_.ref = nullptr;
430   }
431 
~Val()432   ~Val() {
433     reset();
434   }
435 
is_num() const436   auto is_num() const -> bool { return wasm::is_num(kind_); }
is_ref() const437   auto is_ref() const -> bool { return wasm::is_ref(kind_); }
438 
i32(int32_t x)439   static auto i32(int32_t x) -> Val { return Val(x); }
i64(int64_t x)440   static auto i64(int64_t x) -> Val { return Val(x); }
f32(float32_t x)441   static auto f32(float32_t x) -> Val { return Val(x); }
f64(float64_t x)442   static auto f64(float64_t x) -> Val { return Val(x); }
ref(own<Ref> && x)443   static auto ref(own<Ref>&& x) -> Val { return Val(std::move(x)); }
444   template<class T> inline static auto make(T x) -> Val;
445   template<class T> inline static auto make(own<T>&& x) -> Val;
446 
reset()447   void reset() {
448     if (is_ref() && impl_.ref) {
449       delete impl_.ref;
450       impl_.ref = nullptr;
451     }
452   }
453 
reset(Val & that)454   void reset(Val& that) {
455     reset();
456     kind_ = that.kind_;
457     impl_ = that.impl_;
458     if (is_ref()) that.impl_.ref = nullptr;
459   }
460 
operator =(Val && that)461   auto operator=(Val&& that) -> Val& {
462     reset(that);
463     return *this;
464   }
465 
kind() const466   auto kind() const -> ValKind { return kind_; }
i32() const467   auto i32() const -> int32_t { assert(kind_ == I32); return impl_.i32; }
i64() const468   auto i64() const -> int64_t { assert(kind_ == I64); return impl_.i64; }
f32() const469   auto f32() const -> float32_t { assert(kind_ == F32); return impl_.f32; }
f64() const470   auto f64() const -> float64_t { assert(kind_ == F64); return impl_.f64; }
ref() const471   auto ref() const -> Ref* { assert(is_ref()); return impl_.ref; }
472   template<class T> inline auto get() const -> T;
473 
release_ref()474   auto release_ref() -> own<Ref> {
475     assert(is_ref());
476     auto ref = impl_.ref;
477     impl_.ref = nullptr;
478     return own<Ref>(ref);
479   }
480 
copy() const481   auto copy() const -> Val {
482     if (is_ref() && impl_.ref != nullptr) {
483       // TODO(mvsc): MVSC cannot handle this:
484       // impl impl = {.ref = impl_.ref->copy().release()};
485       impl impl;
486       impl.ref = impl_.ref->copy().release();
487       return Val(kind_, impl);
488     } else {
489       return Val(kind_, impl_);
490     }
491   }
492 };
493 
494 
make(int32_t x)495 template<> inline auto Val::make<int32_t>(int32_t x) -> Val { return Val(x); }
make(int64_t x)496 template<> inline auto Val::make<int64_t>(int64_t x) -> Val { return Val(x); }
make(float32_t x)497 template<> inline auto Val::make<float32_t>(float32_t x) -> Val { return Val(x); }
make(float64_t x)498 template<> inline auto Val::make<float64_t>(float64_t x) -> Val { return Val(x); }
make(own<Ref> && x)499 template<> inline auto Val::make<Ref>(own<Ref>&& x) -> Val {
500   return Val(std::move(x));
501 }
502 
make(uint32_t x)503 template<> inline auto Val::make<uint32_t>(uint32_t x) -> Val {
504   return Val(static_cast<int32_t>(x));
505 }
make(uint64_t x)506 template<> inline auto Val::make<uint64_t>(uint64_t x) -> Val {
507   return Val(static_cast<int64_t>(x));
508 }
509 
get() const510 template<> inline auto Val::get<int32_t>() const -> int32_t { return i32(); }
get() const511 template<> inline auto Val::get<int64_t>() const -> int64_t { return i64(); }
get() const512 template<> inline auto Val::get<float32_t>() const -> float32_t { return f32(); }
get() const513 template<> inline auto Val::get<float64_t>() const -> float64_t { return f64(); }
get() const514 template<> inline auto Val::get<Ref*>() const -> Ref* { return ref(); }
515 
get() const516 template<> inline auto Val::get<uint32_t>() const -> uint32_t {
517   return static_cast<uint32_t>(i32());
518 }
get() const519 template<> inline auto Val::get<uint64_t>() const -> uint64_t {
520   return static_cast<uint64_t>(i64());
521 }
522 
523 
524 // Traps
525 
526 using Message = vec<byte_t>;  // null terminated
527 
528 class Instance;
529 
530 class Frame {
531 public:
532   Frame() = delete;
533   ~Frame();
534   void operator delete(void*);
535 
536   auto copy() const -> own<Frame>;
537 
538   auto instance() const -> Instance*;
539   auto func_index() const -> uint32_t;
540   auto func_offset() const -> size_t;
541   auto module_offset() const -> size_t;
542 };
543 
544 class Trap : public Ref {
545 public:
546   Trap() = delete;
547   ~Trap();
548 
549   static auto make(Store*, const Message& msg) -> own<Trap>;
550   auto copy() const -> own<Trap>;
551 
552   auto message() const -> Message;
553   auto origin() const -> own<Frame>;  // may be null
554   auto trace() const -> ownvec<Frame>;  // may be empty, origin first
555 };
556 
557 
558 // Shared objects
559 
560 template<class T>
561 class Shared {
562 public:
563   Shared() = delete;
564   ~Shared();
565   void operator delete(void*);
566 };
567 
568 
569 // Modules
570 
571 class Module : public Ref {
572 public:
573   Module() = delete;
574   ~Module();
575 
576   static auto validate(Store*, const vec<byte_t>& binary) -> bool;
577   static auto make(Store*, const vec<byte_t>& binary) -> own<Module>;
578   auto copy() const -> own<Module>;
579 
580   auto imports() const -> ownvec<ImportType>;
581   auto exports() const -> ownvec<ExportType>;
582 
583   auto share() const -> own<Shared<Module>>;
584   static auto obtain(Store*, const Shared<Module>*) -> own<Module>;
585 
586   auto serialize() const -> vec<byte_t>;
587   static auto deserialize(Store*, const vec<byte_t>&) -> own<Module>;
588 };
589 
590 
591 // Foreign Objects
592 
593 class Foreign : public Ref {
594 public:
595   Foreign() = delete;
596   ~Foreign();
597 
598   static auto make(Store*) -> own<Foreign>;
599   auto copy() const -> own<Foreign>;
600 };
601 
602 
603 // Externals
604 
605 class Func;
606 class Global;
607 class Table;
608 class Memory;
609 
610 class Extern : public Ref {
611 public:
612   Extern() = delete;
613   ~Extern();
614 
615   auto copy() const -> own<Extern>;
616 
617   auto kind() const -> ExternKind;
618   auto type() const -> own<ExternType>;
619 
620   auto func() -> Func*;
621   auto global() -> Global*;
622   auto table() -> Table*;
623   auto memory() -> Memory*;
624 
625   auto func() const -> const Func*;
626   auto global() const -> const Global*;
627   auto table() const -> const Table*;
628   auto memory() const -> const Memory*;
629 };
630 
631 
632 // Function Instances
633 
634 class Func : public Extern {
635 public:
636   Func() = delete;
637   ~Func();
638 
639   using callback = auto (*)(const Val[], Val[]) -> own<Trap>;
640   using callback_with_env = auto (*)(void*, const Val[], Val[]) -> own<Trap>;
641 
642   static auto make(Store*, const FuncType*, callback) -> own<Func>;
643   static auto make(Store*, const FuncType*, callback_with_env,
644     void*, void (*finalizer)(void*) = nullptr) -> own<Func>;
645   auto copy() const -> own<Func>;
646 
647   auto type() const -> own<FuncType>;
648   auto param_arity() const -> size_t;
649   auto result_arity() const -> size_t;
650 
651   auto call(const Val[] = nullptr, Val[] = nullptr) const -> own<Trap>;
652 };
653 
654 
655 // Global Instances
656 
657 class Global : public Extern {
658 public:
659   Global() = delete;
660   ~Global();
661 
662   static auto make(Store*, const GlobalType*, const Val&) -> own<Global>;
663   auto copy() const -> own<Global>;
664 
665   auto type() const -> own<GlobalType>;
666   auto get() const -> Val;
667   void set(const Val&);
668 };
669 
670 
671 // Table Instances
672 
673 class Table : public Extern {
674 public:
675   Table() = delete;
676   ~Table();
677 
678   using size_t = uint32_t;
679 
680   static auto make(
681     Store*, const TableType*, const Ref* init = nullptr) -> own<Table>;
682   auto copy() const -> own<Table>;
683 
684   auto type() const -> own<TableType>;
685   auto get(size_t index) const -> own<Ref>;
686   auto set(size_t index, const Ref*) -> bool;
687   auto size() const -> size_t;
688   auto grow(size_t delta, const Ref* init = nullptr) -> bool;
689 };
690 
691 
692 // Memory Instances
693 
694 class Memory : public Extern {
695 public:
696   Memory() = delete;
697   ~Memory();
698 
699   static auto make(Store*, const MemoryType*) -> own<Memory>;
700   auto copy() const -> own<Memory>;
701 
702   using pages_t = uint32_t;
703 
704   static const size_t page_size = 0x10000;
705 
706   auto type() const -> own<MemoryType>;
707   auto data() const -> byte_t*;
708   auto data_size() const -> size_t;
709   auto size() const -> pages_t;
710   auto grow(pages_t delta) -> bool;
711 };
712 
713 
714 // Module Instances
715 
716 class Instance : public Ref {
717 public:
718   Instance() = delete;
719   ~Instance();
720 
721   static auto make(
722     Store*, const Module*, const Extern* const[], own<Trap>* = nullptr
723   ) -> own<Instance>;
724   auto copy() const -> own<Instance>;
725 
726   auto exports() const -> ownvec<Extern>;
727 };
728 
729 
730 ///////////////////////////////////////////////////////////////////////////////
731 
732 }  // namespace wasm
733 
734 #endif  // #ifdef __WASM_HH
735