cranelift: add support for the Mac aarch64 calling convention

This bumps target-lexicon and adds support for the AppleAarch64 calling
convention. Specifically for WebAssembly support, we only have to worry
about the new stack slots convention. Stack slots don't need to be at
least 8-bytes, they can be as small as the data type's size. For
instance, if we need stack slots for (i32, i32), they can be located at
offsets (+0, +4). Note that they still need to be properly aligned on
the data type they're containing, though, so if we need stack slots for
(i32, i64), we can't start the i64 slot at the +4 offset (it must start
at the +8 offset).

Added one test that was failing on the Mac M1, as well as other tests
stressing different yet similar situations.
This commit is contained in:
Benjamin Bouvier
2021-03-18 15:21:40 +01:00
parent 8e43e96410
commit 6e6713ae0b
26 changed files with 204 additions and 37 deletions

4
Cargo.lock generated
View File

@@ -2705,9 +2705,9 @@ dependencies = [
[[package]] [[package]]
name = "target-lexicon" name = "target-lexicon"
version = "0.11.2" version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95" checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
[[package]] [[package]]
name = "tempfile" name = "tempfile"

View File

@@ -37,7 +37,7 @@ wasi-cap-std-sync = { path = "crates/wasi-common/cap-std-sync", version = "0.25.
structopt = { version = "0.3.5", features = ["color", "suggestions"] } structopt = { version = "0.3.5", features = ["color", "suggestions"] }
object = { version = "0.23.0", default-features = false, features = ["write"] } object = { version = "0.23.0", default-features = false, features = ["write"] }
anyhow = "1.0.19" anyhow = "1.0.19"
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.12.0", default-features = false }
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
file-per-thread-logger = "0.1.1" file-per-thread-logger = "0.1.1"
wat = "1.0.36" wat = "1.0.36"

View File

@@ -34,7 +34,7 @@ log = "0.4.8"
termcolor = "1.1.2" termcolor = "1.1.2"
capstone = { version = "0.7.0", optional = true } capstone = { version = "0.7.0", optional = true }
wat = { version = "1.0.36", optional = true } wat = { version = "1.0.36", optional = true }
target-lexicon = { version = "0.11", features = ["std"] } target-lexicon = { version = "0.12", features = ["std"] }
peepmatic-souper = { path = "./peepmatic/crates/souper", version = "0.72.0", optional = true } peepmatic-souper = { path = "./peepmatic/crates/souper", version = "0.72.0", optional = true }
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
rayon = { version = "1", optional = true } rayon = { version = "1", optional = true }

View File

@@ -17,7 +17,7 @@ cranelift-codegen-shared = { path = "./shared", version = "0.72.0" }
cranelift-entity = { path = "../entity", version = "0.72.0" } cranelift-entity = { path = "../entity", version = "0.72.0" }
cranelift-bforest = { path = "../bforest", version = "0.72.0" } cranelift-bforest = { path = "../bforest", version = "0.72.0" }
hashbrown = { version = "0.9.1", optional = true } hashbrown = { version = "0.9.1", optional = true }
target-lexicon = "0.11" target-lexicon = "0.12"
log = { version = "0.4.6", default-features = false } log = { version = "0.4.6", default-features = false }
serde = { version = "1.0.94", features = ["derive"], optional = true } serde = { version = "1.0.94", features = ["derive"], optional = true }
bincode = { version = "1.2.1", optional = true } bincode = { version = "1.2.1", optional = true }

View File

@@ -192,6 +192,7 @@ pub(crate) fn define() -> SettingGroup {
"cold", "cold",
"system_v", "system_v",
"windows_fastcall", "windows_fastcall",
"apple_aarch64",
"baldrdash_system_v", "baldrdash_system_v",
"baldrdash_windows", "baldrdash_windows",
"baldrdash_2020", "baldrdash_2020",

View File

@@ -171,6 +171,21 @@ impl ABIMachineSpec for AArch64MachineDeps {
let has_baldrdash_tls = call_conv == isa::CallConv::Baldrdash2020; let has_baldrdash_tls = call_conv == isa::CallConv::Baldrdash2020;
// See AArch64 ABI (https://c9x.me/compile/bib/abi-arm64.pdf), sections 5.4. // See AArch64 ABI (https://c9x.me/compile/bib/abi-arm64.pdf), sections 5.4.
//
// MacOS aarch64 is slightly different, see also
// https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms.
// We are diverging from the MacOS aarch64 implementation in the
// following ways:
// - sign- and zero- extensions of data types less than 32 bits are not
// implemented yet.
// - i128 arguments passing isn't implemented yet in the standard (non
// MacOS) aarch64 ABI.
// - we align the arguments stack space to a 16-bytes boundary, while
// the MacOS allows aligning only on 8 bytes. In practice it means we're
// slightly overallocating when calling, which is fine, and doesn't
// break our other invariants that the stack is always allocated in
// 16-bytes chunks.
let mut next_xreg = 0; let mut next_xreg = 0;
let mut next_vreg = 0; let mut next_vreg = 0;
let mut next_stack: u64 = 0; let mut next_stack: u64 = 0;
@@ -264,13 +279,24 @@ impl ABIMachineSpec for AArch64MachineDeps {
*next_reg += 1; *next_reg += 1;
remaining_reg_vals -= 1; remaining_reg_vals -= 1;
} else { } else {
// Compute size. Every arg takes a minimum slot of 8 bytes. (16-byte // Compute the stack slot's size.
// stack alignment happens separately after all args.)
let size = (ty_bits(param.value_type) / 8) as u64; let size = (ty_bits(param.value_type) / 8) as u64;
let size = std::cmp::max(size, 8);
// Align. let size = if call_conv != isa::CallConv::AppleAarch64 {
// Every arg takes a minimum slot of 8 bytes. (16-byte stack
// alignment happens separately after all args.)
std::cmp::max(size, 8)
} else {
// MacOS aarch64 allows stack slots with sizes less than 8
// bytes. They still need to be properly aligned on their
// natural data alignment, though.
size
};
// Align the stack slot.
debug_assert!(size.is_power_of_two()); debug_assert!(size.is_power_of_two());
next_stack = align_to(next_stack, size); next_stack = align_to(next_stack, size);
ret.push(ABIArg::stack( ret.push(ABIArg::stack(
next_stack as i64, next_stack as i64,
param.value_type, param.value_type,

View File

@@ -10,22 +10,24 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum CallConv { pub enum CallConv {
/// Best performance, not ABI-stable /// Best performance, not ABI-stable.
Fast, Fast,
/// Smallest caller code size, not ABI-stable /// Smallest caller code size, not ABI-stable.
Cold, Cold,
/// System V-style convention used on many platforms /// System V-style convention used on many platforms.
SystemV, SystemV,
/// Windows "fastcall" convention, also used for x64 and ARM /// Windows "fastcall" convention, also used for x64 and ARM.
WindowsFastcall, WindowsFastcall,
/// SpiderMonkey WebAssembly convention on systems using natively SystemV /// Mac aarch64 calling convention, which is a tweak aarch64 ABI.
AppleAarch64,
/// SpiderMonkey WebAssembly convention on systems using natively SystemV.
BaldrdashSystemV, BaldrdashSystemV,
/// SpiderMonkey WebAssembly convention on Windows /// SpiderMonkey WebAssembly convention on Windows.
BaldrdashWindows, BaldrdashWindows,
/// SpiderMonkey WebAssembly convention for "ABI-2020", with extra TLS /// SpiderMonkey WebAssembly convention for "ABI-2020", with extra TLS
/// register slots in the frame. /// register slots in the frame.
Baldrdash2020, Baldrdash2020,
/// Specialized convention for the probestack function /// Specialized convention for the probestack function.
Probestack, Probestack,
} }
@@ -36,6 +38,7 @@ impl CallConv {
// Default to System V for unknown targets because most everything // Default to System V for unknown targets because most everything
// uses System V. // uses System V.
Ok(CallingConvention::SystemV) | Err(()) => Self::SystemV, Ok(CallingConvention::SystemV) | Err(()) => Self::SystemV,
Ok(CallingConvention::AppleAarch64) => Self::AppleAarch64,
Ok(CallingConvention::WindowsFastcall) => Self::WindowsFastcall, Ok(CallingConvention::WindowsFastcall) => Self::WindowsFastcall,
Ok(unimp) => unimplemented!("calling convention: {:?}", unimp), Ok(unimp) => unimplemented!("calling convention: {:?}", unimp),
} }
@@ -49,6 +52,7 @@ impl CallConv {
LibcallCallConv::Cold => Self::Cold, LibcallCallConv::Cold => Self::Cold,
LibcallCallConv::SystemV => Self::SystemV, LibcallCallConv::SystemV => Self::SystemV,
LibcallCallConv::WindowsFastcall => Self::WindowsFastcall, LibcallCallConv::WindowsFastcall => Self::WindowsFastcall,
LibcallCallConv::AppleAarch64 => Self::AppleAarch64,
LibcallCallConv::BaldrdashSystemV => Self::BaldrdashSystemV, LibcallCallConv::BaldrdashSystemV => Self::BaldrdashSystemV,
LibcallCallConv::BaldrdashWindows => Self::BaldrdashWindows, LibcallCallConv::BaldrdashWindows => Self::BaldrdashWindows,
LibcallCallConv::Baldrdash2020 => Self::Baldrdash2020, LibcallCallConv::Baldrdash2020 => Self::Baldrdash2020,
@@ -80,6 +84,7 @@ impl fmt::Display for CallConv {
Self::Cold => "cold", Self::Cold => "cold",
Self::SystemV => "system_v", Self::SystemV => "system_v",
Self::WindowsFastcall => "windows_fastcall", Self::WindowsFastcall => "windows_fastcall",
Self::AppleAarch64 => "apple_aarch64",
Self::BaldrdashSystemV => "baldrdash_system_v", Self::BaldrdashSystemV => "baldrdash_system_v",
Self::BaldrdashWindows => "baldrdash_windows", Self::BaldrdashWindows => "baldrdash_windows",
Self::Baldrdash2020 => "baldrdash_2020", Self::Baldrdash2020 => "baldrdash_2020",
@@ -96,6 +101,7 @@ impl str::FromStr for CallConv {
"cold" => Ok(Self::Cold), "cold" => Ok(Self::Cold),
"system_v" => Ok(Self::SystemV), "system_v" => Ok(Self::SystemV),
"windows_fastcall" => Ok(Self::WindowsFastcall), "windows_fastcall" => Ok(Self::WindowsFastcall),
"apple_aarch64" => Ok(Self::AppleAarch64),
"baldrdash_system_v" => Ok(Self::BaldrdashSystemV), "baldrdash_system_v" => Ok(Self::BaldrdashSystemV),
"baldrdash_windows" => Ok(Self::BaldrdashWindows), "baldrdash_windows" => Ok(Self::BaldrdashWindows),
"baldrdash_2020" => Ok(Self::Baldrdash2020), "baldrdash_2020" => Ok(Self::Baldrdash2020),

View File

@@ -907,6 +907,7 @@ fn get_intreg_for_retval(
_ => None, _ => None,
}, },
CallConv::BaldrdashWindows | CallConv::Probestack => todo!(), CallConv::BaldrdashWindows | CallConv::Probestack => todo!(),
CallConv::AppleAarch64 => unreachable!(),
} }
} }
@@ -933,6 +934,7 @@ fn get_fltreg_for_retval(
_ => None, _ => None,
}, },
CallConv::BaldrdashWindows | CallConv::Probestack => todo!(), CallConv::BaldrdashWindows | CallConv::Probestack => todo!(),
CallConv::AppleAarch64 => unreachable!(),
} }
} }
@@ -1001,6 +1003,7 @@ fn get_callee_saves(call_conv: &CallConv, regs: &Set<Writable<RealReg>>) -> Vec<
.filter(|r| is_callee_save_fastcall(r.to_reg())) .filter(|r| is_callee_save_fastcall(r.to_reg()))
.collect(), .collect(),
CallConv::Probestack => todo!("probestack?"), CallConv::Probestack => todo!("probestack?"),
CallConv::AppleAarch64 => unreachable!(),
}; };
// Sort registers for deterministic code output. We can do an unstable sort because the // Sort registers for deterministic code output. We can do an unstable sort because the
// registers will be unique (there are no dups). // registers will be unique (there are no dups).

