-
Notifications
You must be signed in to change notification settings - Fork 15
inNative cref Extension
inNative implements a custom cref
value type that represents a C pointer. Most of the time, it behaves mostly like anyref
would from the Reference Type Proposal, acting as an opaque pointer to C memory that is passed around. Unlike anyref
, however, you are allowed to pass either i32
or i64
into a cref
type. The type has a binary encoding and can be implemented into any standard webassembly module, but because no compiler can generate this value, it's mostly intended to be used in .wat
files.
To demonstrate how cref
works, lets start with a WebAssembly module that calls windows kernel functions to write to standard output, using the _innative_to_c
Helper Function.
(import "!STD" "GetStdHandle" (func $getstdhandle (param i32) (result i64)))
(import "!STD" "WriteConsoleA" (func $writeconsole (param i64 i64 i32 i64 i64) (result i32)))
(import "" "_innative_to_c" (func $toc (param i64) (result i64)))
(func $caller
i32.const -11
call $getstdhandle
i64.const 0
call $toc
i32.const 14
i64.const 16
call $toc
i64.const 0
call $writeconsole
drop
)
Here, we are representing C pointer values with the i64
type (and consequently, this will only work on 64-bit architectures). To acquire a C pointer from a WebAssembly memory offset, we call _innative_to_c
which adds the base value of the memory pointer to the offset and returns the result. We have two pointers here, one for the string and one for the character count output. Unfortunately, most of the other parameters are also integers, so it can be hard to keep track of what's what. We can clean this up by using cref
instead.
(import "!STD" "GetStdHandle" (func $getstdhandle (param i32) (result cref)))
(import "!STD" "WriteConsoleA" (func $writeconsole (param cref cref i32 cref i64) (result i32)))
(func $caller
i32.const -11
call $getstdhandle
i64.const 0
i32.const 14
i64.const 16
i64.const 0
call $writeconsole
drop
)
We change our pointer parameters from i64
to cref
and simply remove our calls to _innative_to_c
. Even though we have pushed i64
parameters on to the stack, when the call consumes those values, they will be automatically converted to cref
values.
It's important to note that the final parameter must be a null pointer, which cannot be represented by cref
. Instead, we keep it as an i64
and pass in 0. If your pointer has a chance of being null, you'll have to make a null check and conditionally call _innative_to_c
, because WebAssembly has no null reference (yet).
We also changed GetStdHandle
to return a cref
pointer, but this must remain an opaque pointer. We simply take this pointer and pass it unmodified into the WriteConsoleA
method. If we had attempted to store it into an integer, it would have failed. If you need to transform a C pointer back into a WebAssembly offset, you must use _innative_from_c
.