Add a wasmtime-specific wasmtime_wat2wasm C API (#1206)
* Add a wasmtime-specific `wasmtime_wat2wasm` C API This commit implements a wasmtime-specific C API for converting the text format to the binary format. An upstream spec issue exists for adding this to the C API, but in the meantime we can experiment with our own version of this API and use it in the C# extension, for example! Closes #1000 * Reorder arguments * Use wasm_byte_vec_t for input `*.wat` * Mark wat input as const * Return an error message and use `fixed` * Actually include the error message * Use `fixed` in `Module.cs` as well
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2263,6 +2263,7 @@ dependencies = [
|
|||||||
"wasi-common",
|
"wasi-common",
|
||||||
"wasmtime",
|
"wasmtime",
|
||||||
"wasmtime-wasi",
|
"wasmtime-wasi",
|
||||||
|
"wat",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -20,3 +20,4 @@ doctest = false
|
|||||||
wasmtime = { path = "../api" }
|
wasmtime = { path = "../api" }
|
||||||
wasi-common = { path = "../wasi-common" }
|
wasi-common = { path = "../wasi-common" }
|
||||||
wasmtime-wasi = { path = "../wasi" }
|
wasmtime-wasi = { path = "../wasi" }
|
||||||
|
wat = "1.0"
|
||||||
|
|||||||
@@ -38,6 +38,26 @@ WASMTIME_CONFIG_PROP(cranelift_opt_level, wasmtime_opt_level_t)
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Converts from the text format of WebAssembly to to the binary format.
|
||||||
|
//
|
||||||
|
// * `engine` - a previously created engine which will drive allocations and
|
||||||
|
// such
|
||||||
|
// * `wat` - this it the input buffer with the WebAssembly Text Format inside of
|
||||||
|
// it. This will be parsed and converted to the binary format.
|
||||||
|
// * `ret` - if the conversion is successful, this byte vector is filled in with
|
||||||
|
// the WebAssembly binary format.
|
||||||
|
// * `error_message` - if the conversion fails, this is filled in with a
|
||||||
|
// descriptive error message of why parsing failed. This parameter is
|
||||||
|
// optional.
|
||||||
|
//
|
||||||
|
// Returns `true` if conversion succeeded, or `false` if it failed.
|
||||||
|
bool wasmtime_wat2wasm(
|
||||||
|
wasm_engine_t *engine,
|
||||||
|
const wasm_byte_vec_t *wat,
|
||||||
|
own wasm_byte_vec_t *ret,
|
||||||
|
own wasm_byte_vec_t *error_message,
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
//! This file defines the extern "C" API extension, which are specific
|
//! This file defines the extern "C" API extension, which are specific
|
||||||
//! to the wasmtime implementation.
|
//! to the wasmtime implementation.
|
||||||
|
|
||||||
use crate::wasm_config_t;
|
use crate::{wasm_byte_vec_t, wasm_config_t, wasm_engine_t};
|
||||||
|
use std::str;
|
||||||
use wasmtime::{OptLevel, Strategy};
|
use wasmtime::{OptLevel, Strategy};
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@@ -86,3 +87,33 @@ pub unsafe extern "C" fn wasmtime_config_cranelift_opt_level_set(
|
|||||||
WASMTIME_OPT_LEVEL_SPEED_AND_SIZE => OptLevel::SpeedAndSize,
|
WASMTIME_OPT_LEVEL_SPEED_AND_SIZE => OptLevel::SpeedAndSize,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasmtime_wat2wasm(
|
||||||
|
_engine: *mut wasm_engine_t,
|
||||||
|
wat: *const wasm_byte_vec_t,
|
||||||
|
ret: *mut wasm_byte_vec_t,
|
||||||
|
error: *mut wasm_byte_vec_t,
|
||||||
|
) -> bool {
|
||||||
|
let wat = match str::from_utf8((*wat).as_slice()) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => {
|
||||||
|
if !error.is_null() {
|
||||||
|
(*error).set_from_slice(b"input was not valid utf-8");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match wat::parse_str(wat) {
|
||||||
|
Ok(bytes) => {
|
||||||
|
(*ret).set_from_slice(&bytes);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if !error.is_null() {
|
||||||
|
(*error).set_from_slice(e.to_string().as_bytes());
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wasmtime
|
namespace Wasmtime
|
||||||
{
|
{
|
||||||
@@ -40,6 +42,34 @@ namespace Wasmtime
|
|||||||
return new Store(this);
|
return new Store(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the WebAssembly text format to the binary format
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns the binary-encoded wasm module.</returns>
|
||||||
|
public byte[] WatToWasm(string wat)
|
||||||
|
{
|
||||||
|
var watBytes = Encoding.UTF8.GetBytes(wat);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte *ptr = watBytes)
|
||||||
|
{
|
||||||
|
Interop.wasm_byte_vec_t watByteVec;
|
||||||
|
watByteVec.size = (UIntPtr)watBytes.Length;
|
||||||
|
watByteVec.data = ptr;
|
||||||
|
if (!Interop.wasmtime_wat2wasm(Handle, ref watByteVec, out var bytes, out var error)) {
|
||||||
|
var errorSpan = new ReadOnlySpan<byte>(error.data, checked((int)error.size));
|
||||||
|
var message = Encoding.UTF8.GetString(errorSpan);
|
||||||
|
Interop.wasm_byte_vec_delete(ref error);
|
||||||
|
throw new WasmtimeException("failed to parse input wat: " + message);
|
||||||
|
}
|
||||||
|
var byteSpan = new ReadOnlySpan<byte>(bytes.data, checked((int)bytes.size));
|
||||||
|
var ret = byteSpan.ToArray();
|
||||||
|
Interop.wasm_byte_vec_delete(ref bytes);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -974,5 +974,14 @@ namespace Wasmtime
|
|||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
public static extern void wasmtime_config_cranelift_opt_level_set(WasmConfigHandle config, wasmtime_opt_level_t level);
|
public static extern void wasmtime_config_cranelift_opt_level_set(WasmConfigHandle config, wasmtime_opt_level_t level);
|
||||||
|
|
||||||
|
[DllImport(LibraryName, CharSet=CharSet.Ansi)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool wasmtime_wat2wasm(
|
||||||
|
EngineHandle engine,
|
||||||
|
ref wasm_byte_vec_t wat,
|
||||||
|
out wasm_byte_vec_t vec,
|
||||||
|
out wasm_byte_vec_t error_message
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,13 @@ namespace Wasmtime
|
|||||||
throw new ArgumentNullException(nameof(store));
|
throw new ArgumentNullException(nameof(store));
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytesHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
unsafe
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte *ptr = bytes)
|
||||||
{
|
{
|
||||||
Interop.wasm_byte_vec_t vec;
|
Interop.wasm_byte_vec_t vec;
|
||||||
vec.size = (UIntPtr)bytes.Length;
|
vec.size = (UIntPtr)bytes.Length;
|
||||||
vec.data = (byte*)bytesHandle.AddrOfPinnedObject();
|
vec.data = ptr;
|
||||||
|
|
||||||
Handle = Interop.wasm_module_new(store.Handle, ref vec);
|
Handle = Interop.wasm_module_new(store.Handle, ref vec);
|
||||||
}
|
}
|
||||||
@@ -33,10 +31,6 @@ namespace Wasmtime
|
|||||||
throw new WasmtimeException($"WebAssembly module '{name}' is not valid.");
|
throw new WasmtimeException($"WebAssembly module '{name}' is not valid.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
bytesHandle.Free();
|
|
||||||
}
|
|
||||||
|
|
||||||
Store = store;
|
Store = store;
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ namespace Wasmtime.Tests
|
|||||||
.WithReferenceTypes(true)
|
.WithReferenceTypes(true)
|
||||||
.Build();
|
.Build();
|
||||||
Store = Engine.CreateStore();
|
Store = Engine.CreateStore();
|
||||||
Module = Store.CreateModule(Path.Combine("Modules", ModuleFileName));
|
var wat = Path.Combine("Modules", ModuleFileName);
|
||||||
|
var wasm = Engine.WatToWasm(File.ReadAllText(wat));
|
||||||
|
Module = Store.CreateModule(wat, wasm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class FunctionExportsFixture : ModuleFixture
|
public class FunctionExportsFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "FunctionExports.wasm";
|
protected override string ModuleFileName => "FunctionExports.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FunctionExportsTests : IClassFixture<FunctionExportsFixture>
|
public class FunctionExportsTests : IClassFixture<FunctionExportsFixture>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class FunctionImportsFixture : ModuleFixture
|
public class FunctionImportsFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "FunctionImports.wasm";
|
protected override string ModuleFileName => "FunctionImports.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FunctionImportsTests : IClassFixture<FunctionImportsFixture>
|
public class FunctionImportsTests : IClassFixture<FunctionImportsFixture>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class FunctionThunkingFixture : ModuleFixture
|
public class FunctionThunkingFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "FunctionThunking.wasm";
|
protected override string ModuleFileName => "FunctionThunking.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FunctionThunkingTests : IClassFixture<FunctionThunkingFixture>
|
public class FunctionThunkingTests : IClassFixture<FunctionThunkingFixture>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class GlobalExportsFixture : ModuleFixture
|
public class GlobalExportsFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "GlobalExports.wasm";
|
protected override string ModuleFileName => "GlobalExports.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GlobalExportsTests : IClassFixture<GlobalExportsFixture>
|
public class GlobalExportsTests : IClassFixture<GlobalExportsFixture>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class GlobalImportBindingFixture : ModuleFixture
|
public class GlobalImportBindingFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "GlobalImportBindings.wasm";
|
protected override string ModuleFileName => "GlobalImportBindings.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GlobalImportBindingTests : IClassFixture<GlobalImportBindingFixture>
|
public class GlobalImportBindingTests : IClassFixture<GlobalImportBindingFixture>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class GlobalImportsFixture : ModuleFixture
|
public class GlobalImportsFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "GlobalImports.wasm";
|
protected override string ModuleFileName => "GlobalImports.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GlobalImportsTests : IClassFixture<GlobalImportsFixture>
|
public class GlobalImportsTests : IClassFixture<GlobalImportsFixture>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class MemoryExportsFixture : ModuleFixture
|
public class MemoryExportsFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "MemoryExports.wasm";
|
protected override string ModuleFileName => "MemoryExports.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemoryExportsTests : IClassFixture<MemoryExportsFixture>
|
public class MemoryExportsTests : IClassFixture<MemoryExportsFixture>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class MemoryImportBindingFixture : ModuleFixture
|
public class MemoryImportBindingFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "MemoryImportBinding.wasm";
|
protected override string ModuleFileName => "MemoryImportBinding.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemoryImportBindingTests : IClassFixture<MemoryImportBindingFixture>
|
public class MemoryImportBindingTests : IClassFixture<MemoryImportBindingFixture>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class MemoryImportFromModuleFixture : ModuleFixture
|
public class MemoryImportFromModuleFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "MemoryImportFromModule.wasm";
|
protected override string ModuleFileName => "MemoryImportFromModule.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemoryImportFromModuleTests : IClassFixture<MemoryImportFromModuleFixture>
|
public class MemoryImportFromModuleTests : IClassFixture<MemoryImportFromModuleFixture>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class MemoryImportNoUpperBoundFixture : ModuleFixture
|
public class MemoryImportNoUpperBoundFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "MemoryImportNoUpperBound.wasm";
|
protected override string ModuleFileName => "MemoryImportNoUpperBound.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemoryImportNoUpperBoundTests : IClassFixture<MemoryImportNoUpperBoundFixture>
|
public class MemoryImportNoUpperBoundTests : IClassFixture<MemoryImportNoUpperBoundFixture>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class MemoryImportWithUpperBoundFixture : ModuleFixture
|
public class MemoryImportWithUpperBoundFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "MemoryImportWithUpperBound.wasm";
|
protected override string ModuleFileName => "MemoryImportWithUpperBound.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemoryImportWithUpperBoundTests : IClassFixture<MemoryImportWithUpperBoundFixture>
|
public class MemoryImportWithUpperBoundTests : IClassFixture<MemoryImportWithUpperBoundFixture>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -8,7 +8,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class TableExportsFixture : ModuleFixture
|
public class TableExportsFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "TableExports.wasm";
|
protected override string ModuleFileName => "TableExports.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TableExportsTests : IClassFixture<TableExportsFixture>
|
public class TableExportsTests : IClassFixture<TableExportsFixture>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class TableImportsFixture : ModuleFixture
|
public class TableImportsFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "TableImports.wasm";
|
protected override string ModuleFileName => "TableImports.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TableImportsTests : IClassFixture<TableImportsFixture>
|
public class TableImportsTests : IClassFixture<TableImportsFixture>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public class WasiFixture : ModuleFixture
|
public class WasiFixture : ModuleFixture
|
||||||
{
|
{
|
||||||
protected override string ModuleFileName => "Wasi.wasm";
|
protected override string ModuleFileName => "Wasi.wat";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WasiTests : IClassFixture<WasiFixture>
|
public class WasiTests : IClassFixture<WasiFixture>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Modules/*.wasm" CopyToOutputDirectory="PreserveNewest" />
|
<None Update="Modules/*.wat" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user