Skip to content

Commit

Permalink
Add a wasmtime-specific wasmtime_wat2wasm C API (#1206)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
alexcrichton authored Mar 3, 2020
1 parent 732c646 commit 77e17d8
Show file tree
Hide file tree
Showing 38 changed files with 118 additions and 30 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/c-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ doctest = false
wasmtime = { path = "../api" }
wasi-common = { path = "../wasi-common" }
wasmtime-wasi = { path = "../wasi" }
wat = "1.0"
20 changes: 20 additions & 0 deletions crates/c-api/include/wasmtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
} // extern "C"
#endif
Expand Down
33 changes: 32 additions & 1 deletion crates/c-api/src/ext.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! This file defines the extern "C" API extension, which are specific
//! 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};

#[repr(u8)]
Expand Down Expand Up @@ -86,3 +87,33 @@ pub unsafe extern "C" fn wasmtime_config_cranelift_opt_level_set(
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
}
}
}
30 changes: 30 additions & 0 deletions crates/misc/dotnet/src/Engine.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Text;
using System.Runtime.InteropServices;

namespace Wasmtime
{
Expand Down Expand Up @@ -40,6 +42,34 @@ public Store CreateStore()
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/>
public void Dispose()
{
Expand Down
15 changes: 12 additions & 3 deletions crates/misc/dotnet/src/Interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,7 @@ public static extern unsafe void wasi_config_set_env(
public static extern bool wasi_config_set_stdin_file(
WasiConfigHandle config,
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
);
);

[DllImport(LibraryName)]
public static extern void wasi_config_inherit_stdin(WasiConfigHandle config);
Expand All @@ -909,7 +909,7 @@ public static extern bool wasi_config_set_stdin_file(
public static extern bool wasi_config_set_stdout_file(
WasiConfigHandle config,
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
);
);

[DllImport(LibraryName)]
public static extern void wasi_config_inherit_stdout(WasiConfigHandle config);
Expand All @@ -919,7 +919,7 @@ public static extern bool wasi_config_set_stdout_file(
public static extern bool wasi_config_set_stderr_file(
WasiConfigHandle config,
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
);
);

[DllImport(LibraryName)]
public static extern void wasi_config_inherit_stderr(WasiConfigHandle config);
Expand Down Expand Up @@ -974,5 +974,14 @@ out IntPtr trap

[DllImport(LibraryName)]
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
);
}
}
12 changes: 3 additions & 9 deletions crates/misc/dotnet/src/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ internal Module(Store store, string name, byte[] bytes)
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;
vec.size = (UIntPtr)bytes.Length;
vec.data = (byte*)bytesHandle.AddrOfPinnedObject();
vec.data = ptr;

Handle = Interop.wasm_module_new(store.Handle, ref vec);
}
Expand All @@ -33,10 +31,6 @@ internal Module(Store store, string name, byte[] bytes)
throw new WasmtimeException($"WebAssembly module '{name}' is not valid.");
}
}
finally
{
bytesHandle.Free();
}

