1 /**
2  * \file wasmtime/module.hh
3  */
4 
5 #ifndef WASMTIME_MODULE_HH
6 #define WASMTIME_MODULE_HH
7 
8 #include <memory>
9 #include <string_view>
10 #include <wasmtime/engine.hh>
11 #include <wasmtime/module.h>
12 #include <wasmtime/span.hh>
13 #include <wasmtime/types/export.hh>
14 #include <wasmtime/types/import.hh>
15 #include <wasmtime/wat.hh>
16 
17 namespace wasmtime {
18 
19 /**
20  * \brief Representation of a compiled WebAssembly module.
21  *
22  * This type contains JIT code of a compiled WebAssembly module. A `Module` is
23  * connected to an `Engine` and can only be instantiated within that `Engine`.
24  * You can inspect a `Module` for its type information. This is passed as an
25  * argument to other APIs to instantiate it.
26  */
27 class Module {
28   friend class Store;
29   friend class Instance;
30   friend class Linker;
31 
32   struct deleter {
33     void operator()(wasmtime_module_t *p) const { wasmtime_module_delete(p); }
34   };
35 
36   std::unique_ptr<wasmtime_module_t, deleter> ptr;
37 
38   Module(wasmtime_module_t *raw) : ptr(raw) {}
39 
40 public:
41   /// Copies another module into this one.
42   Module(const Module &other) : ptr(wasmtime_module_clone(other.ptr.get())) {}
43   /// Copies another module into this one.
44   Module &operator=(const Module &other) {
45     ptr.reset(wasmtime_module_clone(other.ptr.get()));
46     return *this;
47   }
48   ~Module() = default;
49   /// Moves resources from another module into this one.
50   Module(Module &&other) = default;
51   /// Moves resources from another module into this one.
52   Module &operator=(Module &&other) = default;
53 
54 #ifdef WASMTIME_FEATURE_COMPILER
55   /**
56    * \brief Compiles a module from the WebAssembly text format.
57    *
58    * This function will automatically use `wat2wasm` on the input and then
59    * delegate to the #compile function.
60    */
61   static Result<Module> compile(Engine &engine, std::string_view wat) {
62     auto wasm = wat2wasm(wat);
63     if (!wasm) {
64       return wasm.err();
65     }
66     auto bytes = wasm.ok();
67     return compile(engine, bytes);
68   }
69 
70   /**
71    * \brief Compiles a module from the WebAssembly binary format.
72    *
73    * This function compiles the provided WebAssembly binary specified by `wasm`
74    * within the compilation settings configured by `engine`. This method is
75    * synchronous and will not return until the module has finished compiling.
76    *
77    * This function can fail if the WebAssembly binary is invalid or doesn't
78    * validate (or similar).
79    */
80   static Result<Module> compile(Engine &engine, Span<uint8_t> wasm) {
81     wasmtime_module_t *ret = nullptr;
82     auto *error =
83         wasmtime_module_new(engine.ptr.get(), wasm.data(), wasm.size(), &ret);
84     if (error != nullptr) {
85       return Error(error);
86     }
87     return Module(ret);
88   }
89 
90   /**
91    * \brief Validates the provided WebAssembly binary without compiling it.
92    *
93    * This function will validate whether the provided binary is indeed valid
94    * within the compilation settings of the `engine` provided.
95    */
96   static Result<std::monostate> validate(Engine &engine, Span<uint8_t> wasm) {
97     auto *error =
98         wasmtime_module_validate(engine.ptr.get(), wasm.data(), wasm.size());
99     if (error != nullptr) {
100       return Error(error);
101     }
102     return std::monostate();
103   }
104 #endif // WASMTIME_FEATURE_COMPILER
105 
106   /**
107    * \brief Deserializes a previous list of bytes created with `serialize`.
108    *
109    * This function is intended to be much faster than `compile` where it uses
110    * the artifacts of a previous compilation to quickly create an in-memory
111    * module ready for instantiation.
112    *
113    * It is not safe to pass arbitrary input to this function, it is only safe to
114    * pass in output from previous calls to `serialize`. For more information see
115    * the Rust documentation -
116    * https://docs.wasmtime.dev/api/wasmtime/struct.Module.html#method.deserialize
117    */
118   static Result<Module> deserialize(Engine &engine, Span<uint8_t> wasm) {
119     wasmtime_module_t *ret = nullptr;
120     auto *error = wasmtime_module_deserialize(engine.ptr.get(), wasm.data(),
121                                               wasm.size(), &ret);
122     if (error != nullptr) {
123       return Error(error);
124     }
125     return Module(ret);
126   }
127 
128   /**
129    * \brief Deserializes a module from an on-disk file.
130    *
131    * This function is the same as `deserialize` except that it reads the data
132    * for the serialized module from the path on disk. This can be faster than
133    * the alternative which may require copying the data around.
134    *
135    * It is not safe to pass arbitrary input to this function, it is only safe to
136    * pass in output from previous calls to `serialize`. For more information see
137    * the Rust documentation -
138    * https://docs.wasmtime.dev/api/wasmtime/struct.Module.html#method.deserialize
139    */
140   static Result<Module> deserialize_file(Engine &engine,
141                                          const std::string &path) {
142     wasmtime_module_t *ret = nullptr;
143     auto *error =
144         wasmtime_module_deserialize_file(engine.ptr.get(), path.c_str(), &ret);
145     if (error != nullptr) {
146       return Error(error);
147     }
148     return Module(ret);
149   }
150 
151   /// Returns the list of types imported by this module.
152   ImportType::List imports() const {
153     ImportType::List list;
154     wasmtime_module_imports(ptr.get(), &list.list);
155     return list;
156   }
157 
158   /// Returns the list of types exported by this module.
159   ExportType::List exports() const {
160     ExportType::List list;
161     wasmtime_module_exports(ptr.get(), &list.list);
162     return list;
163   }
164 
165 #ifdef WASMTIME_FEATURE_COMPILER
166   /**
167    * \brief Serializes this module to a list of bytes.
168    *
169    * The returned bytes can then be used to later pass to `deserialize` to
170    * quickly recreate this module in a different process perhaps.
171    */
172   Result<std::vector<uint8_t>> serialize() const {
173     wasm_byte_vec_t bytes;
174     auto *error = wasmtime_module_serialize(ptr.get(), &bytes);
175     if (error != nullptr) {
176       return Error(error);
177     }
178     std::vector<uint8_t> ret;
179     // NOLINTNEXTLINE TODO can this be done without triggering lints?
180     Span<uint8_t> raw(reinterpret_cast<uint8_t *>(bytes.data), bytes.size);
181     ret.assign(raw.begin(), raw.end());
182     wasm_byte_vec_delete(&bytes);
183     return ret;
184   }
185 #endif // WASMTIME_FEATURE_COMPILER
186 };
187 
188 } // namespace wasmtime
189 
190 #endif // WASMTIME_MODULE_HH
191