Skip to content

Commit d2a0900

Browse files
liamappelbecommit-bot@chromium.org
authored andcommitted
Reland "[vm] Wasm function imports"
This reverts commit a7cb8ee. Reason for revert: Fixed the crash Original change's description: > Revert "[vm] Wasm function imports" > > This reverts commit 7a24aec. > > Reason for revert: debug-mode gen_snapshot crashes on all programs > > Original change's description: > > [vm] Wasm function imports > > > > Bug: #37882 > > Change-Id: Ia8aa9a87803d5e8b899ddab5479b8cd93e03fd71 > > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/118204 > > Commit-Queue: Liam Appelbe <[email protected]> > > Reviewed-by: Ryan Macnak <[email protected]> > > Reviewed-by: Alexander Markov <[email protected]> > > [email protected],[email protected],[email protected] > > Change-Id: Ib5d348e25854af010b1d8a64a87406da443981df > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: #37882 > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119143 > Reviewed-by: Samir Jindel <[email protected]> > Commit-Queue: Samir Jindel <[email protected]> [email protected],[email protected],[email protected],[email protected] Change-Id: I4fd073a087eae7bb95c75079446d9111e7bc8c40 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: #37882 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119168 Reviewed-by: Liam Appelbe <[email protected]> Reviewed-by: Alexander Markov <[email protected]> Commit-Queue: Liam Appelbe <[email protected]>
1 parent 34087a6 commit d2a0900

File tree

11 files changed

+482
-17
lines changed

11 files changed

+482
-17
lines changed

runtime/lib/wasm.cc