View File

@@ -512,6 +512,7 @@ pub fn prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> Codege
} }
CallConv::Probestack => unimplemented!("probestack calling convention"), CallConv::Probestack => unimplemented!("probestack calling convention"),
CallConv::Baldrdash2020 => unimplemented!("Baldrdash ABI 2020"), CallConv::Baldrdash2020 => unimplemented!("Baldrdash ABI 2020"),
CallConv::AppleAarch64 => unreachable!(),
} }
} }

View File

@@ -646,7 +646,8 @@ impl<M: ABIMachineSpec> ABICalleeImpl<M> {
|| call_conv == isa::CallConv::Fast || call_conv == isa::CallConv::Fast
|| call_conv == isa::CallConv::Cold || call_conv == isa::CallConv::Cold
|| call_conv.extends_baldrdash() || call_conv.extends_baldrdash()
|| call_conv.extends_windows_fastcall(), || call_conv.extends_windows_fastcall()
|| call_conv == isa::CallConv::AppleAarch64,
"Unsupported calling convention: {:?}", "Unsupported calling convention: {:?}",
call_conv call_conv
); );

View File

@@ -23,7 +23,7 @@ gimli = { version = "0.23.0", default-features = false, features = ["read"] }
log = "0.4.6" log = "0.4.6"
memmap2 = "0.2.1" memmap2 = "0.2.1"
num_cpus = "1.8.0" num_cpus = "1.8.0"
target-lexicon = "0.11" target-lexicon = "0.12"
thiserror = "1.0.15" thiserror = "1.0.15"
anyhow = "1.0.32" anyhow = "1.0.32"

