@@ -19,9 +19,10 @@ class WasmModule {
1919 _module = WasmRuntime ().compile (_store, data);
2020 }
2121
22- /// Instantiate the module with the given imports.
23- WasmInstance instantiate (WasmImports imports) {
24- return WasmInstance (_store, _module, imports);
22+ /// Returns a WasmInstanceBuilder that is used to add all the imports that the
23+ /// module needs, and then instantiate it.
24+ WasmInstanceBuilder instantiate () {
25+ return WasmInstanceBuilder (this );
2526 }
2627
2728 /// Create a new memory with the given number of initial pages, and optional
@@ -37,47 +38,166 @@ class WasmModule {
3738 var runtime = WasmRuntime ();
3839 var imports = runtime.importDescriptors (_module);
3940 for (var imp in imports) {
40- var kind = wasmerExternKindName (imp.kind);
41- description.write ('import $kind : ${imp .moduleName }::${imp .name }\n ' );
41+ description.write ("import $imp \n " );
4242 }
4343 var exports = runtime.exportDescriptors (_module);
4444 for (var exp in exports) {
45- var kind = wasmerExternKindName (exp.kind);
46- description.write ('export $kind : ${exp .name }\n ' );
45+ description.write ("export $exp \n " );
4746 }
4847 return description.toString ();
4948 }
5049}
5150
52- /// WasmImports holds all the imports for a WasmInstance.
53- class WasmImports {
54- Pointer <Pointer <WasmerExtern >> _imports;
55- int _capacity;
56- int _length;
51+ Pointer <WasmerTrap > _wasmFnImportTrampoline (Pointer <_WasmFnImport > imp,
52+ Pointer <WasmerVal > args, Pointer <WasmerVal > results) {
53+ try {
54+ _WasmFnImport ._call (imp, args, results);
55+ } catch (e) {
56+ // TODO: Use WasmerTrap to handle this case. For now just print the
57+ // exception (if we ignore it, FFI will silently return a default result).
58+ print (e);
59+ }
60+ return nullptr;
61+ }
62+
63+ void _wasmFnImportFinalizer (Pointer <_WasmFnImport > imp) {
64+ _wasmFnImportToFn.remove (imp.address);
65+ free (imp);
66+ }
5767
58- /// Create an imports object.
59- WasmImports ([this ._capacity = 4 ])
60- : _imports = allocate <Pointer <WasmerExtern >>(count: _capacity),
61- _length = 0 {}
68+ final _wasmFnImportTrampolineNative = Pointer .fromFunction<
69+ Pointer <WasmerTrap > Function (Pointer <_WasmFnImport >, Pointer <WasmerVal >,
70+ Pointer <WasmerVal >)> (_wasmFnImportTrampoline);
71+ final _wasmFnImportToFn = < int , Function > {};
72+ final _wasmFnImportFinalizerNative =
73+ Pointer .fromFunction< Void Function (Pointer <_WasmFnImport >)> (
74+ _wasmFnImportFinalizer);
6275
63- /// Returns the number of imports.
64- int get length => _length;
76+ class _WasmFnImport extends Struct {
77+ @Int 32()
78+ external int numArgs;
79+
80+ @Int 32()
81+ external int returnType;
82+
83+ static void _call (Pointer <_WasmFnImport > imp, Pointer <WasmerVal > rawArgs,
84+ Pointer <WasmerVal > rawResult) {
85+ Function fn = _wasmFnImportToFn[imp.address] as Function ;
86+ var args = [];
87+ for (var i = 0 ; i < imp.ref.numArgs; ++ i) {
88+ args.add (rawArgs[i].toDynamic);
89+ }
90+ var result = Function .apply (fn, args);
91+ switch (imp.ref.returnType) {
92+ case WasmerValKindI32 :
93+ rawResult.ref.i32 = result;
94+ break ;
95+ case WasmerValKindI64 :
96+ rawResult.ref.i64 = result;
97+ break ;
98+ case WasmerValKindF32 :
99+ rawResult.ref.f32 = result;
100+ break ;
101+ case WasmerValKindF64 :
102+ rawResult.ref.f64 = result;
103+ break ;
104+ case WasmerValKindVoid :
105+ // Do nothing.
106+ }
107+ }
108+ }
109+
110+ /// WasmInstanceBuilder is used collect all the imports that a WasmModule
111+ /// requires before it is instantiated.
112+ class WasmInstanceBuilder {
113+ WasmModule _module;
114+ late List <WasmImportDescriptor > _importDescs;
115+ Map <String , int > _importIndex;
116+ late Pointer <Pointer <WasmerExtern >> _imports;
117+
118+ WasmInstanceBuilder (this ._module) : _importIndex = {} {
119+ _importDescs = WasmRuntime ().importDescriptors (_module._module);
120+ _imports = allocate <Pointer <WasmerExtern >>(count: _importDescs.length);
121+ for (var i = 0 ; i < _importDescs.length; ++ i) {
122+ var imp = _importDescs[i];
123+ _importIndex["${imp .moduleName }::${imp .name }" ] = i;
124+ _imports[i] = nullptr;
125+ }
126+ }
127+
128+ int _getIndex (String moduleName, String name) {
129+ var index = _importIndex["${moduleName }::${name }" ];
130+ if (index == null ) {
131+ throw Exception ("Import not found: ${moduleName }::${name }" );
132+ } else if (_imports[index] != nullptr) {
133+ throw Exception ("Import already filled: ${moduleName }::${name }" );
134+ } else {
135+ return index;
136+ }
137+ }
138+
139+ /// Add a WasmMemory to the imports.
140+ WasmInstanceBuilder addMemory (
141+ String moduleName, String name, WasmMemory memory) {
142+ var index = _getIndex (moduleName, name);
143+ var imp = _importDescs[index];
144+ if (imp.kind != WasmerExternKindMemory ) {
145+ throw Exception ("Import is not a memory: $imp " );
146+ }
147+ _imports[index] = WasmRuntime ().memoryToExtern (memory._mem);
148+ return this ;
149+ }
150+
151+ /// Add a function to the imports.
152+ WasmInstanceBuilder addFunction (String moduleName, String name, Function fn) {
153+ var index = _getIndex (moduleName, name);
154+ var imp = _importDescs[index];
155+ var runtime = WasmRuntime ();
156+
157+ if (imp.kind != WasmerExternKindFunction ) {
158+ throw Exception ("Import is not a function: $imp " );
159+ }
160+
161+ var argTypes = runtime.getArgTypes (imp.funcType);
162+ var returnType = runtime.getReturnType (imp.funcType);
163+ var wasmFnImport = allocate <_WasmFnImport >();
164+ wasmFnImport.ref.numArgs = argTypes.length;
165+ wasmFnImport.ref.returnType = returnType;
166+ _wasmFnImportToFn[wasmFnImport.address] = fn;
167+ var fnImp = runtime.newFunc (
168+ _module._store,
169+ imp.funcType,
170+ _wasmFnImportTrampolineNative,
171+ wasmFnImport,
172+ _wasmFnImportFinalizerNative);
173+ _imports[index] = runtime.functionToExtern (fnImp);
174+ return this ;
175+ }
176+
177+ /// Build the module instance.
178+ WasmInstance build () {
179+ for (var i = 0 ; i < _importDescs.length; ++ i) {
180+ if (_imports[i] == nullptr) {
181+ throw Exception ("Missing import: ${_importDescs [i ]}" );
182+ }
183+ }
184+ return WasmInstance (_module, _imports);
185+ }
65186}
66187
67188/// WasmInstance is an instantiated WasmModule.
68189class WasmInstance {
69- Pointer <WasmerStore > _store;
70- Pointer <WasmerModule > _module;
190+ WasmModule _module;
71191 Pointer <WasmerInstance > _instance;
72192 Pointer <WasmerMemory >? _exportedMemory;
73193 Map <String , WasmFunction > _functions = {};
74194
75- WasmInstance (this ._store, this . _module, WasmImports imports)
195+ WasmInstance (this ._module, Pointer < Pointer < WasmerExtern >> imports)
76196 : _instance = WasmRuntime ()
77- .instantiate (_store, _module, imports._imports , imports.length ) {
197+ .instantiate (_module. _store, _module._module , imports) {
78198 var runtime = WasmRuntime ();
79199 var exports = runtime.exports (_instance);
80- var exportDescs = runtime.exportDescriptors (_module);
200+ var exportDescs = runtime.exportDescriptors (_module._module );
81201 assert (exports.ref.length == exportDescs.length);
82202 for (var i = 0 ; i < exports.ref.length; ++ i) {
83203 var e = exports.ref.data[i];
0 commit comments