Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

experiment: mechanism for interacting with external Wasm components #4580

Draft
wants to merge 40 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c10b8fe
Add 'Prim.componentCall()' for interacting with an external Wasm comp…
rvanasa Jun 27, 2024
fe8b7f4
Add '-import-component' flag
rvanasa Jun 27, 2024
154ee4e
Merge branch 'master' of https://github.com/dfinity/motoko into ryan/…
rvanasa Jun 27, 2024
163fb60
Add M0200 error message ('component import is unavailable')
rvanasa Jun 27, 2024
8c11305
Fix compile error
rvanasa Jun 27, 2024
d729cd5
Add test
rvanasa Jun 27, 2024
36b92cf
Adjust error code in error message
rvanasa Jun 27, 2024
330a295
Fix
rvanasa Jun 27, 2024
8874431
Rename test
rvanasa Jun 27, 2024
74c5809
Adjust error message
rvanasa Jun 27, 2024
f4a63cb
Update test
rvanasa Jun 27, 2024
90f7361
Misc
rvanasa Jun 27, 2024
d18df6d
move M0200 error detection from compile.ml to typing.ml, using specia…
crusso Jun 28, 2024
1a2a3e7
Merge branch 'ryan/component-call' of https://github.com/dfinity/moto…
rvanasa Jun 28, 2024
3be8fd9
Rename 'componentCall' prim to 'wit:component:call'
rvanasa Jun 28, 2024
36bf9ad
Accept new test output
rvanasa Jun 28, 2024
68bca73
Set up `Blob -> Blob` function type
rvanasa Jun 28, 2024
866e778
Temporarily use unboxed constant expressions
rvanasa Jul 1, 2024
1eca269
Merge branch 'master' into ryan/component-call
rvanasa Jul 9, 2024
9100f65
Use Blob arg in place of Nat32
rvanasa Jul 10, 2024
0b22a79
Merge branch 'ryan/component-call-blob' into ryan/component-call
rvanasa Jul 10, 2024
fabbb7c
Progress
rvanasa Jul 10, 2024
64d0091
Accept new test output
rvanasa Jul 10, 2024
5912a33
Merge branch 'master' into ryan/component-call
rvanasa Jul 10, 2024
b6406f4
Merge branch 'ryan/component-call' into ryan/component-call-blob
rvanasa Jul 10, 2024
5d9d496
Implement Blob return value
rvanasa Jul 10, 2024
1397ed8
Rename local variable
rvanasa Jul 10, 2024
1a6b821
Set up 'cabi_realloc'
rvanasa Jul 11, 2024
c751640
Export 'cabi_realloc'
rvanasa Jul 11, 2024
97a5ebb
Simplify
rvanasa Jul 11, 2024
93f5089
Working 'Blob -> Blob' component call logic
rvanasa Jul 11, 2024
b6df7a1
Misc
rvanasa Jul 12, 2024
8c3cbc6
Merge branch 'master' into ryan/component-call
rvanasa Jul 19, 2024
cd5fa02
Fix missing RTS import
rvanasa Jul 19, 2024
9ff3c22
Merge branch 'ryan/component-call' of https://github.com/dfinity/moto…
rvanasa Jul 19, 2024
4b95c4f
Reduce diff
rvanasa Jul 19, 2024
bf1fe7d
Update heap-32 test
rvanasa Jul 19, 2024
3912581
Adjust more tests
rvanasa Jul 19, 2024
93fcb8b
Merge branch 'master' into ryan/component-call
rvanasa Jul 22, 2024
80ebfef
Merge branch 'master' into ryan/component-call
rvanasa Jul 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions rts/motoko-rts/src/component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Wasm Component Model utilities

use crate::{
barriers::allocation_barrier,
memory::{alloc_blob, Memory},
types::Value,
Bytes,
};
use alloc as alloc_crate;
use core::convert::TryInto;
use motoko_rts_macros::ic_mem_fn;

/// Convert a Canonical ABI `list<u8>` pointer to a Motoko `Blob`.
#[ic_mem_fn]
unsafe fn blob_of_cabi<M: Memory>(mem: &mut M, ret: *const usize) -> Value {
let content = *ret as *const u8;
let len = *ret.add(1);

// TODO: reuse Blob from `cabi_realloc`?
let value = alloc_blob(mem, Bytes(len.try_into().unwrap())); // Checked conversion from `usize` to `u32`
let blob = value.as_blob_mut();
let dest = blob.payload_addr();
for i in 0..len as usize {
*dest.add(i) = *content.add(i);
}
allocation_barrier(value)
}