+259-15
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,54 @@ static bool ToWasmValue(const Number& value,
8585
}
8686
}
8787

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+
88136
static RawObject* ToDartObject(wasmer_value_t ret) {
89137
switch (ret.tag) {
90138
case wasmer_value_tag::WASM_I32:
@@ -101,6 +149,22 @@ static RawObject* ToDartObject(wasmer_value_t ret) {
101149
}
102150
}
103151

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+
104168
RawExternalTypedData* WasmMemoryToExternalTypedData(wasmer_memory_t* memory) {
105169
uint8_t* data = wasmer_memory_data(memory);
106170
uint32_t size = wasmer_memory_data_length(memory);
@@ -158,6 +222,41 @@ RawString* DescribeModule(const wasmer_module_t* module) {
158222
return String::New(desc.str().c_str());
159223
}
160224

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+
161260
class WasmImports {
162261
public:
163262
explicit WasmImports(std::unique_ptr<char[]> module_name)
@@ -167,11 +266,15 @@ class WasmImports {
167266
for (wasmer_global_t* global : _globals) {
168267
wasmer_global_destroy(global);
169268
}
269+
for (WasmFunctionImport* fn_imp : _functions) {
270+
delete fn_imp;
271+
}
170272
for (const char* name : _import_names) {
171273
delete[] name;
172274
}
173275
}
174276

277+
void SetHandle(FinalizablePersistentHandle* handle) { _handle = handle; }
175278
size_t NumImports() const { return _imports.length(); }
176279
wasmer_import_t* RawImports() { return _imports.data(); }
177280

@@ -189,10 +292,86 @@ class WasmImports {
189292
global;
190293
}
191294

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 inst = Dart_HandleFromWeakPersistent(_handle->apiHandle());
331+
Dart_Handle dart_args[2] = {
332+
inst,
333+
Dart_NewInteger(fn_imp->fn_id),
334+
};
335+
Dart_Handle closure = Dart_Invoke(Dart_InstanceGetType(inst),
336+
Dart_NewStringFromCString("getFunction"),
337+
ARRAY_SIZE(dart_args), dart_args);
338+
if (Dart_IsError(closure)) {
339+
Dart_ThrowException(closure);
340+
UNREACHABLE();
341+
}
342+
Dart_Handle result;
343+
{
344+
auto args =
345+
std::unique_ptr<Dart_Handle[]>(new Dart_Handle[fn_imp->num_args]);
346+
for (intptr_t i = 0; i < fn_imp->num_args; ++i) {
347+
args[i] = ToDartApiObject(wasm_args[i], fn_imp->args[i]);
348+
}
349+
result = Dart_InvokeClosure(closure, fn_imp->num_args, args.get());
350+
}
351+
if (Dart_IsError(result)) {
352+
Dart_ThrowException(result);
353+
UNREACHABLE();
354+
}
355+
if (fn_imp->num_rets == 0) {
356+
// Wasmer ignores the result of this function if it expects no results,
357+
// so skip the converters below (we get errors if we run them).
358+
return 0;
359+
}
360+
wasmer_value wasm_result;
361+
result = ToWasmValue(result, fn_imp->ret, &wasm_result);
362+
if (Dart_IsError(result)) {
363+
Dart_ThrowException(result);
364+
UNREACHABLE();
365+
}
366+
return wasm_result.I64;
367+
}
368+
192369
private:
370+
FinalizablePersistentHandle* _handle;
193371
std::unique_ptr<char[]> _module_name;
194372
MallocGrowableArray<const char*> _import_names;
195373
MallocGrowableArray<wasmer_global_t*> _globals;
374+
MallocGrowableArray<WasmFunctionImport*> _functions;
196375
MallocGrowableArray<wasmer_import_t> _imports;
197376

198377
wasmer_import_export_value* AddImport(std::unique_ptr<char[]> name,
@@ -212,6 +391,14 @@ class WasmImports {
212391
DISALLOW_COPY_AND_ASSIGN(WasmImports);
213392
};
214393

394+
extern "C" {
395+
int64_t Trampoline(void* context, int64_t* args) {
396+
WasmFunctionImport* fn_imp = reinterpret_cast<WasmFunctionImport*>(context);
397+
// Skip the first arg (it's another context pointer).
398+
return fn_imp->imports->CallImportedFunction(fn_imp, args + 1);
399+
}
400+
}
401+
215402
class WasmFunction {
216403
public:
217404
WasmFunction(MallocGrowableArray<classid_t> args,
@@ -468,8 +655,9 @@ DEFINE_NATIVE_ENTRY(Wasm_initImports, 0, 2) {
468655
WasmImports* imports = new WasmImports(ToUTF8(module_name));
469656

470657
imp_wrap.SetNativeField(0, reinterpret_cast<intptr_t>(imports));
471-
FinalizablePersistentHandle::New(thread->isolate(), imp_wrap, imports,
472-
Finalize<WasmImports>, sizeof(WasmImports));
658+
imports->SetHandle(FinalizablePersistentHandle::New(
659+
thread->isolate(), imp_wrap, imports, Finalize<WasmImports>,
660+
sizeof(WasmImports)));
473661

474662
return Object::null();
475663
}
@@ -505,8 +693,9 @@ DEFINE_NATIVE_ENTRY(Wasm_addGlobalImport, 0, 5) {
505693
reinterpret_cast<WasmImports*>(imp_wrap.GetNativeField(0));
506694
wasmer_value_t wasm_value;
507695
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")));
696+
Exceptions::ThrowArgumentError(String::Handle(
697+
zone, String::NewFormatted(
698+
"Can't convert dart value to WASM global variable")));
510699
UNREACHABLE();
511700
}
512701

@@ -515,6 +704,53 @@ DEFINE_NATIVE_ENTRY(Wasm_addGlobalImport, 0, 5) {
515704
return Object::null();
516705
}
517706

707+
DEFINE_NATIVE_ENTRY(Wasm_addFunctionImport, 0, 4) {
708+
GET_NON_NULL_NATIVE_ARGUMENT(Instance, imp_wrap, arguments->NativeArgAt(0));
709+
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(1));
710+
GET_NON_NULL_NATIVE_ARGUMENT(Integer, fn_id, arguments->NativeArgAt(2));
711+
GET_NON_NULL_NATIVE_ARGUMENT(Type, fn_type, arguments->NativeArgAt(3));
712+
713+
ASSERT(imp_wrap.NumNativeFields() == 1);
714+
715+
Function& sig = Function::Handle(zone, fn_type.signature());
716+
717+
classid_t ret = AbstractType::Handle(zone, sig.result_type()).type_class_id();
718+
intptr_t num_rets = ret == kWasmVoidCid ? 0 : 1;
719+
wasmer_value_tag wasm_ret = wasmer_value_tag::WASM_I64;
720+
if (num_rets != 0) {
721+
if (!ToWasmValueTag(ret, &wasm_ret)) {
722+
Exceptions::ThrowArgumentError(String::Handle(
723+
zone, String::NewFormatted("Return type is not a valid WASM type")));
724+
UNREACHABLE();
725+
}
726+
}
727+
728+
Array& args = Array::Handle(zone, sig.parameter_types());
729+
AbstractType& arg_type = AbstractType::Handle(zone);
730+
intptr_t first_arg_index = sig.NumImplicitParameters();
731+
intptr_t num_args = args.Length() - first_arg_index;
732+
auto wasm_args =
733+
std::unique_ptr<wasmer_value_tag[]>(new wasmer_value_tag[num_args]);
734+
for (intptr_t i = 0; i < num_args; ++i) {
735+
arg_type ^= args.At(i + first_arg_index);
736+
classid_t dart_arg = arg_type.type_class_id();
737+
if (!ToWasmValueTag(dart_arg, &wasm_args[i])) {
738+
wasm_args.reset();
739+
Exceptions::ThrowArgumentError(String::Handle(
740+
zone, String::NewFormatted(
741+
"Type of arg %" Pd " is not a valid WASM type", i)));
742+
UNREACHABLE();
743+
}
744+
}
745+
746+
WasmImports* imports =
747+
reinterpret_cast<WasmImports*>(imp_wrap.GetNativeField(0));
748+
imports->AddFunction(ToUTF8(name), fn_id.AsInt64Value(), std::move(wasm_args),
749+
num_args, wasm_ret, num_rets);
750+
751+
return Object::null();
752+
}
753+
518754
DEFINE_NATIVE_ENTRY(Wasm_initMemory, 0, 3) {
519755
GET_NON_NULL_NATIVE_ARGUMENT(Instance, mem_wrap, arguments->NativeArgAt(0));
520756
GET_NON_NULL_NATIVE_ARGUMENT(Integer, init, arguments->NativeArgAt(1));
@@ -610,15 +846,16 @@ DEFINE_NATIVE_ENTRY(Wasm_initFunction, 0, 4) {
610846
String& error = String::Handle(zone);
611847

612848
{
613-
Function& sig = Function::Handle(fn_type.signature());
614-
Array& args = Array::Handle(sig.parameter_types());
849+
Function& sig = Function::Handle(zone, fn_type.signature());
850+
Array& args = Array::Handle(zone, sig.parameter_types());
851+
AbstractType& arg_type = AbstractType::Handle(zone);
615852
MallocGrowableArray<classid_t> dart_args;
616853
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());
854+
arg_type ^= args.At(i);
855+
dart_args.Add(arg_type.type_class_id());
619856
}
620857
classid_t dart_ret =
621-
AbstractType::Handle(sig.result_type()).type_class_id();
858+
AbstractType::Handle(zone, sig.result_type()).type_class_id();
622859

623860
std::unique_ptr<char[]> name_raw = ToUTF8(name);
624861
fn = inst->GetFunction(name_raw.get(), dart_args, dart_ret, &error);
@@ -643,19 +880,21 @@ DEFINE_NATIVE_ENTRY(Wasm_callFunction, 0, 2) {
643880
WasmFunction* fn = reinterpret_cast<WasmFunction*>(fn_wrap.GetNativeField(0));
644881

645882
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())));
883+
Exceptions::ThrowArgumentError(String::Handle(
884+
zone, String::NewFormatted("Wrong number of args. Expected %" Pu
885+
" but found %" Pd ".",
886+
fn->args().length(), args.Length())));
649887
UNREACHABLE();
650888
}
651889
auto params = std::unique_ptr<wasmer_value_t[]>(
652890
new wasmer_value_t[fn->args().length()]);
891+
Number& arg_num = Number::Handle(zone);
653892
for (intptr_t i = 0; i < args.Length(); ++i) {
654-
if (!ToWasmValue(Number::Cast(Object::Handle(args.At(i))), fn->args()[i],
655-
&params[i])) {
893+
arg_num ^= args.At(i);
894+
if (!ToWasmValue(arg_num, fn->args()[i], &params[i])) {
656895
params.reset();
657896
Exceptions::ThrowArgumentError(String::Handle(
658-
String::NewFormatted("Arg %" Pd " is the wrong type.", i)));
897+
zone, String::NewFormatted("Arg %" Pd " is the wrong type.", i)));
659898
UNREACHABLE();
660899
}
661900
}
@@ -709,6 +948,11 @@ DEFINE_NATIVE_ENTRY(Wasm_addGlobalImport, 0, 5) {
709948
return nullptr;
710949
}
711950

951+
DEFINE_NATIVE_ENTRY(Wasm_addFunctionImport, 0, 4) {
952+
Exceptions::ThrowUnsupportedError("WASM is disabled");
953+
return nullptr;
954+
}
955+
712956
DEFINE_NATIVE_ENTRY(Wasm_initMemory, 0, 3) {
713957
Exceptions::ThrowUnsupportedError("WASM is disabled");
714958
return nullptr;

runtime/vm/bootstrap_natives.h

+1
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ namespace dart {
396396
V(Wasm_initImports, 2) \
397397
V(Wasm_addMemoryImport, 3) \
398398
V(Wasm_addGlobalImport, 5) \
399+
V(Wasm_addFunctionImport, 4) \
399400
V(Wasm_initMemory, 3) \
400401
V(Wasm_growMemory, 2) \
401402
V(Wasm_initInstance, 3) \

0 commit comments

Comments
 (0)