mirror of
https://github.com/fluencelabs/marine.git
synced 2024-12-12 14:55:32 +00:00
linking
This commit is contained in:
parent
3d5be0e798
commit
9d3d605190
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -806,6 +806,10 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipfs_node"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipfs_rpc"
|
name = "ipfs_rpc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -968,6 +972,15 @@ dependencies = [
|
|||||||
"ws2_32-sys",
|
"ws2_32-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multimap"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8883adfde9756c1d30b0f519c9b8c502a94b41ac62f696453c37c7fc0a958ce"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
@ -2244,6 +2257,7 @@ dependencies = [
|
|||||||
name = "wit_fce"
|
name = "wit_fce"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"multimap",
|
||||||
"wasmer-interface-types",
|
"wasmer-interface-types",
|
||||||
"wasmer-runtime 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasmer-runtime 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasmer-runtime-core 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasmer-runtime-core 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -4,5 +4,6 @@ members = [
|
|||||||
"wit_fce",
|
"wit_fce",
|
||||||
"wit_embedder",
|
"wit_embedder",
|
||||||
"wit_fce/examples/export_test",
|
"wit_fce/examples/export_test",
|
||||||
|
"wit_fce/examples/ipfs_node",
|
||||||
"wit_fce/examples/ipfs_rpc",
|
"wit_fce/examples/ipfs_rpc",
|
||||||
]
|
]
|
||||||
|
@ -6,5 +6,14 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime = "0.17.0"
|
wasmer-runtime = "0.17.0"
|
||||||
wasmer-runtime-core = "0.17.0"
|
wasmer-runtime-core = { version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
|
||||||
wasmer-interface-types = { git = "http://github.com/fluencelabs/interface-types" }
|
wasmer-interface-types = { git = "http://github.com/fluencelabs/interface-types" }
|
||||||
|
multimap = "0.8.1"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
debug = false
|
||||||
|
lto = true
|
||||||
|
debug-assertions = false
|
||||||
|
overflow-checks = false
|
||||||
|
panic = "abort"
|
||||||
|
@ -45,5 +45,5 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
;; Implementations
|
;; Implementations
|
||||||
(@interface implement (func 0) (func 2))
|
(@interface implement (func 2) (func 2))
|
||||||
(@interface implement (func 1) (func 3))
|
(@interface implement (func 3) (func 3))
|
||||||
|
10
wit_fce/examples/ipfs_node/Cargo.toml
Normal file
10
wit_fce/examples/ipfs_node/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "ipfs_node"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Fluence Labs"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "ipfs_node"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
crate-type = ["cdylib"]
|
62
wit_fce/examples/ipfs_node/src/lib.rs
Normal file
62
wit_fce/examples/ipfs_node/src/lib.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mod mem;
|
||||||
|
mod result;
|
||||||
|
|
||||||
|
use crate::result::{RESULT_PTR, RESULT_SIZE};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn put(file_content_ptr: *mut u8, file_content_size: usize) {
|
||||||
|
let file_content = String::from_raw_parts(
|
||||||
|
file_content_ptr,
|
||||||
|
file_content_size,
|
||||||
|
file_content_size
|
||||||
|
);
|
||||||
|
|
||||||
|
let msg = format!("from Wasm node: file content is {}\n", file_content);
|
||||||
|
log_utf8_string(msg.as_ptr() as _, msg.len() as _);
|
||||||
|
|
||||||
|
let cmd = format!("put {}", file_content);
|
||||||
|
ipfs(file_content.as_ptr() as _, file_content.len() as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn get(hash_ptr: *mut u8, hash_size: usize, t: i32) {
|
||||||
|
let hash = String::from_raw_parts(
|
||||||
|
hash_ptr,
|
||||||
|
hash_size,
|
||||||
|
hash_size
|
||||||
|
);
|
||||||
|
|
||||||
|
let msg = format!("from Wasm node: file content is {}\n", hash);
|
||||||
|
log_utf8_string(msg.as_ptr() as _, msg.len() as _);
|
||||||
|
|
||||||
|
let cmd = format!("get {}", hash);
|
||||||
|
ipfs(cmd.as_ptr() as _, cmd.len() as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link(wasm_import_module = "logger")]
|
||||||
|
extern "C" {
|
||||||
|
/// Writes a byte string of size bytes that starts from ptr to a logger.
|
||||||
|
fn log_utf8_string(ptr: i32, size: i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link(wasm_import_module = "host")]
|
||||||
|
extern "C" {
|
||||||
|
/// Put a file to ipfs, returns ipfs hash of the file.
|
||||||
|
fn ipfs(ptr: i32, size: i32);
|
||||||
|
}
|
33
wit_fce/examples/ipfs_node/src/mem.rs
Normal file
33
wit_fce/examples/ipfs_node/src/mem.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
use std::alloc::{alloc as global_alloc, dealloc as global_dealloc, Layout};
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
/// Allocates memory area of specified size and returns its address.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn allocate(size: usize) -> NonNull<u8> {
|
||||||
|
let layout: Layout = Layout::from_size_align(size, std::mem::align_of::<u8>()).unwrap();
|
||||||
|
NonNull::new_unchecked(global_alloc(layout))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deallocates memory area for provided memory pointer and size.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn deallocate(ptr: NonNull<u8>, size: usize) {
|
||||||
|
let layout = Layout::from_size_align(size, std::mem::align_of::<u8>()).unwrap();
|
||||||
|
global_dealloc(ptr.as_ptr(), layout);
|
||||||
|
}
|
41
wit_fce/examples/ipfs_node/src/result.rs
Normal file
41
wit_fce/examples/ipfs_node/src/result.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
use std::sync::atomic::AtomicUsize;
|
||||||
|
|
||||||
|
pub static mut RESULT_PTR: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
pub static mut RESULT_SIZE: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn get_result_ptr() -> usize {
|
||||||
|
*RESULT_PTR.get_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn get_result_size() -> usize {
|
||||||
|
*RESULT_SIZE.get_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn set_result_ptr(ptr: usize) {
|
||||||
|
*RESULT_PTR.get_mut() = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn set_result_size(size: usize) {
|
||||||
|
*RESULT_SIZE.get_mut() = size;
|
||||||
|
}
|
44
wit_fce/examples/ipfs_node/wit
Normal file
44
wit_fce/examples/ipfs_node/wit
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
;; allocate function type
|
||||||
|
(@interface type (func (param i32) (result i32))) ;; 0
|
||||||
|
|
||||||
|
;; deallocate function
|
||||||
|
(@interface type (func (param i32 i32))) ;; 1
|
||||||
|
|
||||||
|
;; invoke function
|
||||||
|
(@interface type (func (param string) (result string))) ;; 2
|
||||||
|
|
||||||
|
;; result extractor functions
|
||||||
|
(@interface type (func (result i32))) ;; 3
|
||||||
|
|
||||||
|
;; result setter functions
|
||||||
|
(@interface type (func (param string))) ;; 4
|
||||||
|
|
||||||
|
;; import ipfs put/get function
|
||||||
|
(@interface type (func (param string) (result string))) ;; 5
|
||||||
|
|
||||||
|
;; import ipfs put/get function
|
||||||
|
(@interface type (func (param string) (result string))) ;; 6
|
||||||
|
|
||||||
|
;; import ipfs put/get function
|
||||||
|
(@interface type (func (param string) (result string))) ;; 7
|
||||||
|
|
||||||
|
(@interface export "allocate" (func 0)) ;; 0
|
||||||
|
(@interface export "deallocate" (func 1)) ;; 1
|
||||||
|
(@interface export "get_result_size" (func 3)) ;; 3
|
||||||
|
(@interface export "get_result_ptr" (func 3)) ;; 4
|
||||||
|
(@interface export "set_result_size" (func 4)) ;; 5
|
||||||
|
(@interface export "set_result_ptr" (func 4)) ;; 6
|
||||||
|
|
||||||
|
(@interface export "put" (func 5)) ;; 8
|
||||||
|
(@interface export "get" (func 5)) ;; 7
|
||||||
|
|
||||||
|
(@interface func (type 6)
|
||||||
|
arg.get 0
|
||||||
|
string.lower_memory
|
||||||
|
call-core 9 ;; call node.get
|
||||||
|
call-core 5 ;; call set_result_size
|
||||||
|
call-core 6 ;; call set_result_ptr
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Implementations
|
||||||
|
(@interface implement (func 5) (func 6))
|
@ -21,14 +21,26 @@ use crate::result::{RESULT_PTR, RESULT_SIZE};
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe fn invoke(file_content_ptr: *mut u8, file_content_size: usize) {
|
pub unsafe fn invoke(file_content_ptr: *mut u8, file_content_size: usize) {
|
||||||
|
let file_content = String::from_raw_parts(
|
||||||
|
file_content_ptr,
|
||||||
|
file_content_size,
|
||||||
|
file_content_size,
|
||||||
|
);
|
||||||
|
let msg = format!("from Wasm rpc: file_content is {}\n", file_content);
|
||||||
|
log_utf8_string(msg.as_ptr() as _, msg.len() as _);
|
||||||
|
|
||||||
put(file_content_ptr as _, file_content_size as _);
|
put(file_content_ptr as _, file_content_size as _);
|
||||||
|
|
||||||
|
/*
|
||||||
let hash = String::from_raw_parts(
|
let hash = String::from_raw_parts(
|
||||||
*RESULT_PTR.get_mut(),
|
*RESULT_PTR.get_mut(),
|
||||||
*RESULT_SIZE.get_mut(),
|
*RESULT_SIZE.get_mut(),
|
||||||
*RESULT_SIZE.get_mut(),
|
*RESULT_SIZE.get_mut(),
|
||||||
);
|
);
|
||||||
|
let msg = format!("from Wasm rpc: hash is {}\n", hash);
|
||||||
|
|
||||||
log_utf8_string(hash.as_ptr() as _, hash.len() as _);
|
log_utf8_string(msg.as_ptr() as _, msg.len() as _);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[link(wasm_import_module = "logger")]
|
#[link(wasm_import_module = "logger")]
|
||||||
|
@ -36,6 +36,6 @@ pub unsafe fn set_result_ptr(ptr: usize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe fn set_result_size(ptr: usize) {
|
pub unsafe fn set_result_size(size: usize) {
|
||||||
*RESULT_SIZE.get_mut() = size;
|
*RESULT_SIZE.get_mut() = size;
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,69 @@
|
|||||||
;; allocate function type
|
;; allocate function type
|
||||||
(@interface type (func (param i32) (result i32)))
|
(@interface type (func (param i32) (result i32))) ;; 0
|
||||||
|
|
||||||
;; deallocate function
|
;; deallocate function
|
||||||
(@interface type (func (param i32 i32)))
|
(@interface type (func (param i32 i32))) ;; 1
|
||||||
|
|
||||||
;; invoke function
|
;; invoke function
|
||||||
(@interface type (func (param string) (result string)))
|
(@interface type (func (param string) (result string))) ;; 2
|
||||||
|
|
||||||
;; result extractor functions
|
;; result extractor functions
|
||||||
(@interface type (func (result i32)))
|
(@interface type (func (result i32))) ;; 3
|
||||||
|
|
||||||
;; result setter functions
|
;; result setter functions
|
||||||
(@interface type (func (param i32)))
|
(@interface type (func (param i32))) ;; 4
|
||||||
|
|
||||||
;; import ipfs put/get function
|
;; import ipfs put/get function
|
||||||
(@interface type (func (param string) (param string)))
|
(@interface type (func (param i32 i32))) ;; 5
|
||||||
|
|
||||||
(@interface export "allocate" (func 0))
|
;; import ipfs put/get function
|
||||||
(@interface export "deallocate" (func 1))
|
(@interface type (func (param string) (result string))) ;; 6
|
||||||
(@interface export "invoke" (func 2))
|
|
||||||
(@interface export "get_result_size" (func 3))
|
|
||||||
(@interface export "get_result_ptr" (func 3))
|
|
||||||
(@interface export "set_result_size" (func 4))
|
|
||||||
(@interface export "set_result_ptr" (func 4))
|
|
||||||
|
|
||||||
(@interface import "node" "get" (func 5))
|
;; import ipfs put/get function
|
||||||
(@interface import "node" "put" (func 5))
|
(@interface type (func (param string) (result string))) ;; 7
|
||||||
|
|
||||||
|
;; import ipfs put/get function
|
||||||
|
(@interface type (func (param i64 i32) (result i64 i32))) ;; 8
|
||||||
|
|
||||||
|
(@interface export "allocate" (func 0)) ;; 0
|
||||||
|
(@interface export "deallocate" (func 1)) ;; 1
|
||||||
|
(@interface export "invoke" (func 2)) ;; 2
|
||||||
|
(@interface export "get_result_size" (func 3)) ;; 3
|
||||||
|
(@interface export "get_result_ptr" (func 3)) ;; 4
|
||||||
|
(@interface export "set_result_size" (func 4)) ;; 5
|
||||||
|
(@interface export "set_result_ptr" (func 4)) ;; 6
|
||||||
|
|
||||||
|
(@interface import "node" "get" (func (type 5)))
|
||||||
|
(@interface import "node" "put" (func (type 5)))
|
||||||
|
|
||||||
|
(@interface import "node" "get" (func (type 7))) ;; 7
|
||||||
|
(@interface import "node" "put" (func (type 8))) ;; 8
|
||||||
|
|
||||||
(@interface func (type 2)
|
(@interface func (type 2)
|
||||||
arg.get 0
|
arg.get 0
|
||||||
string.size
|
string.size
|
||||||
call-core 0 ;; call allocate
|
call-core 0 ;; call allocate
|
||||||
arg.get 0
|
arg.get 0
|
||||||
string.lower_memory
|
string.lower_memory
|
||||||
call-core 2 ;; call greeting
|
call-core 2 ;; call invoke
|
||||||
call-core 3 ;; call get_result_size
|
call-core 3 ;; call get_result_size
|
||||||
call-core 4 ;; call get_result_ptr
|
call-core 4 ;; call get_result_ptr
|
||||||
string.lift_memory
|
string.lift_memory
|
||||||
call-core 3 ;; call get_result_size
|
call-core 3 ;; call get_result_size
|
||||||
call-core 4 ;; call get_result_ptr
|
call-core 4 ;; call get_result_ptr
|
||||||
call-core 1 ;; call deallocate
|
call-core 1 ;; call deallocate
|
||||||
|
)
|
||||||
|
|
||||||
|
(@interface func (type 5)
|
||||||
|
arg.get 0
|
||||||
|
arg.get 1
|
||||||
|
string.lift_memory
|
||||||
|
call-core 7 ;; call node.get that returns string
|
||||||
|
string.lower_memory
|
||||||
|
call-core 5 ;; call set_result_size
|
||||||
|
call-core 6 ;; call set_result_ptr
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Implementations
|
;; Implementations
|
||||||
(@interface implement (func 0) (func 2))
|
(@interface implement (func 2) (func 2))
|
||||||
|
(@interface implement (func 5) (func 5))
|
||||||
|
@ -45,7 +45,7 @@ pub enum WITFCEError {
|
|||||||
NonUniqueModuleName,
|
NonUniqueModuleName,
|
||||||
|
|
||||||
/// Returns when there is no module with such name.
|
/// Returns when there is no module with such name.
|
||||||
NoSuchFunction,
|
NoSuchFunction(String),
|
||||||
|
|
||||||
/// Returns when there is no module with such name.
|
/// Returns when there is no module with such name.
|
||||||
NoSuchModule,
|
NoSuchModule,
|
||||||
@ -79,8 +79,13 @@ impl std::fmt::Display for WITFCEError {
|
|||||||
WITFCEError::PrepareError(msg) => {
|
WITFCEError::PrepareError(msg) => {
|
||||||
write!(f, "Prepare error: {}, probably module is mailformed", msg)
|
write!(f, "Prepare error: {}, probably module is mailformed", msg)
|
||||||
}
|
}
|
||||||
WITFCEError::NonUniqueModuleName => write!(f, "FCE already has module with such name"),
|
WITFCEError::NonUniqueModuleName => {
|
||||||
WITFCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such name"),
|
write!(f, "FCE already has module with such a name")
|
||||||
|
}
|
||||||
|
WITFCEError::NoSuchFunction(msg) => {
|
||||||
|
write!(f, "FCE doesn't have a function with such a name: {}", msg)
|
||||||
|
}
|
||||||
|
WITFCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such a name"),
|
||||||
WITFCEError::ModuleInUse => {
|
WITFCEError::ModuleInUse => {
|
||||||
write!(f, "Module is used by other modules and couldn't be deleted")
|
write!(f, "Module is used by other modules and couldn't be deleted")
|
||||||
}
|
}
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crate::instance::errors::WITFCEError;
|
|
||||||
use wasmer_interface_types::interpreter::wasm;
|
|
||||||
use wasmer_interface_types::{types::InterfaceType, values::InterfaceValue};
|
|
||||||
use wasmer_runtime_core::instance::DynFunc;
|
|
||||||
use wasmer_runtime_core::types::Value;
|
|
||||||
|
|
||||||
pub(crate) struct WITLocalImport {
|
|
||||||
inner: DynFunc<'static>,
|
|
||||||
inputs: Vec<InterfaceType>,
|
|
||||||
outputs: Vec<InterfaceType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WITLocalImport {
|
|
||||||
pub fn new(dyn_func: DynFunc<'static>) -> Result<Self, WITFCEError> {
|
|
||||||
use super::wtype_to_itype;
|
|
||||||
|
|
||||||
let signature = dyn_func.signature();
|
|
||||||
let inputs = signature
|
|
||||||
.params()
|
|
||||||
.iter()
|
|
||||||
.map(wtype_to_itype)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let outputs = signature
|
|
||||||
.returns()
|
|
||||||
.iter()
|
|
||||||
.map(wtype_to_itype)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
inner: dyn_func,
|
|
||||||
inputs,
|
|
||||||
outputs,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for WITLocalImport {
|
|
||||||
type Target = DynFunc<'static>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl wasm::structures::LocalImport for WITLocalImport {
|
|
||||||
fn inputs_cardinality(&self) -> usize {
|
|
||||||
self.inputs.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn outputs_cardinality(&self) -> usize {
|
|
||||||
self.outputs.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inputs(&self) -> &[InterfaceType] {
|
|
||||||
&self.inputs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn outputs(&self) -> &[InterfaceType] {
|
|
||||||
&self.outputs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> {
|
|
||||||
use super::{ival_to_wval, wval_to_ival};
|
|
||||||
|
|
||||||
self.inner
|
|
||||||
.call(&arguments.iter().map(ival_to_wval).collect::<Vec<Value>>())
|
|
||||||
.map(|results| results.iter().map(wval_to_ival).collect())
|
|
||||||
.map_err(|_| ())
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,6 +26,7 @@ impl<'a> std::ops::Deref for WITMemoryView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct WITMemory(pub Memory);
|
pub struct WITMemory(pub Memory);
|
||||||
impl std::ops::Deref for WITMemory {
|
impl std::ops::Deref for WITMemory {
|
||||||
type Target = Memory;
|
type Target = Memory;
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod exports;
|
pub mod exports;
|
||||||
pub mod locals_imports;
|
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
|
pub mod wit_function;
|
||||||
pub mod wit_instance;
|
pub mod wit_instance;
|
||||||
pub mod wit_module;
|
pub mod wit_module;
|
||||||
|
|
||||||
@ -35,6 +35,16 @@ pub fn wtype_to_itype(ty: &WType) -> IType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn itype_to_wtype(ty: &IType) -> WType {
|
||||||
|
match ty {
|
||||||
|
IType::I32 => WType::I32,
|
||||||
|
IType::I64 => WType::I64,
|
||||||
|
IType::F32 => WType::F32,
|
||||||
|
IType::F64 => WType::F64,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ival_to_wval(value: &IValue) -> WValue {
|
pub fn ival_to_wval(value: &IValue) -> WValue {
|
||||||
match value {
|
match value {
|
||||||
IValue::I32(v) => WValue::I32(*v),
|
IValue::I32(v) => WValue::I32(*v),
|
||||||
|
153
wit_fce/src/instance/wit_function.rs
Normal file
153
wit_fce/src/instance/wit_function.rs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::instance::errors::WITFCEError;
|
||||||
|
use crate::instance::wit_module::WITModule;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use wasmer_interface_types::interpreter::wasm;
|
||||||
|
use wasmer_interface_types::{types::InterfaceType, values::InterfaceValue};
|
||||||
|
use wasmer_runtime_core::instance::DynFunc;
|
||||||
|
use wasmer_runtime_core::types::Value;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum WITFunctionInner {
|
||||||
|
Export {
|
||||||
|
func: Arc<DynFunc<'static>>,
|
||||||
|
inputs: Vec<InterfaceType>,
|
||||||
|
outputs: Vec<InterfaceType>,
|
||||||
|
},
|
||||||
|
Import {
|
||||||
|
wit_module: Arc<WITModule>,
|
||||||
|
func_name: String,
|
||||||
|
inputs: Vec<InterfaceType>,
|
||||||
|
outputs: Vec<InterfaceType>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct WITFunction {
|
||||||
|
inner: WITFunctionInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WITFunction {
|
||||||
|
pub fn from_export(dyn_func: DynFunc<'static>) -> Result<Self, WITFCEError> {
|
||||||
|
use super::wtype_to_itype;
|
||||||
|
|
||||||
|
let signature = dyn_func.signature();
|
||||||
|
let inputs = signature
|
||||||
|
.params()
|
||||||
|
.iter()
|
||||||
|
.map(wtype_to_itype)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let outputs = signature
|
||||||
|
.returns()
|
||||||
|
.iter()
|
||||||
|
.map(wtype_to_itype)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let inner = WITFunctionInner::Export {
|
||||||
|
func: Arc::new(dyn_func),
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_import(wit_module: Arc<WITModule>, func_name: String) -> Result<Self, WITFCEError> {
|
||||||
|
let (inputs, outputs) = wit_module.as_ref().get_func_signature(&func_name)?;
|
||||||
|
println!("from_import: {:?}", inputs);
|
||||||
|
|
||||||
|
let inner = WITFunctionInner::Import {
|
||||||
|
wit_module,
|
||||||
|
func_name,
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
impl std::ops::Deref for WITFuncs {
|
||||||
|
type Target = DynFunc<'static>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl wasm::structures::LocalImport for WITFunction {
|
||||||
|
fn inputs_cardinality(&self) -> usize {
|
||||||
|
match &self.inner {
|
||||||
|
WITFunctionInner::Export { ref inputs, .. } => inputs.len(),
|
||||||
|
WITFunctionInner::Import { ref inputs, .. } => inputs.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outputs_cardinality(&self) -> usize {
|
||||||
|
match &self.inner {
|
||||||
|
WITFunctionInner::Export { ref outputs, .. } => outputs.len(),
|
||||||
|
WITFunctionInner::Import { ref outputs, .. } => outputs.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inputs(&self) -> &[InterfaceType] {
|
||||||
|
match &self.inner {
|
||||||
|
WITFunctionInner::Export { ref inputs, .. } => inputs,
|
||||||
|
WITFunctionInner::Import { ref inputs, .. } => inputs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outputs(&self) -> &[InterfaceType] {
|
||||||
|
match &self.inner {
|
||||||
|
WITFunctionInner::Export { ref outputs, .. } => outputs,
|
||||||
|
WITFunctionInner::Import { ref outputs, .. } => outputs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> {
|
||||||
|
use super::{ival_to_wval, wval_to_ival};
|
||||||
|
|
||||||
|
match &self.inner {
|
||||||
|
WITFunctionInner::Export { func, .. } => {
|
||||||
|
println!("calling with {:?}", arguments);
|
||||||
|
func.as_ref()
|
||||||
|
.call(&arguments.iter().map(ival_to_wval).collect::<Vec<Value>>())
|
||||||
|
.map(|results| results.iter().map(wval_to_ival).collect())
|
||||||
|
.map_err(|_| ())
|
||||||
|
}
|
||||||
|
WITFunctionInner::Import {
|
||||||
|
wit_module,
|
||||||
|
func_name,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
println!("calling {} with {:?}", func_name, arguments);
|
||||||
|
let mut tt = wit_module.clone();
|
||||||
|
unsafe {
|
||||||
|
let result = Arc::get_mut_unchecked(&mut tt)
|
||||||
|
.call(func_name, arguments)
|
||||||
|
.map_err(|_| ());
|
||||||
|
|
||||||
|
println!("result is {:?}", result);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,20 +16,26 @@
|
|||||||
|
|
||||||
use crate::instance::errors::WITFCEError;
|
use crate::instance::errors::WITFCEError;
|
||||||
use crate::instance::exports::WITExport;
|
use crate::instance::exports::WITExport;
|
||||||
use crate::instance::locals_imports::WITLocalImport;
|
|
||||||
use crate::instance::memory::{WITMemory, WITMemoryView};
|
use crate::instance::memory::{WITMemory, WITMemoryView};
|
||||||
|
use crate::instance::wit_function::WITFunction;
|
||||||
|
|
||||||
use wasmer_interface_types::interpreter::wasm;
|
use wasmer_interface_types::interpreter::wasm;
|
||||||
use wasmer_runtime_core::Instance as WasmerInstance;
|
use wasmer_runtime_core::Instance as WasmerInstance;
|
||||||
|
|
||||||
|
use crate::instance::wit_module::WITModule;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
use wasmer_interface_types::ast::Interfaces;
|
use wasmer_interface_types::ast::Interfaces;
|
||||||
use wasmer_interface_types::ast::Type;
|
use wasmer_interface_types::ast::Type;
|
||||||
use wasmer_interface_types::interpreter::wasm::structures::{LocalImportIndex, TypedIndex};
|
use wasmer_interface_types::interpreter::wasm::structures::{
|
||||||
|
LocalImport, LocalImportIndex, TypedIndex,
|
||||||
|
};
|
||||||
|
use wasmer_interface_types::types::InterfaceType;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct WITInstance {
|
pub struct WITInstance {
|
||||||
// represent all import and export functions
|
// represent all import and export functions that could be called from WIT context
|
||||||
funcs: HashMap<usize, WITLocalImport>,
|
funcs: HashMap<usize, WITFunction>,
|
||||||
memories: Vec<WITMemory>,
|
memories: Vec<WITMemory>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,17 +43,37 @@ impl WITInstance {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
wasmer_instance: &WasmerInstance,
|
wasmer_instance: &WasmerInstance,
|
||||||
interfaces: &Interfaces,
|
interfaces: &Interfaces,
|
||||||
|
modules: &HashMap<String, Arc<WITModule>>,
|
||||||
) -> Result<Self, WITFCEError> {
|
) -> Result<Self, WITFCEError> {
|
||||||
let funcs = Self::extract_funcs(&wasmer_instance, interfaces)?;
|
let mut exports = Self::extract_exports(&wasmer_instance, interfaces)?;
|
||||||
|
println!("exports count {}", exports.len());
|
||||||
|
let imports = Self::extract_imports(modules, interfaces, exports.len())?;
|
||||||
|
println!("imports count {}", imports.len());
|
||||||
let memories = Self::extract_memories(&wasmer_instance);
|
let memories = Self::extract_memories(&wasmer_instance);
|
||||||
|
|
||||||
|
exports.extend(imports);
|
||||||
|
let funcs = exports;
|
||||||
|
|
||||||
Ok(Self { funcs, memories })
|
Ok(Self { funcs, memories })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_funcs(
|
pub fn get_func_signature(
|
||||||
|
&self,
|
||||||
|
func_idx: usize,
|
||||||
|
) -> Result<(Vec<InterfaceType>, Vec<InterfaceType>), WITFCEError> {
|
||||||
|
match self.funcs.get(&func_idx) {
|
||||||
|
Some(func) => Ok((func.inputs().to_owned(), func.outputs().to_owned())),
|
||||||
|
None => Err(WITFCEError::NoSuchFunction(format!(
|
||||||
|
"function with idx = {} hasn't been found during its signature looking up",
|
||||||
|
func_idx
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_exports(
|
||||||
wasmer_instance: &WasmerInstance,
|
wasmer_instance: &WasmerInstance,
|
||||||
interfaces: &Interfaces,
|
interfaces: &Interfaces,
|
||||||
) -> Result<HashMap<usize, WITLocalImport>, WITFCEError> {
|
) -> Result<HashMap<usize, WITFunction>, WITFCEError> {
|
||||||
use wasmer_runtime_core::DynFunc;
|
use wasmer_runtime_core::DynFunc;
|
||||||
let module_exports = &wasmer_instance.exports;
|
let module_exports = &wasmer_instance.exports;
|
||||||
|
|
||||||
@ -62,12 +88,58 @@ impl WITInstance {
|
|||||||
// here it is safe because dyn func is never lives WITInstance
|
// here it is safe because dyn func is never lives WITInstance
|
||||||
let export_func =
|
let export_func =
|
||||||
std::mem::transmute::<DynFunc<'_>, DynFunc<'static>>(export_func);
|
std::mem::transmute::<DynFunc<'_>, DynFunc<'static>>(export_func);
|
||||||
Ok((export_id, WITLocalImport::new(export_func)?))
|
let tt = WITFunction::from_export(export_func)?;
|
||||||
|
println!(
|
||||||
|
"{}, {} - {:?}",
|
||||||
|
export_id,
|
||||||
|
export.name,
|
||||||
|
tt.inputs()
|
||||||
|
);
|
||||||
|
Ok((export_id, tt))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts only those imports that don't have implementations.
|
||||||
|
fn extract_imports(
|
||||||
|
modules: &HashMap<String, Arc<WITModule>>,
|
||||||
|
interfaces: &Interfaces,
|
||||||
|
start_index: usize,
|
||||||
|
) -> Result<HashMap<usize, WITFunction>, WITFCEError> {
|
||||||
|
// uses to filter import functions that have an adapter implementation
|
||||||
|
let core_to_adapter = interfaces
|
||||||
|
.implementations
|
||||||
|
.iter()
|
||||||
|
.map(|i| (i.core_function_type, i.adapter_function_type))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
let mut non_wit_callable_imports = HashMap::new();
|
||||||
|
|
||||||
|
for import in interfaces.imports.iter() {
|
||||||
|
if let Some(_) = core_to_adapter.get(&import.function_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match modules.get(import.namespace) {
|
||||||
|
Some(module) => {
|
||||||
|
let func = WITFunction::from_import(module.clone(), import.name.to_string())?;
|
||||||
|
println!(
|
||||||
|
"{}, {} - {:?}",
|
||||||
|
start_index + non_wit_callable_imports.len(),
|
||||||
|
import.name,
|
||||||
|
func.inputs()
|
||||||
|
);
|
||||||
|
non_wit_callable_imports
|
||||||
|
.insert(start_index + non_wit_callable_imports.len() as usize, func);
|
||||||
|
}
|
||||||
|
None => return Err(WITFCEError::NoSuchModule),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(non_wit_callable_imports)
|
||||||
|
}
|
||||||
|
|
||||||
fn extract_memories(wasmer_instance: &WasmerInstance) -> Vec<WITMemory> {
|
fn extract_memories(wasmer_instance: &WasmerInstance) -> Vec<WITMemory> {
|
||||||
use wasmer_runtime_core::export::Export::Memory;
|
use wasmer_runtime_core::export::Export::Memory;
|
||||||
|
|
||||||
@ -90,7 +162,7 @@ impl WITInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'instance> wasm::structures::Instance<WITExport, WITLocalImport, WITMemory, WITMemoryView<'_>>
|
impl<'instance> wasm::structures::Instance<WITExport, WITFunction, WITMemory, WITMemoryView<'_>>
|
||||||
for WITInstance
|
for WITInstance
|
||||||
{
|
{
|
||||||
fn export(&self, _export_name: &str) -> Option<&WITExport> {
|
fn export(&self, _export_name: &str) -> Option<&WITExport> {
|
||||||
@ -101,7 +173,7 @@ impl<'instance> wasm::structures::Instance<WITExport, WITLocalImport, WITMemory,
|
|||||||
fn local_or_import<I: TypedIndex + LocalImportIndex>(
|
fn local_or_import<I: TypedIndex + LocalImportIndex>(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: I,
|
index: I,
|
||||||
) -> Option<&WITLocalImport> {
|
) -> Option<&WITFunction> {
|
||||||
self.funcs.get(&index.index())
|
self.funcs.get(&index.index())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,41 +16,47 @@
|
|||||||
|
|
||||||
use crate::instance::errors::WITFCEError;
|
use crate::instance::errors::WITFCEError;
|
||||||
use crate::instance::exports::WITExport;
|
use crate::instance::exports::WITExport;
|
||||||
use crate::instance::locals_imports::WITLocalImport;
|
|
||||||
use crate::instance::memory::{WITMemory, WITMemoryView};
|
use crate::instance::memory::{WITMemory, WITMemoryView};
|
||||||
|
use crate::instance::wit_function::WITFunction;
|
||||||
use crate::instance::wit_instance::WITInstance;
|
use crate::instance::wit_instance::WITInstance;
|
||||||
|
|
||||||
use wasmer_interface_types as wit;
|
use wasmer_interface_types as wit;
|
||||||
|
use wasmer_interface_types::ast::Interfaces;
|
||||||
use wasmer_interface_types::interpreter::Interpreter;
|
use wasmer_interface_types::interpreter::Interpreter;
|
||||||
use wasmer_interface_types::values::InterfaceValue;
|
use wasmer_interface_types::values::InterfaceValue;
|
||||||
use wasmer_runtime::{compile, ImportObject};
|
use wasmer_runtime::{compile, ImportObject};
|
||||||
use wasmer_runtime_core::Instance as WasmerInstance;
|
use wasmer_runtime_core::Instance as WasmerInstance;
|
||||||
|
|
||||||
|
use multimap::MultiMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
use std::sync::Arc;
|
||||||
use wasmer_interface_types::interpreter::stack::Stackable;
|
use wasmer_interface_types::interpreter::stack::Stackable;
|
||||||
|
use wasmer_interface_types::types::InterfaceType;
|
||||||
|
use wasmer_runtime_core::import::Namespace;
|
||||||
|
|
||||||
const WIT_SECTION_NAME: &str = "interface-types";
|
const WIT_SECTION_NAME: &str = "interface-types";
|
||||||
|
type WITInterpreter =
|
||||||
|
Interpreter<WITInstance, WITExport, WITFunction, WITMemory, WITMemoryView<'static>>;
|
||||||
|
|
||||||
pub struct WITModule {
|
pub struct WITModule {
|
||||||
instance: WasmerInstance,
|
instance: WasmerInstance,
|
||||||
wit_instance: WITInstance,
|
wit_instance: Arc<WITInstance>,
|
||||||
exports: HashMap<
|
func_name_to_idx: HashMap<String, usize>,
|
||||||
String,
|
funcs: HashMap<String, WITInterpreter>,
|
||||||
Interpreter<WITInstance, WITExport, WITLocalImport, WITMemory, WITMemoryView<'static>>,
|
|
||||||
>,
|
|
||||||
import_object: ImportObject,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WITModule {
|
impl WITModule {
|
||||||
pub fn new(wasm_bytes: &[u8], imports: &ImportObject) -> Result<Self, WITFCEError> {
|
pub fn new(
|
||||||
let wasmer_instance = compile(&wasm_bytes)?.instantiate(imports)?;
|
wasm_bytes: &[u8],
|
||||||
|
imports: ImportObject,
|
||||||
|
modules: &HashMap<String, Arc<WITModule>>,
|
||||||
|
) -> Result<Self, WITFCEError> {
|
||||||
|
let wasmer_instance = compile(&wasm_bytes)?;
|
||||||
|
|
||||||
let wit_sections = wasmer_instance
|
let wit_sections = wasmer_instance
|
||||||
.module
|
.custom_sections(WIT_SECTION_NAME)
|
||||||
.info
|
|
||||||
.custom_sections
|
|
||||||
.get(WIT_SECTION_NAME)
|
|
||||||
.ok_or_else(|| WITFCEError::NoWITSection)?;
|
.ok_or_else(|| WITFCEError::NoWITSection)?;
|
||||||
|
|
||||||
if wit_sections.len() > 1 {
|
if wit_sections.len() > 1 {
|
||||||
@ -63,61 +69,25 @@ impl WITModule {
|
|||||||
return Err(WITFCEError::WITRemainderNotEmpty);
|
return Err(WITFCEError::WITRemainderNotEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
let wit_instance = WITInstance::new(&wasmer_instance, &interfaces)?;
|
let mut wit_instance = Arc::new_uninit();
|
||||||
|
|
||||||
let wit_export_names = interfaces
|
let callable_exports = Self::extract_exports(&interfaces)?;
|
||||||
.imports
|
let mut import_object = Self::adjust_imports(&interfaces, wit_instance.clone())?;
|
||||||
.iter()
|
import_object.extend(imports);
|
||||||
.map(|export| (export.function_type, export.name.to_string()))
|
|
||||||
.collect::<HashMap<u32, String>>();
|
|
||||||
|
|
||||||
let callable_exports = interfaces
|
let wasmer_instance = wasmer_instance.instantiate(&import_object)?;
|
||||||
.adapters
|
|
||||||
.iter()
|
|
||||||
.map(|adapter| {
|
|
||||||
let export_func_name = wit_export_names
|
|
||||||
.get(&adapter.function_type)
|
|
||||||
.ok_or_else(|| WITFCEError::NoSuchFunction)?;
|
|
||||||
let instructions = &adapter.instructions;
|
|
||||||
|
|
||||||
let interpreter: Interpreter<
|
let wit_instance = unsafe {
|
||||||
WITInstance,
|
*Arc::get_mut_unchecked(&mut wit_instance) =
|
||||||
WITExport,
|
MaybeUninit::new(WITInstance::new(&wasmer_instance, &interfaces, modules)?);
|
||||||
WITLocalImport,
|
std::mem::transmute::<_, Arc<WITInstance>>(wit_instance)
|
||||||
WITMemory,
|
};
|
||||||
WITMemoryView<'static>,
|
|
||||||
> = instructions.try_into().unwrap();
|
|
||||||
|
|
||||||
Ok((export_func_name.to_owned(), interpreter))
|
|
||||||
})
|
|
||||||
.collect::<Result<HashMap<_, _>, WITFCEError>>()?;
|
|
||||||
|
|
||||||
|
|
||||||
let callable_imports = interfaces
|
|
||||||
.adapters
|
|
||||||
.iter()
|
|
||||||
.map(|adapter| {
|
|
||||||
let import_func_name = wit_export_names
|
|
||||||
.get(&adapter.function_type)
|
|
||||||
.ok_or_else(|| WITFCEError::NoSuchFunction)?;
|
|
||||||
let instructions = &adapter.instructions;
|
|
||||||
|
|
||||||
let interpreter: Interpreter<
|
|
||||||
WITInstance,
|
|
||||||
WITExport,
|
|
||||||
WITLocalImport,
|
|
||||||
WITMemory,
|
|
||||||
WITMemoryView<'static>,
|
|
||||||
> = instructions.try_into().unwrap();
|
|
||||||
|
|
||||||
Ok((export_func_name.to_owned(), interpreter))
|
|
||||||
})
|
|
||||||
.collect::<Result<HashMap<_, _>, WITFCEError>>()?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
instance: wasmer_instance,
|
instance: wasmer_instance,
|
||||||
wit_instance,
|
wit_instance,
|
||||||
exports: callable_exports,
|
func_name_to_idx: HashMap::new(),
|
||||||
|
funcs: callable_exports,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,15 +96,184 @@ impl WITModule {
|
|||||||
function_name: &str,
|
function_name: &str,
|
||||||
args: &[InterfaceValue],
|
args: &[InterfaceValue],
|
||||||
) -> Result<Vec<InterfaceValue>, WITFCEError> {
|
) -> Result<Vec<InterfaceValue>, WITFCEError> {
|
||||||
match self.exports.get(function_name) {
|
println!("here, func name is {}, args = {:?}", function_name, args);
|
||||||
|
match self.funcs.get(function_name) {
|
||||||
Some(func) => {
|
Some(func) => {
|
||||||
let result = func
|
let tt = Arc::make_mut(&mut self.wit_instance);
|
||||||
.run(args, &mut self.wit_instance)?
|
|
||||||
.as_slice()
|
let result = func.run(args, tt)?.as_slice().to_owned();
|
||||||
.to_owned();
|
println!("here {:?}", result);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
None => Err(WITFCEError::NoSuchFunction),
|
None => {
|
||||||
|
println!("no func");
|
||||||
|
Err(WITFCEError::NoSuchFunction(format!(
|
||||||
|
"{} hasn't been found while calling",
|
||||||
|
function_name
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_func_signature(
|
||||||
|
&self,
|
||||||
|
function_name: &str,
|
||||||
|
) -> Result<(Vec<InterfaceType>, Vec<InterfaceType>), WITFCEError> {
|
||||||
|
match self.func_name_to_idx.get(function_name) {
|
||||||
|
Some(func_idx) => {
|
||||||
|
println!("func_idx: {}", func_idx);
|
||||||
|
self.wit_instance.as_ref().get_func_signature(*func_idx)
|
||||||
|
},
|
||||||
|
None => Err(WITFCEError::NoSuchFunction(format!(
|
||||||
|
"{} has't been found during its signature looking up",
|
||||||
|
function_name
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_exports(
|
||||||
|
interfaces: &Interfaces,
|
||||||
|
) -> Result<HashMap<String, WITInterpreter>, WITFCEError> {
|
||||||
|
let exports_type_to_names = interfaces
|
||||||
|
.exports
|
||||||
|
.iter()
|
||||||
|
.map(|export| (export.function_type, export.name.to_string()))
|
||||||
|
.collect::<MultiMap<_, _>>();
|
||||||
|
|
||||||
|
let adapter_type_to_instructions = interfaces
|
||||||
|
.adapters
|
||||||
|
.iter()
|
||||||
|
.map(|adapter| (adapter.function_type, &adapter.instructions))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
let mut wit_callable_exports = HashMap::new();
|
||||||
|
for i in interfaces.implementations.iter() {
|
||||||
|
let export_function_names = match exports_type_to_names.get_vec(&i.core_function_type) {
|
||||||
|
Some(export_function_names) => export_function_names,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
// * just to remove reference
|
||||||
|
let adapter_instructions = *adapter_type_to_instructions
|
||||||
|
.get(&i.adapter_function_type)
|
||||||
|
.ok_or_else(|| WITFCEError::NoSuchFunction(
|
||||||
|
format!("adapter function with idx = {} hasn't been found during extracting exports by implementations", i.adapter_function_type)
|
||||||
|
))?;
|
||||||
|
|
||||||
|
for export_function_name in export_function_names.iter() {
|
||||||
|
println!("export func name {}", export_function_name);
|
||||||
|
|
||||||
|
// TODO: handle errors
|
||||||
|
let interpreter: WITInterpreter = adapter_instructions.try_into().unwrap();
|
||||||
|
wit_callable_exports.insert(export_function_name.to_owned(), interpreter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(wit_callable_exports)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function deals only with import functions that have an adaptor implementation
|
||||||
|
fn adjust_imports(
|
||||||
|
interfaces: &Interfaces,
|
||||||
|
wit_instance: Arc<MaybeUninit<WITInstance>>,
|
||||||
|
) -> Result<ImportObject, WITFCEError> {
|
||||||
|
use crate::instance::{itype_to_wtype, wval_to_ival};
|
||||||
|
use wasmer_interface_types::ast::Type as IType;
|
||||||
|
use wasmer_runtime_core::typed_func::DynamicFunc;
|
||||||
|
use wasmer_runtime_core::types::{FuncSig, Type as WType, Value};
|
||||||
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
|
// returns function that will be called from imports of Wasmer module
|
||||||
|
fn dyn_func_from_imports<F>(inputs: Vec<InterfaceType>, func: F) -> DynamicFunc<'static>
|
||||||
|
where
|
||||||
|
F: Fn(&mut Ctx, &[Value]) -> Vec<Value> + 'static,
|
||||||
|
{
|
||||||
|
let signature = inputs.iter().map(itype_to_wtype).collect::<Vec<_>>();
|
||||||
|
DynamicFunc::new(Arc::new(FuncSig::new(signature, vec![])), func)
|
||||||
|
}
|
||||||
|
|
||||||
|
// uses to filter out import functions that have an adapter implementation
|
||||||
|
let adapter_to_core = interfaces
|
||||||
|
.implementations
|
||||||
|
.iter()
|
||||||
|
.map(|i| (i.adapter_function_type, i.core_function_type))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
// all wit imports
|
||||||
|
let mut export_type_to_name = interfaces
|
||||||
|
.imports
|
||||||
|
.iter()
|
||||||
|
.map(|import| {
|
||||||
|
(
|
||||||
|
import.function_type,
|
||||||
|
(import.namespace.to_string(), import.name.to_string()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
let mut import_namespaces: HashMap<String, Namespace> = HashMap::new();
|
||||||
|
|
||||||
|
for adapter in interfaces.adapters.iter() {
|
||||||
|
let core_function_idx = adapter_to_core
|
||||||
|
.get(&adapter.function_type)
|
||||||
|
.ok_or_else(|| WITFCEError::NoSuchFunction(format!("function with idx = {} hasn't been found during adjusting imports in WIT implementation", adapter.function_type)))?;
|
||||||
|
|
||||||
|
let (namespace, func_name) = match export_type_to_name.remove(core_function_idx) {
|
||||||
|
Some(v) => (v.0, v.1),
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if adapter.function_type >= interfaces.types.len() as u32 {
|
||||||
|
// TODO: change error type
|
||||||
|
return Err(WITFCEError::NoSuchFunction(format!(
|
||||||
|
"{} function id is bigger than WIT interface types count",
|
||||||
|
adapter.function_type
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let IType::Function { inputs, .. } =
|
||||||
|
&interfaces.types[adapter.function_type as usize]
|
||||||
|
{
|
||||||
|
let instructions = &adapter.instructions;
|
||||||
|
let interpreter: WITInterpreter = instructions.try_into().unwrap();
|
||||||
|
|
||||||
|
let wit_instance = wit_instance.clone();
|
||||||
|
let inner_import = Box::new(move |_: &mut Ctx, inputs: &[Value]| -> Vec<Value> {
|
||||||
|
println!("calling from import with {:?}", inputs);
|
||||||
|
|
||||||
|
let tt = wit_instance.clone();
|
||||||
|
let converted_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>();
|
||||||
|
//let mut wit_instance_copy = Arc::make_mut(tt).unwrap();
|
||||||
|
unsafe {
|
||||||
|
let r = interpreter
|
||||||
|
.run(&converted_inputs, Arc::make_mut(&mut tt.assume_init()));
|
||||||
|
println!("import interpreter result is {:?}", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec![]
|
||||||
|
});
|
||||||
|
|
||||||
|
let linking_import = dyn_func_from_imports(inputs.clone(), inner_import);
|
||||||
|
|
||||||
|
let mut n = Namespace::new();
|
||||||
|
n.insert(func_name.clone(), linking_import);
|
||||||
|
|
||||||
|
import_namespaces.insert(namespace, n);
|
||||||
|
} else {
|
||||||
|
// TODO: change error type
|
||||||
|
return Err(WITFCEError::WasmerResolveError(format!(
|
||||||
|
"WIT type with idx = {} doesn't refer to function",
|
||||||
|
adapter.function_type
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut import_object = ImportObject::new();
|
||||||
|
|
||||||
|
for (namespace_name, namespace) in import_namespaces.into_iter() {
|
||||||
|
import_object.register(namespace_name, namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(import_object)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,40 +13,54 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
#![feature(get_mut_unchecked)]
|
||||||
|
#![feature(new_uninit)]
|
||||||
|
|
||||||
mod instance;
|
mod instance;
|
||||||
|
|
||||||
use crate::instance::wit_module::WITModule;
|
use crate::instance::wit_module::WITModule;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
use wasmer_interface_types::values::InterfaceValue;
|
use wasmer_interface_types::values::InterfaceValue;
|
||||||
use wasmer_runtime::{func, imports, ImportObject};
|
use wasmer_runtime::{func, imports, ImportObject};
|
||||||
use wasmer_runtime_core::vm::Ctx;
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
const FILE_NAME: &str =
|
const IPFS_NODE: &str =
|
||||||
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/export_test_wit.wasm";
|
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_node_wit.wasm";
|
||||||
|
|
||||||
|
const IPFS_RPC: &str =
|
||||||
|
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_rpc_wit.wasm";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let wasm_bytes = std::fs::read(FILE_NAME).unwrap();
|
let ipfs_node_bytes = std::fs::read(IPFS_NODE).unwrap();
|
||||||
let logger_imports = imports! {
|
let ipfs_rpc_bytes = std::fs::read(IPFS_RPC).unwrap();
|
||||||
|
let imports = imports! {
|
||||||
"logger" => {
|
"logger" => {
|
||||||
"log_utf8_string" => func!(logger_log_utf8_string),
|
"log_utf8_string" => func!(logger_log_utf8_string),
|
||||||
},
|
},
|
||||||
|
"host" => {
|
||||||
|
"ipfs" => func!(ipfs_call),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let mut import_object = ImportObject::new();
|
let mut import_object = ImportObject::new();
|
||||||
import_object.extend(logger_imports);
|
import_object.extend(imports);
|
||||||
|
let mut modules = HashMap::new();
|
||||||
|
|
||||||
let mut module =
|
println!("loading ipfs node module");
|
||||||
WITModule::new(&wasm_bytes, &import_object).expect("module successfully created");
|
let ipfs_node = WITModule::new(&ipfs_node_bytes, import_object.clone(), &modules)
|
||||||
|
.expect("module successfully created");
|
||||||
|
modules.insert("node".to_string(), Arc::new(ipfs_node));
|
||||||
|
|
||||||
let result1 = module
|
println!("loading ipfs rpc module");
|
||||||
.call("strlen", &[InterfaceValue::String("aaaaaa".to_string())])
|
let mut ipfs_rpc = WITModule::new(&ipfs_rpc_bytes, import_object, &modules)
|
||||||
.unwrap();
|
.expect("module successfully created");
|
||||||
let result2 = module
|
|
||||||
.call("greeting", &[InterfaceValue::String("Mike".to_string())])
|
let result1 = ipfs_rpc
|
||||||
|
.call("invoke", &[InterfaceValue::String("aaaaaa".to_string())])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
println!("stack state {:?}", result1);
|
println!("stack state {:?}", result1);
|
||||||
println!("stack state {:?}", result2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
|
fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
|
||||||
@ -58,3 +72,13 @@ fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
|
|||||||
None => print!("fce logger: incorrect UTF8 string's been supplied to logger"),
|
None => print!("fce logger: incorrect UTF8 string's been supplied to logger"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ipfs_call(ctx: &mut Ctx, ptr: i32, size: i32) {
|
||||||
|
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
|
||||||
|
|
||||||
|
let wasm_ptr = WasmPtr::<u8, Array>::new(ptr as _);
|
||||||
|
match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) {
|
||||||
|
Some(msg) => print!("ipfs_call {}", msg),
|
||||||
|
None => print!("fce logger: incorrect UTF8 string's been supplied to logger"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
26
wit_fce/src/wit_fce.rs
Normal file
26
wit_fce/src/wit_fce.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::instance::wit_module::WITModule;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use wasmer_interface_types::values::InterfaceValue;
|
||||||
|
use wasmer_runtime::{func, imports, ImportObject};
|
||||||
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
|
pub struct WITFCE {
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user