@@ -85,6 +85,54 @@ static bool ToWasmValue(const Number& value,
85
85
}
86
86
}
87
87
88
+ static Dart_Handle ToWasmValue (Dart_Handle value,
89
+ wasmer_value_tag type,
90
+ wasmer_value* out) {
91
+ switch (type) {
92
+ case wasmer_value_tag::WASM_I32: {
93
+ int64_t i64;
94
+ Dart_Handle result = Dart_IntegerToInt64 (value, &i64);
95
+ out->I32 = i64;
96
+ if (out->I32 != i64) {
97
+ return Dart_NewApiError (" Int doesn't fit into 32-bits" );
98
+ }
99
+ return result;
100
+ }
101
+ case wasmer_value_tag::WASM_I64:
102
+ return Dart_IntegerToInt64 (value, &out->I64 );
103
+ case wasmer_value_tag::WASM_F32: {
104
+ double f64;
105
+ Dart_Handle result = Dart_DoubleValue (value, &f64);
106
+ out->F32 = f64;
107
+ return result;
108
+ }
109
+ case wasmer_value_tag::WASM_F64:
110
+ return Dart_DoubleValue (value, &out->F64 );
111
+ default :
112
+ FATAL (" Unknown WASM type" );
113
+ return nullptr ;
114
+ }
115
+ }
116
+
117
+ static bool ToWasmValueTag (classid_t type, wasmer_value_tag* out) {
118
+ switch (type) {
119
+ case kWasmInt32Cid :
120
+ *out = wasmer_value_tag::WASM_I32;
121
+ return true ;
122
+ case kWasmInt64Cid :
123
+ *out = wasmer_value_tag::WASM_I64;
124
+ return true ;
125
+ case kWasmFloatCid :
126
+ *out = wasmer_value_tag::WASM_F32;
127
+ return true ;
128
+ case kWasmDoubleCid :
129
+ *out = wasmer_value_tag::WASM_F64;
130
+ return true ;
131
+ default :
132
+ return false ;
133
+ }
134
+ }
135
+
88
136
static RawObject* ToDartObject (wasmer_value_t ret) {
89
137
switch (ret.tag ) {
90
138
case wasmer_value_tag::WASM_I32:
@@ -101,6 +149,22 @@ static RawObject* ToDartObject(wasmer_value_t ret) {
101
149
}
102
150
}
103
151
152
+ static Dart_Handle ToDartApiObject (wasmer_value value, wasmer_value_tag type) {
153
+ switch (type) {
154
+ case wasmer_value_tag::WASM_I32:
155
+ return Dart_NewInteger (value.I32 );
156
+ case wasmer_value_tag::WASM_I64:
157
+ return Dart_NewInteger (value.I64 );
158
+ case wasmer_value_tag::WASM_F32:
159
+ return Dart_NewDouble (value.F32 );
160
+ case wasmer_value_tag::WASM_F64:
161
+ return Dart_NewDouble (value.F64 );
162
+ default :
163
+ FATAL (" Unknown WASM type" );
164
+ return nullptr ;
165
+ }
166
+ }
167
+
104
168
RawExternalTypedData* WasmMemoryToExternalTypedData (wasmer_memory_t * memory) {
105
169
uint8_t * data = wasmer_memory_data (memory);
106
170
uint32_t size = wasmer_memory_data_length (memory);
@@ -158,6 +222,41 @@ RawString* DescribeModule(const wasmer_module_t* module) {
158
222
return String::New (desc.str ().c_str ());
159
223
}
160
224
225
+ class WasmImports ;
226
+
227
+ struct WasmFunctionImport {
228
+ WasmImports* imports;
229
+ std::unique_ptr<wasmer_value_tag[]> args;
230
+ intptr_t num_args;
231
+ wasmer_value_tag ret;
232
+ intptr_t num_rets;
233
+ int64_t fn_id;
234
+ wasmer_import_func_t * wasm_fn;
235
+ wasmer_trampoline_buffer_t * buffer;
236
+ WasmFunctionImport (WasmImports* imports_,
237
+ std::unique_ptr<wasmer_value_tag[]> args_,
238
+ intptr_t num_args_,
239
+ wasmer_value_tag ret_,
240
+ intptr_t num_rets_,
241
+ int64_t fn_id_)
242
+ : imports(imports_),
243
+ args (std::move(args_)),
244
+ num_args(num_args_),
245
+ ret(ret_),
246
+ num_rets(num_rets_),
247
+ fn_id(fn_id),
248
+ wasm_fn(nullptr ),
249
+ buffer(nullptr ) {}
250
+ ~WasmFunctionImport () {
251
+ wasmer_trampoline_buffer_destroy (buffer);
252
+ wasmer_import_func_destroy (wasm_fn);
253
+ }
254
+ };
255
+
256
+ extern " C" {
257
+ int64_t Trampoline (void * context, int64_t * args);
258
+ }
259
+
161
260
class WasmImports {
162
261
public:
163
262
explicit WasmImports (std::unique_ptr<char []> module_name)
@@ -167,11 +266,15 @@ class WasmImports {
167
266
for (wasmer_global_t * global : _globals) {
168
267
wasmer_global_destroy (global);
169
268
}
269
+ for (WasmFunctionImport* fn_imp : _functions) {
270
+ delete fn_imp;
271
+ }
170
272
for (const char * name : _import_names) {
171
273
delete[] name;
172
274
}
173
275
}
174
276
277
+ void SetHandle (FinalizablePersistentHandle* handle) { _handle = handle; }
175
278
size_t NumImports () const { return _imports.length (); }
176
279
wasmer_import_t * RawImports () { return _imports.data (); }
177
280
@@ -189,10 +292,82 @@ class WasmImports {
189
292
global;
190
293
}
191
294
295
+ void AddFunction (std::unique_ptr<char []> name,
296
+ int64_t fn_id,
297
+ std::unique_ptr<wasmer_value_tag[]> args,
298
+ intptr_t num_args,
299
+ wasmer_value_tag ret,
300
+ intptr_t num_rets) {
301
+ // Trampoline args include the context pointer.
302
+ const intptr_t num_trampoline_args = num_args + 1 ;
303
+
304
+ WasmFunctionImport* fn_imp = new WasmFunctionImport (
305
+ this , std::move (args), num_args, ret, num_rets, fn_id);
306
+ _functions.Add (fn_imp);
307
+
308
+ wasmer_trampoline_buffer_builder_t * builder =
309
+ wasmer_trampoline_buffer_builder_new ();
310
+ uintptr_t trampoline_id =
311
+ wasmer_trampoline_buffer_builder_add_callinfo_trampoline (
312
+ builder,
313
+ reinterpret_cast <wasmer_trampoline_callable_t *>(Trampoline),
314
+ reinterpret_cast <void *>(fn_imp), num_trampoline_args);
315
+ fn_imp->buffer = wasmer_trampoline_buffer_builder_build (builder);
316
+
317
+ const wasmer_trampoline_callable_t * trampoline =
318
+ wasmer_trampoline_buffer_get_trampoline (fn_imp->buffer , trampoline_id);
319
+ fn_imp->wasm_fn = wasmer_import_func_new (
320
+ reinterpret_cast <void (*)(void *)>(
321
+ const_cast <wasmer_trampoline_callable_t *>(trampoline)),
322
+ fn_imp->args .get (), num_args, &ret, num_rets);
323
+
324
+ AddImport (std::move (name), wasmer_import_export_kind::WASM_FUNCTION)->func =
325
+ fn_imp->wasm_fn ;
326
+ }
327
+
328
+ int64_t CallImportedFunction (WasmFunctionImport* fn_imp, int64_t * raw_args) {
329
+ wasmer_value* wasm_args = reinterpret_cast <wasmer_value*>(raw_args);
330
+ Dart_Handle fn_id = Dart_NewInteger (fn_imp->fn_id );
331
+ Dart_Handle closure =
332
+ Dart_Invoke (Dart_HandleFromWeakPersistent (_handle->apiHandle ()),
333
+ Dart_NewStringFromCString (" getFunction" ), 1 , &fn_id);
334
+ if (Dart_IsError (closure)) {
335
+ Dart_ThrowException (closure);
336
+ UNREACHABLE ();
337
+ }
338
+ Dart_Handle result;
339
+ {
340
+ auto args =
341
+ std::unique_ptr<Dart_Handle[]>(new Dart_Handle[fn_imp->num_args ]);
342
+ for (intptr_t i = 0 ; i < fn_imp->num_args ; ++i) {
343
+ args[i] = ToDartApiObject (wasm_args[i], fn_imp->args [i]);
344
+ }
345
+ result = Dart_InvokeClosure (closure, fn_imp->num_args , args.get ());
346
+ }
347
+ if (Dart_IsError (result)) {
348
+ Dart_ThrowException (result);
349
+ UNREACHABLE ();
350
+ }
351
+ if (fn_imp->num_rets == 0 ) {
352
+ // Wasmer ignores the result of this function if it expects no results,
353
+ // so skip the converters below (we get errors if we run them).
354
+ return 0 ;
355
+ }
356
+ wasmer_value wasm_result;
357
+ result = ToWasmValue (result, fn_imp->ret , &wasm_result);
358
+ if (Dart_IsError (result)) {
359
+ Dart_ThrowException (result);
360
+ UNREACHABLE ();
361
+ }
362
+ return wasm_result.I64 ;
363
+ }
364
+
192
365
private:
366
+ FinalizablePersistentHandle* _handle;
193
367
std::unique_ptr<char []> _module_name;
194
368
MallocGrowableArray<const char *> _import_names;
195
369
MallocGrowableArray<wasmer_global_t *> _globals;
370
+ MallocGrowableArray<WasmFunctionImport*> _functions;
196
371
MallocGrowableArray<wasmer_import_t > _imports;
197
372
198
373
wasmer_import_export_value* AddImport (std::unique_ptr<char []> name,
@@ -212,6 +387,14 @@ class WasmImports {
212
387
DISALLOW_COPY_AND_ASSIGN (WasmImports);
213
388
};
214
389
390
+ extern " C" {
391
+ int64_t Trampoline (void * context, int64_t * args) {
392
+ WasmFunctionImport* fn_imp = reinterpret_cast <WasmFunctionImport*>(context);
393
+ // Skip the first arg (it's another context pointer).
394
+ return fn_imp->imports ->CallImportedFunction (fn_imp, args + 1 );
395
+ }
396
+ }
397
+
215
398
class WasmFunction {
216
399
public:
217
400
WasmFunction (MallocGrowableArray<classid_t > args,
@@ -468,8 +651,9 @@ DEFINE_NATIVE_ENTRY(Wasm_initImports, 0, 2) {
468
651
WasmImports* imports = new WasmImports (ToUTF8 (module_name));
469
652
470
653
imp_wrap.SetNativeField (0 , reinterpret_cast <intptr_t >(imports));
471
- FinalizablePersistentHandle::New (thread->isolate (), imp_wrap, imports,
472
- Finalize<WasmImports>, sizeof (WasmImports));
654
+ imports->SetHandle (FinalizablePersistentHandle::New (
655
+ thread->isolate (), imp_wrap, imports, Finalize<WasmImports>,
656
+ sizeof (WasmImports)));
473
657
474
658
return Object::null ();
475
659
}
@@ -505,8 +689,9 @@ DEFINE_NATIVE_ENTRY(Wasm_addGlobalImport, 0, 5) {
505
689
reinterpret_cast <WasmImports*>(imp_wrap.GetNativeField (0 ));
506
690
wasmer_value_t wasm_value;
507
691
if (!ToWasmValue (value, type.type_class_id (), &wasm_value)) {
508
- Exceptions::ThrowArgumentError (String::Handle (String::NewFormatted (
509
- " Can't convert dart value to WASM global variable" )));
692
+ Exceptions::ThrowArgumentError (String::Handle (
693
+ zone, String::NewFormatted (
694
+ " Can't convert dart value to WASM global variable" )));
510
695
UNREACHABLE ();
511
696
}
512
697
@@ -515,6 +700,53 @@ DEFINE_NATIVE_ENTRY(Wasm_addGlobalImport, 0, 5) {
515
700
return Object::null ();
516
701
}
517
702
703
+ DEFINE_NATIVE_ENTRY (Wasm_addFunctionImport, 0 , 4 ) {
704
+ GET_NON_NULL_NATIVE_ARGUMENT (Instance, imp_wrap, arguments->NativeArgAt (0 ));
705
+ GET_NON_NULL_NATIVE_ARGUMENT (String, name, arguments->NativeArgAt (1 ));
706
+ GET_NON_NULL_NATIVE_ARGUMENT (Integer, fn_id, arguments->NativeArgAt (2 ));
707
+ GET_NON_NULL_NATIVE_ARGUMENT (Type, fn_type, arguments->NativeArgAt (3 ));
708
+
709
+ ASSERT (imp_wrap.NumNativeFields () == 1 );
710
+
711
+ Function& sig = Function::Handle (zone, fn_type.signature ());
712
+
713
+ classid_t ret = AbstractType::Handle (zone, sig.result_type ()).type_class_id ();
714
+ intptr_t num_rets = ret == kWasmVoidCid ? 0 : 1 ;
715
+ wasmer_value_tag wasm_ret = wasmer_value_tag::WASM_I64;
716
+ if (num_rets != 0 ) {
717
+ if (!ToWasmValueTag (ret, &wasm_ret)) {
718
+ Exceptions::ThrowArgumentError (String::Handle (
719
+ zone, String::NewFormatted (" Return type is not a valid WASM type" )));
720
+ UNREACHABLE ();
721
+ }
722
+ }
723
+
724
+ Array& args = Array::Handle (zone, sig.parameter_types ());
725
+ AbstractType& arg_type = AbstractType::Handle (zone);
726
+ intptr_t first_arg_index = sig.NumImplicitParameters ();
727
+ intptr_t num_args = args.Length () - first_arg_index;
728
+ auto wasm_args =
729
+ std::unique_ptr<wasmer_value_tag[]>(new wasmer_value_tag[num_args]);
730
+ for (intptr_t i = 0 ; i < num_args; ++i) {
731
+ arg_type ^= args.At (i + first_arg_index);
732
+ classid_t dart_arg = arg_type.type_class_id ();
733
+ if (!ToWasmValueTag (dart_arg, &wasm_args[i])) {
734
+ wasm_args.reset ();
735
+ Exceptions::ThrowArgumentError (String::Handle (
736
+ zone, String::NewFormatted (
737
+ " Type of arg %" Pd " is not a valid WASM type" , i)));
738
+ UNREACHABLE ();
739
+ }
740
+ }
741
+
742
+ WasmImports* imports =
743
+ reinterpret_cast <WasmImports*>(imp_wrap.GetNativeField (0 ));
744
+ imports->AddFunction (ToUTF8 (name), fn_id.AsInt64Value (), std::move (wasm_args),
745
+ num_args, wasm_ret, num_rets);
746
+
747
+ return Object::null ();
748
+ }
749
+
518
750
DEFINE_NATIVE_ENTRY (Wasm_initMemory, 0 , 3 ) {
519
751
GET_NON_NULL_NATIVE_ARGUMENT (Instance, mem_wrap, arguments->NativeArgAt (0 ));
520
752
GET_NON_NULL_NATIVE_ARGUMENT (Integer, init, arguments->NativeArgAt (1 ));
@@ -610,15 +842,16 @@ DEFINE_NATIVE_ENTRY(Wasm_initFunction, 0, 4) {
610
842
String& error = String::Handle (zone);
611
843
612
844
{
613
- Function& sig = Function::Handle (fn_type.signature ());
614
- Array& args = Array::Handle (sig.parameter_types ());
845
+ Function& sig = Function::Handle (zone, fn_type.signature ());
846
+ Array& args = Array::Handle (zone, sig.parameter_types ());
847
+ AbstractType& arg_type = AbstractType::Handle (zone);
615
848
MallocGrowableArray<classid_t > dart_args;
616
849
for (intptr_t i = sig.NumImplicitParameters (); i < args.Length (); ++i) {
617
- dart_args. Add (
618
- AbstractType::Cast ( Object::Handle (args. At (i))) .type_class_id ());
850
+ arg_type ^= args. At (i);
851
+ dart_args. Add (arg_type .type_class_id ());
619
852
}
620
853
classid_t dart_ret =
621
- AbstractType::Handle (sig.result_type ()).type_class_id ();
854
+ AbstractType::Handle (zone, sig.result_type ()).type_class_id ();
622
855
623
856
std::unique_ptr<char []> name_raw = ToUTF8 (name);
624
857
fn = inst->GetFunction (name_raw.get (), dart_args, dart_ret, &error);
@@ -643,19 +876,21 @@ DEFINE_NATIVE_ENTRY(Wasm_callFunction, 0, 2) {
643
876
WasmFunction* fn = reinterpret_cast <WasmFunction*>(fn_wrap.GetNativeField (0 ));
644
877
645
878
if (args.Length () != fn->args ().length ()) {
646
- Exceptions::ThrowArgumentError (String::Handle (String::NewFormatted (
647
- " Wrong number of args. Expected %" Pu " but found %" Pd " ." ,
648
- fn->args ().length (), args.Length ())));
879
+ Exceptions::ThrowArgumentError (String::Handle (
880
+ zone, String::NewFormatted (" Wrong number of args. Expected %" Pu
881
+ " but found %" Pd " ." ,
882
+ fn->args ().length (), args.Length ())));
649
883
UNREACHABLE ();
650
884
}
651
885
auto params = std::unique_ptr<wasmer_value_t []>(
652
886
new wasmer_value_t [fn->args ().length ()]);
887
+ Number& arg_num = Number::Handle (zone);
653
888
for (intptr_t i = 0 ; i < args.Length (); ++i) {
654
- if (! ToWasmValue ( Number::Cast ( Object::Handle ( args.At (i))), fn-> args ()[i],
655
- ¶ms[i])) {
889
+ arg_num ^= args.At (i);
890
+ if (! ToWasmValue (arg_num, fn-> args ()[i], ¶ms[i])) {
656
891
params.reset ();
657
892
Exceptions::ThrowArgumentError (String::Handle (
658
- String::NewFormatted (" Arg %" Pd " is the wrong type." , i)));
893
+ zone, String::NewFormatted (" Arg %" Pd " is the wrong type." , i)));
659
894
UNREACHABLE ();
660
895
}
661
896
}
@@ -709,6 +944,11 @@ DEFINE_NATIVE_ENTRY(Wasm_addGlobalImport, 0, 5) {
709
944
return nullptr ;
710
945
}
711
946
947
+ DEFINE_NATIVE_ENTRY (Wasm_addFunctionImport, 0 , 4 ) {
948
+ Exceptions::ThrowUnsupportedError (" WASM is disabled" );
949
+ return nullptr ;
950
+ }
951
+
712
952
DEFINE_NATIVE_ENTRY (Wasm_initMemory, 0 , 3 ) {
713
953
Exceptions::ThrowUnsupportedError (" WASM is disabled" );
714
954
return nullptr ;
0 commit comments