View File

@@ -12,7 +12,7 @@ edition = "2018"
[dependencies] [dependencies]
cranelift-codegen = { path = "../codegen", version = "0.72.0", default-features = false } cranelift-codegen = { path = "../codegen", version = "0.72.0", default-features = false }
target-lexicon = "0.11" target-lexicon = "0.12"
log = { version = "0.4.6", default-features = false } log = { version = "0.4.6", default-features = false }
hashbrown = { version = "0.9.1", optional = true } hashbrown = { version = "0.9.1", optional = true }
smallvec = { version = "1.6.1" } smallvec = { version = "1.6.1" }

View File

@@ -18,7 +18,7 @@ anyhow = "1.0"
region = "2.2.0" region = "2.2.0"
libc = { version = "0.2.42" } libc = { version = "0.2.42" }
errno = "0.2.4" errno = "0.2.4"
target-lexicon = "0.11" target-lexicon = "0.12"
memmap2 = { version = "0.2.1", optional = true } memmap2 = { version = "0.2.1", optional = true }
log = { version = "0.4.6", default-features = false } log = { version = "0.4.6", default-features = false }

View File

@@ -12,7 +12,7 @@ edition = "2018"
[dependencies] [dependencies]
cranelift-codegen = { path = "../codegen", version = "0.72.0", default-features = false } cranelift-codegen = { path = "../codegen", version = "0.72.0", default-features = false }
target-lexicon = "0.11" target-lexicon = "0.12"
[features] [features]
default = ["std"] default = ["std"]

