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