/// Canonical ABI allocation logic.
/// Derived from: https://docs.rs/wit-bindgen-rt/0.27.0/src/wit_bindgen_rt/lib.rs.html#54-88
#[ic_mem_fn]
unsafe fn cabi_realloc<M: Memory>(
_mem: &mut M,
old_ptr: *mut u8,
old_len: usize,
align: usize,
new_len: usize,
) -> *mut u8 {
use alloc_crate::alloc::{self, Layout};

let layout;
let ptr = if old_len == 0 {
if new_len == 0 {
return align as *mut u8;
}
layout = Layout::from_size_align_unchecked(new_len, align);
alloc::alloc(layout)
} else {
debug_assert_ne!(new_len, 0, "non-zero old_len requires non-zero new_len!");
layout = Layout::from_size_align_unchecked(old_len, align);
alloc::realloc(old_ptr, layout, new_len)
};
if ptr.is_null() {
unreachable!();
}
ptr
}
1 change: 1 addition & 0 deletions rts/motoko-rts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub mod bitrel;
mod blob_iter;
pub mod buf;
mod char;
mod component;
pub mod constants;
pub mod continuation_table;
#[cfg(feature = "ic")]
Expand Down
25 changes: 25 additions & 0 deletions src/codegen/compile.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,9 @@ module RTS = struct
E.add_func_import env "rts" "stream_shutdown" [I32Type] [];
E.add_func_import env "rts" "stream_reserve" [I32Type; I32Type] [I32Type];
E.add_func_import env "rts" "stream_stable_dest" [I32Type; I64Type; I64Type] [];
if !Flags.import_component then (
E.add_func_import env "rts" "blob_of_cabi" [I32Type] [I32Type];
E.add_func_import env "rts" "cabi_realloc" [I32Type; I32Type; I32Type; I32Type] [I32Type]);
if !Flags.gc_strategy = Flags.Incremental then
incremental_gc_imports env
else
Expand Down Expand Up @@ -11257,6 +11260,24 @@ and compile_prim_invocation (env : E.t) ae p es at =
compile_exp_as env ae SR.UnboxedFloat64 e ^^
E.call_import env "rts" "log" (* musl *)

| OtherPrim "wit:component:call", [e] ->
assert !Flags.import_component;
SR.Vanilla,
(* Read blob pointer and length *)
let set_blob, get_blob = new_local env "blob" in
compile_exp_as env ae SR.Vanilla e ^^ set_blob ^^
(* Allocate return value *)
let set_ret, get_ret = new_local env "ret" in
(* TODO: optimize? *)
Blob.lit env "\x00\x00\x00\x00\x00\x00\x00\x00" ^^ set_ret ^^ (* pointer, length *)
(* Call component export *)
get_blob ^^ Blob.payload_ptr_unskewed env ^^
get_blob ^^ Blob.len env ^^
get_ret ^^ Blob.payload_ptr_unskewed env ^^
E.call_import env "component" "call" ^^
get_ret ^^ Blob.payload_ptr_unskewed env ^^
E.call_import env "rts" "blob_of_cabi"

(* Other prims, nullary *)

| SystemTimePrim, [] ->
Expand Down Expand Up @@ -12830,6 +12851,10 @@ let compile mode rts (prog : Ir.prog) : Wasm_exts.CustomModule.extended_module =
IC.system_imports env;
RTS.system_imports env;

(* Wasm Component Model *)
if !Flags.import_component then
E.add_func_import env "component" "call" [I32Type; I32Type; I32Type] [];

compile_init_func env prog;
let start_fi_o = match E.mode env with
| Flags.ICMode | Flags.RefMode ->
Expand Down
3 changes: 3 additions & 0 deletions src/exes/moc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ let argspec = [
"-wasi-system-api",
Arg.Unit (fun () -> Flags.(compile_mode := WASIMode)),
" use the WASI system API (wasmtime)";
"-import-component",
Arg.Unit (fun () -> Flags.(import_component := true)),
" enable calling an external Wasm component";
"-ref-system-api",
Arg.Unit (fun () -> Flags.(compile_mode := RefMode)),
" use the reference implementation of the Internet Computer system API (ic-ref-run)";
Expand Down
1 change: 1 addition & 0 deletions src/lang_utils/error_codes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,5 @@ let error_codes : (string * string option) list =
"M0197", Some([%blob "lang_utils/error_codes/M0197.md"]); (* `system` capability required *)
"M0198", Some([%blob "lang_utils/error_codes/M0198.md"]); (* Unused field pattern warning *)
"M0199", Some([%blob "lang_utils/error_codes/M0199.md"]); (* Deprecate experimental stable memory *)
"M0200", Some([%blob "lang_utils/error_codes/M0200.md"]); (* Component import is unavailable *)
]
5 changes: 5 additions & 0 deletions src/lang_utils/error_codes/M0200.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# M0200

This error indicates that the Wasm Component Model (cross-language) functionality is not enabled.