View File

@@ -13,7 +13,7 @@ edition = "2018"
cranelift-module = { path = "../module", version = "0.72.0" } cranelift-module = { path = "../module", version = "0.72.0" }
cranelift-codegen = { path = "../codegen", version = "0.72.0", default-features = false, features = ["std"] } cranelift-codegen = { path = "../codegen", version = "0.72.0", default-features = false, features = ["std"] }
object = { version = "0.23.0", default-features = false, features = ["write"] } object = { version = "0.23.0", default-features = false, features = ["write"] }
target-lexicon = "0.11" target-lexicon = "0.12"
anyhow = "1.0" anyhow = "1.0"
log = { version = "0.4.6", default-features = false } log = { version = "0.4.6", default-features = false }

View File

@@ -12,7 +12,7 @@ edition = "2018"
[dependencies] [dependencies]
cranelift-codegen = { path = "../codegen", version = "0.72.0" } cranelift-codegen = { path = "../codegen", version = "0.72.0" }
smallvec = "1.6.1" smallvec = "1.6.1"
target-lexicon = "0.11" target-lexicon = "0.12"
thiserror = "1.0.15" thiserror = "1.0.15"
[badges] [badges]

View File

@@ -25,7 +25,7 @@ thiserror = "1.0.4"
[dev-dependencies] [dev-dependencies]
wat = "1.0.36" wat = "1.0.36"
target-lexicon = "0.11" target-lexicon = "0.12"
# Enable the riscv feature for cranelift-codegen, as some tests require it # Enable the riscv feature for cranelift-codegen, as some tests require it
cranelift-codegen = { path = "../codegen", version = "0.72.0", default-features = false, features = ["riscv"] } cranelift-codegen = { path = "../codegen", version = "0.72.0", default-features = false, features = ["riscv"] }

View File

