mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-24 14:44:20 +00:00
219 lines
5.5 KiB
Rust
219 lines
5.5 KiB
Rust
use {
|
|
anyhow::{Context, Result},
|
|
wit_component::StringEncoding,
|
|
wit_parser::Resolve,
|
|
};
|
|
|
|
const FOO: &str = r#"
|
|
(module
|
|
(@dylink.0
|
|
(mem-info (memory 4 4))
|
|
(needed "libc.so")
|
|
)
|
|
(type (func))
|
|
(type (func (param i32) (result i32)))
|
|
(import "env" "memory" (memory 1))
|
|
(import "env" "__indirect_function_table" (table 0 funcref))
|
|
(import "env" "__stack_pointer" (global $__stack_pointer (mut i32)))
|
|
(import "env" "__memory_base" (global $__memory_base i32))
|
|
(import "env" "__table_base" (global $__table_base i32))
|
|
(import "env" "malloc" (func $malloc (type 1)))
|
|
(import "env" "abort" (func $abort (type 0)))
|
|
(import "GOT.mem" "um" (global $um (mut i32)))
|
|
(import "test:test/test" "bar" (func $bar (type 1)))
|
|
(func $__wasm_call_ctors (type 0))
|
|
(func $__wasm_apply_data_relocs (type 0))
|
|
(func $foo (type 1) (param i32) (result i32)
|
|
global.get $__stack_pointer
|
|
i32.const 16
|
|
i32.sub
|
|
global.set $__stack_pointer
|
|
|
|
i32.const 4
|
|
call $malloc
|
|
|
|
i32.const 0
|
|
i32.eq
|
|
if
|
|
call $abort
|
|
unreachable
|
|
end
|
|
|
|
local.get 0
|
|
global.get $um
|
|
i32.load offset=16
|
|
i32.add
|
|
i32.const 42
|
|
i32.add
|
|
|
|
call $bar
|
|
|
|
global.get $__stack_pointer
|
|
i32.const 16
|
|
i32.add
|
|
global.set $__stack_pointer
|
|
)
|
|
(global i32 i32.const 0)
|
|
(export "__wasm_call_ctors" (func $__wasm_call_ctors))
|
|
(export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs))
|
|
(export "foo" (func $foo))
|
|
(export "well" (global 4))
|
|
(data $.data (global.get $__memory_base) "\04\00\00\00")
|
|
)
|
|
"#;
|
|
|
|
const BAR: &str = r#"
|
|
(module
|
|
(@dylink.0
|
|
(mem-info (memory 20 4))
|
|
(needed "libfoo.so")
|
|
)
|
|
(type (func (param i32) (result i32)))
|
|
(type (func))
|
|
(import "env" "memory" (memory 1))
|
|
(import "env" "__indirect_function_table" (table 0 funcref))
|
|
(import "env" "__memory_base" (global $__memory_base i32))
|
|
(import "env" "__table_base" (global $__table_base i32))
|
|
(import "env" "foo" (func $foo (type 0)))
|
|
(import "GOT.mem" "well" (global $well (mut i32)))
|
|
(func $__wasm_call_ctors (type 1))
|
|
(func $__wasm_apply_data_relocs (type 1))
|
|
(func $bar (type 0) (param i32) (result i32)
|
|
local.get 0
|
|
call $foo
|
|
global.get $well
|
|
i32.load
|
|
i32.add
|
|
)
|
|
(global i32 i32.const 0)
|
|
(export "__wasm_call_ctors" (func $__wasm_call_ctors))
|
|
(export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs))
|
|
(export "test:test/test#bar" (func $bar))
|
|
(export "um" (global 3))
|
|
(data $.data (global.get $__memory_base) "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00")
|
|
)
|
|
"#;
|
|
|
|
const LIBC: &str = r#"
|
|
(module
|
|
(@dylink.0)
|
|
(type (func))
|
|
(type (func (param i32) (result i32)))
|
|
(import "GOT.mem" "__heap_base" (global $__heap_base (mut i32)))
|
|
(import "GOT.mem" "__heap_end" (global $__heap_end (mut i32)))
|
|
(global $heap (mut i32) i32.const 0)
|
|
(func $start (type 0)
|
|
global.get $__heap_base
|
|
global.set $heap
|
|
)
|
|
(func $malloc (type 1) (param i32) (result i32)
|
|
global.get $heap
|
|
global.get $heap
|
|
local.get 0
|
|
i32.add
|
|
global.set $heap
|
|
)
|
|
(func $abort (type 0)
|
|
unreachable
|
|
)
|
|
(export "malloc" (func $malloc))
|
|
(export "abort" (func $abort))
|
|
(start $start)
|
|
)
|
|
"#;
|
|
|
|
const WIT: &str = r#"
|
|
package test:test;
|
|
|
|
interface test {
|
|
bar: func(v: s32) -> s32;
|
|
}
|
|
|
|
world bar {
|
|
import test;
|
|
export test;
|
|
}
|
|
"#;
|
|
|
|
fn encode(wat: &str, wit: Option<&str>) -> Result<Vec<u8>> {
|
|
let mut module = wat::parse_str(wat)?;
|
|
|
|
if let Some(wit) = wit {
|
|
let mut resolve = Resolve::default();
|
|
let pkg = resolve.push_str("test.wit", wit)?;
|
|
let world = resolve.select_world(pkg, None)?;
|
|
|
|
wit_component::embed_component_metadata(
|
|
&mut module,
|
|
&resolve,
|
|
world,
|
|
StringEncoding::UTF8,
|
|
)?;
|
|
}
|
|
|
|
wasmparser::validate(&module)?;
|
|
|
|
Ok(module)
|
|
}
|
|
|
|
#[test]
|
|
fn linking() -> Result<()> {
|
|
let component = [
|
|
("libfoo.so", FOO, None),
|
|
("libbar.so", BAR, Some(WIT)),
|
|
("libc.so", LIBC, None),
|
|
]
|
|
.into_iter()
|
|
.try_fold(
|
|
wit_component::Linker::default().validate(true),
|
|
|linker, (name, wat, wit)| {
|
|
linker.library(
|
|
name,
|
|
&encode(wat, wit).with_context(|| name.to_owned())?,
|
|
false,
|
|
)
|
|
},
|
|
)?
|
|
.encode()?;
|
|
|
|
#[cfg(target_family = "wasm")]
|
|
{
|
|
_ = component;
|
|
}
|
|
|
|
#[cfg(not(target_family = "wasm"))]
|
|
{
|
|
use {
|
|
anyhow::anyhow,
|
|
wasmtime::{
|
|
component::{Component, Linker},
|
|
Config, Engine, Store,
|
|
},
|
|
};
|
|
|
|
let mut config = Config::new();
|
|
config.wasm_component_model(true);
|
|
|
|
let engine = Engine::new(&config)?;
|
|
let mut linker = Linker::new(&engine);
|
|
linker
|
|
.instance("test:test/test")?
|
|
.func_wrap("bar", |_store, (v,): (i32,)| Ok((v + 7,)))?;
|
|
let mut store = Store::new(&engine, ());
|
|
let instance = linker.instantiate(&mut store, &Component::new(&engine, &component)?)?;
|
|
let func = instance
|
|
.get_export(&mut store, None, "test:test/test")
|
|
.and_then(|i| instance.get_export(&mut store, Some(&i), "bar"))
|
|
.and_then(|f| {
|
|
instance
|
|
.get_typed_func::<(i32,), (i32,)>(&mut store, &f)
|
|
.ok()
|
|
})
|
|
.ok_or_else(|| anyhow!("func `test:test/test/bar` not found"))?;
|
|
|
|
assert_eq!(65, func.call(&mut store, (7,))?.0);
|
|
}
|
|
|
|
Ok(())
|
|
}
|