You can fix this by passing the `-import-component` compiler flag, e.g. `moc -wasi-system-api -import-component ...`.
1 change: 1 addition & 0 deletions src/linking/linkModule.ml
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ let remove_non_ic_exports (em : extended_module) : extended_module =
exported in the final module *)
let is_ic_export (exp : export) =
Lib.String.chop_prefix "canister_" (Lib.Utf8.encode exp.it.name) <> None ||
(!Mo_config.Flags.import_component && Lib.String.chop_prefix "cabi_" (Lib.Utf8.encode exp.it.name) <> None) || (* Wasm Component Model *)
"_start" = Lib.Utf8.encode exp.it.name
in

Expand Down
1 change: 1 addition & 0 deletions src/mo_config/flags.ml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ let use_stable_regions = ref false
let share_code = ref false
let experimental_stable_memory_default = 0 (* _ < 0: error; _ = 0: warn, _ > 0: allow *)
let experimental_stable_memory = ref experimental_stable_memory_default
let import_component = ref false
5 changes: 4 additions & 1 deletion src/mo_frontend/typing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ let check_deprecation env at desc id depr =
| _ -> fun _ _ _ _ -> ())
env at code
"this code is (or uses) the deprecated library `ExperimentalStableMemory`.\nPlease use the `Region` library instead: https://internetcomputer.org/docs/current/motoko/main/stable-memory/stable-regions/#the-region-library or compile with flag `--experimental-stable-memory 1` to suppress this message."
end
end
| Some ("M0200" as code) ->
if not !Flags.import_component then
error env at code "component import is unavailable (pass `-import-component` flag)"
| Some msg ->
warn env at "M0154" "%s %s is deprecated:\n%s" desc id msg
| None -> ()
Expand Down
5 changes: 5 additions & 0 deletions src/prelude/prim.mo
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,11 @@ func arctan2(y : Float, x : Float) : Float = (prim "fatan2" : (Float, Float) ->
func exp(f : Float) : Float = (prim "fexp" : Float -> Float) f;
func log(f : Float) : Float = (prim "flog" : Float -> Float) f;

// Wasm Component Model functions

/// @deprecated M0200
func componentCall(value : Blob) : Blob = (prim "wit:component:call" : Blob -> Blob) value;

// Array utilities

func Array_init<T>(len : Nat, x : T) : [var T] {
Expand Down
2 changes: 1 addition & 1 deletion test/bench/ok/heap-32.drun-run-opt.ok
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101
ingress Completed: Reply: 0x4449444c0000
debug.print: (50_227, +29_863_068, 708_174_952)
debug.print: (50_070, +32_992_212, 766_613_680)
debug.print: (50_070, +32_992_212, 766_613_760)
ingress Completed: Reply: 0x4449444c0000
2 changes: 1 addition & 1 deletion test/bench/ok/heap-32.drun-run.ok
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ingress Completed: Reply: 0x4449444c016c01b3c4b1f204680100010a00000000000000000101
ingress Completed: Reply: 0x4449444c0000
debug.print: (50_227, +29_863_068, 769_000_085)
debug.print: (50_070, +32_992_212, 830_427_376)
debug.print: (50_070, +32_992_212, 830_427_500)
ingress Completed: Reply: 0x4449444c0000
3 changes: 3 additions & 0 deletions test/fail/M0200.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Prim = "mo:⛔";

ignore Prim.componentCall(123);
1 change: 1 addition & 0 deletions test/fail/ok/M0200.tc.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
M0200.mo:3.8-3.26: type error [M0200], component import is unavailable (pass `-import-component` flag)
1 change: 1 addition & 0 deletions test/fail/ok/M0200.tc.ret.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Return code 1
1 change: 1 addition & 0 deletions test/fail/ok/no-timer-canc.tc.ok
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ no-timer-canc.mo:3.10-3.21: type error [M0119], object field cancelTimer is not
clzNat32 : Nat32 -> Nat32;
clzNat64 : Nat64 -> Nat64;
clzNat8 : Nat8 -> Nat8;
componentCall : Blob -> Blob;
cos : Float -> Float;
createActor : (Blob, Blob) -> async Principal;
ctzInt16 : Int16 -> Int16;
Expand Down
1 change: 1 addition & 0 deletions test/fail/ok/no-timer-set.tc.ok
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ no-timer-set.mo:3.10-3.18: type error [M0119], object field setTimer is not cont
clzNat32 : Nat32 -> Nat32;
clzNat64 : Nat64 -> Nat64;
clzNat8 : Nat8 -> Nat8;
componentCall : Blob -> Blob;
cos : Float -> Float;
createActor : (Blob, Blob) -> async Principal;
ctzInt16 : Int16 -> Int16;
Expand Down