@@ -16,7 +16,7 @@ gimli = "0.23.0"
wasmparser = "0.76" wasmparser = "0.76"
object = { version = "0.23.0", default-features = false, features = ["read_core", "elf", "write"] } object = { version = "0.23.0", default-features = false, features = ["read_core", "elf", "write"] }
wasmtime-environ = { path = "../environ", version = "0.25.0" } wasmtime-environ = { path = "../environ", version = "0.25.0" }
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.12.0", default-features = false }
anyhow = "1.0" anyhow = "1.0"
thiserror = "1.0.4" thiserror = "1.0.4"
more-asserts = "0.2.1" more-asserts = "0.2.1"

View File

@@ -27,7 +27,7 @@ wasmtime-obj = { path = "../obj", version = "0.25.0" }
rayon = { version = "1.0", optional = true } rayon = { version = "1.0", optional = true }
region = "2.2.0" region = "2.2.0"
thiserror = "1.0.4" thiserror = "1.0.4"
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.12.0", default-features = false }
wasmparser = "0.76" wasmparser = "0.76"
more-asserts = "0.2.1" more-asserts = "0.2.1"
anyhow = "1.0" anyhow = "1.0"

View File

@@ -15,7 +15,7 @@ anyhow = "1.0"
wasmtime-environ = { path = "../environ", version = "0.25.0" } wasmtime-environ = { path = "../environ", version = "0.25.0" }
object = { version = "0.23.0", default-features = false, features = ["write"] } object = { version = "0.23.0", default-features = false, features = ["write"] }
more-asserts = "0.2.1" more-asserts = "0.2.1"
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.12.0", default-features = false }
wasmtime-debug = { path = "../debug", version = "0.25.0" } wasmtime-debug = { path = "../debug", version = "0.25.0" }
[badges] [badges]

View File

@@ -18,7 +18,7 @@ lazy_static = "1.4"
libc = { version = "0.2.60", default-features = false } libc = { version = "0.2.60", default-features = false }
scroll = { version = "0.10.1", features = ["derive"], optional = true } scroll = { version = "0.10.1", features = ["derive"], optional = true }
serde = { version = "1.0.99", features = ["derive"] } serde = { version = "1.0.99", features = ["derive"] }
target-lexicon = "0.11.0" target-lexicon = "0.12.0"
wasmtime-environ = { path = "../environ", version = "0.25.0" } wasmtime-environ = { path = "../environ", version = "0.25.0" }
wasmtime-runtime = { path = "../runtime", version = "0.25.0" } wasmtime-runtime = { path = "../runtime", version = "0.25.0" }
ittapi-rs = { version = "0.1.5", optional = true } ittapi-rs = { version = "0.1.5", optional = true }

View File

@@ -15,7 +15,7 @@ wasi-common = { path = "../wasi-common", version = "0.25.0" }
wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync", version = "0.25.0" } wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync", version = "0.25.0" }
wasmtime = { path = "../wasmtime", version = "0.25.0" } wasmtime = { path = "../wasmtime", version = "0.25.0" }
wasmtime-wasi = { path = "../wasi", version = "0.25.0" } wasmtime-wasi = { path = "../wasi", version = "0.25.0" }
target-lexicon = "0.11.0" target-lexicon = "0.12.0"
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
tempfile = "3.1.0" tempfile = "3.1.0"
os_pipe = "0.9" os_pipe = "0.9"

View File

@@ -19,7 +19,7 @@ wasmtime-jit = { path = "../jit", version = "0.25.0" }
wasmtime-cache = { path = "../cache", version = "0.25.0", optional = true } wasmtime-cache = { path = "../cache", version = "0.25.0", optional = true }
wasmtime-profiling = { path = "../profiling", version = "0.25.0" } wasmtime-profiling = { path = "../profiling", version = "0.25.0" }
wasmtime-fiber = { path = "../fiber", version = "0.25.0", optional = true } wasmtime-fiber = { path = "../fiber", version = "0.25.0", optional = true }
target-lexicon = { version = "0.11.0", default-features = false } target-lexicon = { version = "0.12.0", default-features = false }
wasmparser = "0.76" wasmparser = "0.76"
anyhow = "1.0.19" anyhow = "1.0.19"
region = "2.2.0" region = "2.2.0"

View File