Store = store;
Name = name;
Expand Down
4 changes: 3 additions & 1 deletion crates/misc/dotnet/tests/Fixtures/ModuleFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ public ModuleFixture()
.WithReferenceTypes(true)
.Build();
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()
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/FunctionExportsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Wasmtime.Tests
{
public class FunctionExportsFixture : ModuleFixture
{
protected override string ModuleFileName => "FunctionExports.wasm";
protected override string ModuleFileName => "FunctionExports.wat";
}

public class FunctionExportsTests : IClassFixture<FunctionExportsFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/FunctionImportsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Wasmtime.Tests
{
public class FunctionImportsFixture : ModuleFixture
{
protected override string ModuleFileName => "FunctionImports.wasm";
protected override string ModuleFileName => "FunctionImports.wat";
}

public class FunctionImportsTests : IClassFixture<FunctionImportsFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/FunctionThunkingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Wasmtime.Tests
{
public class FunctionThunkingFixture : ModuleFixture
{
protected override string ModuleFileName => "FunctionThunking.wasm";
protected override string ModuleFileName => "FunctionThunking.wat";
}

public class FunctionThunkingTests : IClassFixture<FunctionThunkingFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/GlobalExportsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Wasmtime.Tests
{
public class GlobalExportsFixture : ModuleFixture
{
protected override string ModuleFileName => "GlobalExports.wasm";
protected override string ModuleFileName => "GlobalExports.wat";
}

public class GlobalExportsTests : IClassFixture<GlobalExportsFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/GlobalImportBindingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Wasmtime.Tests
{
public class GlobalImportBindingFixture : ModuleFixture
{
protected override string ModuleFileName => "GlobalImportBindings.wasm";
protected override string ModuleFileName => "GlobalImportBindings.wat";
}

public class GlobalImportBindingTests : IClassFixture<GlobalImportBindingFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/GlobalImportsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Wasmtime.Tests
{
public class GlobalImportsFixture : ModuleFixture
{
protected override string ModuleFileName => "GlobalImports.wasm";
protected override string ModuleFileName => "GlobalImports.wat";
}

public class GlobalImportsTests : IClassFixture<GlobalImportsFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/MemoryExportsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Wasmtime.Tests
{
public class MemoryExportsFixture : ModuleFixture
{
protected override string ModuleFileName => "MemoryExports.wasm";
protected override string ModuleFileName => "MemoryExports.wat";
}

public class MemoryExportsTests : IClassFixture<MemoryExportsFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/MemoryImportBindingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Wasmtime.Tests
{
public class MemoryImportBindingFixture : ModuleFixture
{
protected override string ModuleFileName => "MemoryImportBinding.wasm";
protected override string ModuleFileName => "MemoryImportBinding.wat";
}

public class MemoryImportBindingTests : IClassFixture<MemoryImportBindingFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/MemoryImportFromModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Wasmtime.Tests
{
public class MemoryImportFromModuleFixture : ModuleFixture
{
protected override string ModuleFileName => "MemoryImportFromModule.wasm";
protected override string ModuleFileName => "MemoryImportFromModule.wat";
}

public class MemoryImportFromModuleTests : IClassFixture<MemoryImportFromModuleFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/MemoryImportNoUpperBoundTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Wasmtime.Tests
{
public class MemoryImportNoUpperBoundFixture : ModuleFixture
{
protected override string ModuleFileName => "MemoryImportNoUpperBound.wasm";
protected override string ModuleFileName => "MemoryImportNoUpperBound.wat";
}

public class MemoryImportNoUpperBoundTests : IClassFixture<MemoryImportNoUpperBoundFixture>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Wasmtime.Tests
{
public class MemoryImportWithUpperBoundFixture : ModuleFixture
{
protected override string ModuleFileName => "MemoryImportWithUpperBound.wasm";
protected override string ModuleFileName => "MemoryImportWithUpperBound.wat";
}

public class MemoryImportWithUpperBoundTests : IClassFixture<MemoryImportWithUpperBoundFixture>
Expand Down
Binary file removed crates/misc/dotnet/tests/Modules/FunctionExports.wasm
Binary file not shown.
Binary file removed crates/misc/dotnet/tests/Modules/FunctionImports.wasm
Binary file not shown.
Binary file removed crates/misc/dotnet/tests/Modules/FunctionThunking.wasm
Binary file not shown.
Binary file removed crates/misc/dotnet/tests/Modules/GlobalExports.wasm
Binary file not shown.
Binary file not shown.
Binary file removed crates/misc/dotnet/tests/Modules/GlobalImports.wasm
Binary file not shown.
Binary file removed crates/misc/dotnet/tests/Modules/MemoryExports.wasm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed crates/misc/dotnet/tests/Modules/TableExports.wasm
Binary file not shown.
Binary file removed crates/misc/dotnet/tests/Modules/TableImports.wasm
Binary file not shown.
Binary file removed crates/misc/dotnet/tests/Modules/Wasi.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/TableExportsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Wasmtime.Tests
{
public class TableExportsFixture : ModuleFixture
{
protected override string ModuleFileName => "TableExports.wasm";
protected override string ModuleFileName => "TableExports.wat";
}

public class TableExportsTests : IClassFixture<TableExportsFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/TableImportsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Wasmtime.Tests
{
public class TableImportsFixture : ModuleFixture
{
protected override string ModuleFileName => "TableImports.wasm";
protected override string ModuleFileName => "TableImports.wat";
}

public class TableImportsTests : IClassFixture<TableImportsFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/TempFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ public void Dispose()

public string Path { get; private set; }
}
}
}
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/WasiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Wasmtime.Tests
{
public class WasiFixture : ModuleFixture
{
protected override string ModuleFileName => "Wasi.wasm";
protected override string ModuleFileName => "Wasi.wat";
}

public class WasiTests : IClassFixture<WasiFixture>
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/dotnet/tests/Wasmtime.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</Target>

<ItemGroup>
<None Update="Modules/*.wasm" CopyToOutputDirectory="PreserveNewest" />
<None Update="Modules/*.wat" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

</Project>

0 comments on commit 77e17d8

Please sign in to comment.