@@ -13,7 +13,7 @@ cranelift-codegen = { path = "../cranelift/codegen" }
cranelift-reader = { path = "../cranelift/reader" } cranelift-reader = { path = "../cranelift/reader" }
cranelift-wasm = { path = "../cranelift/wasm" } cranelift-wasm = { path = "../cranelift/wasm" }
libfuzzer-sys = "0.4.0" libfuzzer-sys = "0.4.0"
target-lexicon = "0.11" target-lexicon = "0.12"
peepmatic-fuzzing = { path = "../cranelift/peepmatic/crates/fuzzing", optional = true } peepmatic-fuzzing = { path = "../cranelift/peepmatic/crates/fuzzing", optional = true }
wasmtime = { path = "../crates/wasmtime" } wasmtime = { path = "../crates/wasmtime" }
wasmtime-fuzzing = { path = "../crates/fuzzing" } wasmtime-fuzzing = { path = "../crates/fuzzing" }

View File

@@ -121,9 +121,6 @@ fn signatures_match() {
} }
#[test] #[test]
// Note: Cranelift only supports refrerence types (used in the wasm in this
// test) on x64.
#[cfg(target_arch = "x86_64")]
fn import_works() -> Result<()> { fn import_works() -> Result<()> {
static HITS: AtomicUsize = AtomicUsize::new(0); static HITS: AtomicUsize = AtomicUsize::new(0);

View File

@@ -219,9 +219,6 @@ fn signatures_match() -> Result<()> {
} }
#[test] #[test]
// Note: Cranelift only supports refrerence types (used in the wasm in this
// test) on x64.
#[cfg(target_arch = "x86_64")]
fn import_works() -> Result<()> { fn import_works() -> Result<()> {
static HITS: AtomicUsize = AtomicUsize::new(0); static HITS: AtomicUsize = AtomicUsize::new(0);
@@ -328,6 +325,141 @@ fn import_works() -> Result<()> {
Ok(()) Ok(())
} }
#[test]
fn call_import_many_args() -> Result<()> {
let wasm = wat::parse_str(
r#"
(import "" "host" (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)))
(func (export "run")
i32.const 1
i32.const 2
i32.const 3
i32.const 4
i32.const 5
i32.const 6
i32.const 7
i32.const 8
i32.const 9
i32.const 10
call 0
)
"#,
)?;
let mut config = Config::new();
config.wrap_host_func(
"",
"host",
|x1: i32,
x2: i32,
x3: i32,
x4: i32,
x5: i32,
x6: i32,
x7: i32,
x8: i32,
x9: i32,
x10: i32| {
assert_eq!(x1, 1);
assert_eq!(x2, 2);
assert_eq!(x3, 3);
assert_eq!(x4, 4);
assert_eq!(x5, 5);
assert_eq!(x6, 6);
assert_eq!(x7, 7);
assert_eq!(x8, 8);
assert_eq!(x9, 9);
assert_eq!(x10, 10);
},
);
let engine = Engine::new(&config)?;
let module = Module::new(&engine, &wasm)?;
let store = Store::new(&engine);
let instance = Instance::new(
&store,
&module,
&[store
.get_host_func("", "host")
.expect("should be defined")
.into()],
)?;
let run = instance.get_func("run").unwrap();
run.call(&[])?;
Ok(())
}
#[test]
fn call_wasm_many_args() -> Result<()> {
let wasm = wat::parse_str(
r#"
(func (export "run") (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
i32.const 1
get_local 0
i32.ne
if
unreachable
end
i32.const 10
get_local 9
i32.ne
if
unreachable
end
)
(func (export "test")
i32.const 1
i32.const 2
i32.const 3
i32.const 4
i32.const 5
i32.const 6
i32.const 7
i32.const 8
i32.const 9
i32.const 10
call 0
)
"#,
)?;
let config = Config::new();
let engine = Engine::new(&config)?;
let module = Module::new(&engine, &wasm)?;
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let run = instance.get_func("run").unwrap();
run.call(&[
1.into(),
2.into(),
3.into(),
4.into(),
5.into(),
6.into(),
7.into(),
8.into(),
9.into(),
10.into(),
])?;
let typed_run =
instance.get_typed_func::<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), ()>("run")?;
typed_run.call((1, 2, 3, 4, 5, 6, 7, 8, 9, 10))?;
let test = instance.get_func("test").unwrap();
test.call(&[])?;
Ok(())
}
#[test] #[test]
fn trap_smoke() -> Result<()> { fn trap_smoke() -> Result<()> {
let mut config = Config::default(); let mut config = Config::default();