mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-03 14:50:21 +00:00
feat!: move to async execution (#44)
* compiling async interpreter * compiling * fix after merge * added lifetimes to allocatable * move from async_trait to BoxFuture * self-review fixes * fix lifetime naming * make simple instructions sync * fmt
This commit is contained in:
parent
2a2288f2c1
commit
63b4395ab5
160
Cargo.lock
generated
160
Cargo.lock
generated
@ -8,6 +8,23 @@ version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@ -31,12 +48,103 @@ dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "it-lilo"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
"fluence-it-types",
|
||||
"futures",
|
||||
"it-memory-traits",
|
||||
"log",
|
||||
"paste",
|
||||
@ -108,24 +216,36 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.11"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
||||
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.49"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@ -165,7 +285,7 @@ checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -179,6 +299,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
@ -190,6 +319,17 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.38"
|
||||
@ -207,7 +347,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -223,7 +363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aae2faf80ac463422992abf4de234731279c058aaf33171ca70277c98406b124"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -232,12 +372,14 @@ version = "0.27.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"fluence-it-types",
|
||||
"futures",
|
||||
"it-lilo",
|
||||
"it-memory-traits",
|
||||
"it-to-bytes",
|
||||
"itertools",
|
||||
"log",
|
||||
"nom",
|
||||
"paste",
|
||||
"safe-transmute",
|
||||
"semver",
|
||||
"serde",
|
||||
|
@ -11,10 +11,12 @@ name = "it_lilo"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
fluence-it-types = { path = "../it-types/", version = "0.4.1" }
|
||||
fluence-it-types = { path = "../it-types", version = "0.4.1" }
|
||||
it-memory-traits = { path = "../it-memory-traits", version = "0.4.0" }
|
||||
|
||||
anyhow = "1.0.75"
|
||||
paste = "1.0.11"
|
||||
thiserror = "1.0.38"
|
||||
log = "0.4.17"
|
||||
async-recursion = "1.0.5"
|
||||
futures = "0.3.29"
|
||||
|
@ -41,9 +41,6 @@ impl<'r, R: RecordResolvable, MV: MemoryView<Store>, Store: it_memory_traits::St
|
||||
{
|
||||
pub fn new(view: MV, resolver: &'r R) -> Self {
|
||||
let reader = MemoryReader::new(view);
|
||||
Self {
|
||||
reader,
|
||||
resolver,
|
||||
}
|
||||
Self { reader, resolver }
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ impl LoweredArray {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_lower_memory<
|
||||
#[async_recursion::async_recursion]
|
||||
pub async fn array_lower_memory<
|
||||
A: Allocatable<MV, Store>,
|
||||
MV: MemoryView<Store>,
|
||||
Store: it_memory_traits::Store,
|
||||
@ -54,32 +55,57 @@ pub fn array_lower_memory<
|
||||
let elements_count = array_values.len() as u32;
|
||||
let size = ser_value_size(&array_values[0]) * elements_count;
|
||||
let type_tag = type_tag_form_ivalue(&array_values[0]);
|
||||
let seq_writer = lowerer.writer.sequential_writer(store, size, type_tag)?;
|
||||
let seq_writer = lowerer
|
||||
.writer
|
||||
.sequential_writer(store, size, type_tag)
|
||||
.await?;
|
||||
|
||||
// here it's known that all interface values have the same type
|
||||
for value in array_values {
|
||||
match value {
|
||||
IValue::Boolean(value) => seq_writer.write_u8(store, &lowerer.writer, value as _),
|
||||
IValue::S8(value) => seq_writer.write_u8(store, &lowerer.writer, value as _),
|
||||
IValue::S16(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::S32(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::S64(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::U8(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::U16(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::U32(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::U64(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::I32(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::I64(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::F32(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::F64(value) => seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes()),
|
||||
IValue::S16(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::S32(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::S64(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::U8(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::U16(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::U32(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::U64(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::I32(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::I64(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::F32(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::F64(value) => {
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &value.to_le_bytes())
|
||||
}
|
||||
IValue::String(value) => {
|
||||
let offset = lowerer.writer.write_bytes(store, &value.as_bytes())? as u32;
|
||||
let offset = lowerer.writer.write_bytes(store, &value.as_bytes()).await? as u32;
|
||||
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &offset.to_le_bytes());
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &(value.len() as u32).to_le_bytes());
|
||||
}
|
||||
IValue::ByteArray(values) => {
|
||||
let offset = lowerer.writer.write_bytes(store, &values)? as u32;
|
||||
let offset = lowerer.writer.write_bytes(store, &values).await? as u32;
|
||||
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &offset.to_le_bytes());
|
||||
seq_writer.write_bytes(
|
||||
@ -89,13 +115,14 @@ pub fn array_lower_memory<
|
||||
);
|
||||
}
|
||||
IValue::Array(values) => {
|
||||
let LoweredArray { offset, size } = array_lower_memory(store, lowerer, values)?;
|
||||
let LoweredArray { offset, size } =
|
||||
array_lower_memory(store, lowerer, values).await?;
|
||||
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &(offset as u32).to_le_bytes());
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &(size as u32).to_le_bytes());
|
||||
}
|
||||
IValue::Record(values) => {
|
||||
let offset = super::record_lower_memory(store, lowerer, values)? as u32;
|
||||
let offset = super::record_lower_memory(store, lowerer, values).await? as u32;
|
||||
seq_writer.write_bytes(store, &lowerer.writer, &offset.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ use crate::NEVec;
|
||||
|
||||
use it_memory_traits::MemoryView;
|
||||
|
||||
pub fn record_lower_memory<
|
||||
#[async_recursion::async_recursion]
|
||||
pub async fn record_lower_memory<
|
||||
A: Allocatable<MV, Store>,
|
||||
MV: MemoryView<Store>,
|
||||
Store: it_memory_traits::Store,
|
||||
@ -52,13 +53,13 @@ pub fn record_lower_memory<
|
||||
IValue::F32(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::F64(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::String(value) => {
|
||||
let offset = lowerer.writer.write_bytes(store, value.as_bytes())?;
|
||||
let offset = lowerer.writer.write_bytes(store, value.as_bytes()).await?;
|
||||
|
||||
result.extend_from_slice(&offset.to_le_bytes());
|
||||
result.extend_from_slice(&(value.len() as u32).to_le_bytes());
|
||||
}
|
||||
IValue::ByteArray(value) => {
|
||||
let offset = lowerer.writer.write_bytes(store, &value)?;
|
||||
let offset = lowerer.writer.write_bytes(store, &value).await?;
|
||||
|
||||
result.extend_from_slice(&offset.to_le_bytes());
|
||||
result.extend_from_slice(&(value.len() as u32).to_le_bytes());
|
||||
@ -66,21 +67,21 @@ pub fn record_lower_memory<
|
||||
|
||||
IValue::Array(values) => {
|
||||
let LoweredArray { offset, size } =
|
||||
super::array_lower_memory(store, lowerer, values)?;
|
||||
super::array_lower_memory(store, lowerer, values).await?;
|
||||
|
||||
result.extend_from_slice(&(offset).to_le_bytes());
|
||||
result.extend_from_slice(&(size).to_le_bytes());
|
||||
}
|
||||
|
||||
IValue::Record(values) => {
|
||||
let offset = record_lower_memory(store, lowerer, values)?;
|
||||
let offset = record_lower_memory(store, lowerer, values).await?;
|
||||
|
||||
result.extend_from_slice(&offset.to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result_pointer = lowerer.writer.write_bytes(store, &result)?;
|
||||
let result_pointer = lowerer.writer.write_bytes(store, &result).await?;
|
||||
|
||||
Ok(result_pointer)
|
||||
}
|
||||
|
@ -46,25 +46,27 @@ impl<'i, A: Allocatable<MV, Store>, MV: MemoryView<Store>, Store: it_memory_trai
|
||||
Ok(writer)
|
||||
}
|
||||
|
||||
pub fn write_bytes(
|
||||
pub async fn write_bytes<'store, 'store_inner: 'store>(
|
||||
&mut self,
|
||||
store: &mut <Store as it_memory_traits::Store>::ActualStore<'_>,
|
||||
store: &'store mut <Store as it_memory_traits::Store>::ActualStore<'store_inner>,
|
||||
bytes: &[u8],
|
||||
) -> LoResult<u32> {
|
||||
let byte_type_tag = type_tag_form_itype(&crate::IType::U8);
|
||||
let seq_writer = self.sequential_writer(store, bytes.len() as u32, byte_type_tag)?;
|
||||
let seq_writer = self
|
||||
.sequential_writer(store, bytes.len() as u32, byte_type_tag)
|
||||
.await?;
|
||||
seq_writer.write_bytes(store, &self, bytes);
|
||||
|
||||
Ok(seq_writer.start_offset())
|
||||
}
|
||||
|
||||
pub fn sequential_writer(
|
||||
pub async fn sequential_writer(
|
||||
&mut self,
|
||||
store: &mut <Store as it_memory_traits::Store>::ActualStore<'_>,
|
||||
size: u32,
|
||||
type_tag: u32,
|
||||
) -> LoResult<SequentialWriter> {
|
||||
let (offset, view) = self.heap_manager.allocate(store, size, type_tag)?;
|
||||
let (offset, view) = self.heap_manager.allocate(store, size, type_tag).await?;
|
||||
self.view.replace(view);
|
||||
let seq_writer = SequentialWriter::new(offset);
|
||||
Ok(seq_writer)
|
||||
|
@ -14,18 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use it_memory_traits::MemoryView;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub const DEFAULT_MEMORY_INDEX: usize = 0;
|
||||
|
||||
pub trait Allocatable<MV: MemoryView<Store>, Store: it_memory_traits::Store> {
|
||||
fn allocate(
|
||||
&mut self,
|
||||
store: &mut <Store as it_memory_traits::Store>::ActualStore<'_>,
|
||||
pub trait Allocatable<MV: MemoryView<Store>, Store: it_memory_traits::Store>: Send {
|
||||
fn allocate<'this, 'store: 'this, 'store_inner: 'this>(
|
||||
&'this mut self,
|
||||
store: &'store mut <Store as it_memory_traits::Store>::ActualStore<'store_inner>,
|
||||
size: u32,
|
||||
type_tag: u32,
|
||||
) -> Result<(u32, MV), AllocatableError>;
|
||||
) -> BoxFuture<'this, Result<(u32, MV), AllocatableError>>;
|
||||
}
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
|
@ -18,8 +18,8 @@ mod errors;
|
||||
|
||||
pub use errors::MemoryAccessError;
|
||||
|
||||
pub trait Store {
|
||||
type ActualStore<'c>;
|
||||
pub trait Store: Send {
|
||||
type ActualStore<'c>: Send;
|
||||
}
|
||||
|
||||
pub trait MemoryReadable<Store: self::Store> {
|
||||
@ -70,7 +70,9 @@ pub trait MemoryWritable<Store: self::Store> {
|
||||
);
|
||||
}
|
||||
|
||||
pub trait MemoryView<Store: self::Store>: MemoryWritable<Store> + MemoryReadable<Store> {
|
||||
pub trait MemoryView<Store: self::Store>:
|
||||
Send + MemoryWritable<Store> + MemoryReadable<Store>
|
||||
{
|
||||
/// For optimization purposes, user must check bounds first, then try read-write to memory
|
||||
/// `MemoryWritable` and `MemoryReadable` functions will panic in case of out of bounds access`
|
||||
fn check_bounds(
|
||||
@ -81,7 +83,7 @@ pub trait MemoryView<Store: self::Store>: MemoryWritable<Store> + MemoryReadable
|
||||
) -> Result<(), MemoryAccessError>;
|
||||
}
|
||||
|
||||
pub trait Memory<View, Store: self::Store>
|
||||
pub trait Memory<View, Store: self::Store>: Send
|
||||
where
|
||||
View: MemoryView<Store>,
|
||||
{
|
||||
|
3
rust-toolchain.toml
Normal file
3
rust-toolchain.toml
Normal file
@ -0,0 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2023-09-17"
|
||||
targets = [ "x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "wasm32-wasi" ]
|
@ -26,6 +26,8 @@ serde_json = "1.0"
|
||||
safe-transmute = "0.11.2"
|
||||
log = "0.4.17"
|
||||
itertools = "0.10.5"
|
||||
futures = "0.3.29"
|
||||
paste = "1.0.14"
|
||||
|
||||
thiserror = "1.0.38"
|
||||
semver = "1.0.16"
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::instr_error;
|
||||
use crate::{errors::InstructionErrorKind, interpreter::Instruction};
|
||||
use crate::interpreter::instructions::InstructionErrorKind;
|
||||
use crate::interpreter::Instruction;
|
||||
|
||||
executable_instruction!(
|
||||
impl_sync_executable_instruction!(
|
||||
argument_get(index: u32, instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let invocation_inputs = runtime.invocation_inputs;
|
||||
|
@ -1,7 +1,10 @@
|
||||
use super::lilo;
|
||||
|
||||
use crate::errors::InstructionResult;
|
||||
use crate::instr_error;
|
||||
use crate::interpreter::instructions::to_native;
|
||||
use crate::interpreter::stack::Stackable;
|
||||
use crate::interpreter::{AsyncExecutableInstructionImpl, ExecutableInstruction, Runtime};
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
@ -12,17 +15,17 @@ use it_lilo::lowerer::ILowerer;
|
||||
use it_lilo::lowerer::LoweredArray;
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures::FutureExt;
|
||||
|
||||
struct ArrayLiftMemoryAsync {
|
||||
instruction: Instruction,
|
||||
value_type: IType,
|
||||
}
|
||||
pub(crate) fn array_lift_memory<Instance, Export, LocalImport, Memory, MemoryView, Store>(
|
||||
instruction: Instruction,
|
||||
value_type: IType,
|
||||
) -> crate::interpreter::ExecutableInstruction<
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
>
|
||||
) -> ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
@ -37,10 +40,37 @@ where
|
||||
>,
|
||||
Store: crate::interpreter::wasm::structures::Store,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
ExecutableInstruction::Async(Box::new(ArrayLiftMemoryAsync {
|
||||
instruction,
|
||||
value_type,
|
||||
}))
|
||||
}
|
||||
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
AsyncExecutableInstructionImpl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
for ArrayLiftMemoryAsync
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
>,
|
||||
Store: crate::interpreter::wasm::structures::Store,
|
||||
{
|
||||
fn execute<'args>(
|
||||
&'args self,
|
||||
runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>,
|
||||
) -> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let value_type = &self.value_type;
|
||||
let instruction = &self.instruction;
|
||||
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
@ -74,29 +104,33 @@ where
|
||||
|
||||
let li_helper = lilo::LiHelper::new(&**instance);
|
||||
let lifter = ILifter::new(memory_view, &li_helper);
|
||||
let array =
|
||||
it_lilo::lifter::array_lift_memory(runtime.store, &lifter, &value_type, offset, size)
|
||||
.map_err(|e| InstructionError::from_li(instruction.clone(), e))?;
|
||||
let array = it_lilo::lifter::array_lift_memory(
|
||||
runtime.store,
|
||||
&lifter,
|
||||
&value_type,
|
||||
offset,
|
||||
size,
|
||||
)
|
||||
.map_err(|e| InstructionError::from_li(instruction.clone(), e))?;
|
||||
|
||||
log::trace!("array.lift_memory: pushing {:?} on the stack", array);
|
||||
runtime.stack.push(array);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
struct ArrayLowerMemoryAsync {
|
||||
instruction: Instruction,
|
||||
value_type: IType,
|
||||
}
|
||||
|
||||
pub(crate) fn array_lower_memory<Instance, Export, LocalImport, Memory, MemoryView, Store>(
|
||||
instruction: Instruction,
|
||||
value_type: IType,
|
||||
) -> crate::interpreter::ExecutableInstruction<
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
>
|
||||
) -> ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
@ -111,10 +145,37 @@ where
|
||||
>,
|
||||
Store: crate::interpreter::wasm::structures::Store,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
ExecutableInstruction::Async(Box::new(ArrayLowerMemoryAsync {
|
||||
instruction,
|
||||
value_type,
|
||||
}))
|
||||
}
|
||||
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
AsyncExecutableInstructionImpl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
for ArrayLowerMemoryAsync
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
>,
|
||||
Store: crate::interpreter::wasm::structures::Store,
|
||||
{
|
||||
fn execute<'args>(
|
||||
&'args self,
|
||||
runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>,
|
||||
) -> BoxFuture<InstructionResult<()>> {
|
||||
let value_type = &self.value_type;
|
||||
let instruction = &self.instruction;
|
||||
|
||||
async move {
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let stack_value = runtime.stack.pop1().ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
@ -125,7 +186,11 @@ where
|
||||
|
||||
match stack_value {
|
||||
IValue::Array(values) => {
|
||||
log::trace!("array.lower_memory: obtained {:?} values on the stack for interface type {:?}", values, value_type);
|
||||
log::trace!(
|
||||
"array.lower_memory: obtained {:?} values on the stack for interface type {:?}",
|
||||
values,
|
||||
value_type
|
||||
);
|
||||
|
||||
for value in values.iter() {
|
||||
super::is_value_compatible_to_type(&**instance, &value_type, &value)
|
||||
@ -150,6 +215,7 @@ where
|
||||
|
||||
let LoweredArray { offset, size } =
|
||||
it_lilo::lowerer::array_lower_memory(runtime.store, &mut lowerer, values)
|
||||
.await
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
log::trace!(
|
||||
@ -181,6 +247,7 @@ where
|
||||
let offset = lowerer
|
||||
.writer
|
||||
.write_bytes(runtime.store, &bytearray)
|
||||
.await
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
let size = bytearray.len();
|
||||
|
||||
@ -203,5 +270,6 @@ where
|
||||
),
|
||||
}
|
||||
}
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
@ -3,136 +3,173 @@ use crate::instr_error;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
errors::{InstructionError, InstructionErrorKind, InstructionResult},
|
||||
interpreter::stack::Stackable,
|
||||
interpreter::Instruction,
|
||||
interpreter::Runtime,
|
||||
};
|
||||
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
executable_instruction!(
|
||||
byte_array_lift_memory(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
use futures::future::BoxFuture;
|
||||
use futures::FutureExt;
|
||||
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
struct ByteArrayLiftMemoryAsync {
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
impl_async_executable_instruction!(
|
||||
byte_array_lift_memory(instruction: Instruction) -> _ {
|
||||
Box::new(ByteArrayLiftMemoryAsync{instruction})
|
||||
}
|
||||
ByteArrayLiftMemoryAsync {
|
||||
fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>)
|
||||
-> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
self.instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let pointer = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let length = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
self.instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?;
|
||||
|
||||
let memory_view = memory.view();
|
||||
let pointer = to_native::<i32>(inputs.remove(0), self.instruction.clone())? as u32;
|
||||
let length = to_native::<i32>(inputs.remove(0), self.instruction.clone())? as u32;
|
||||
|
||||
if length == 0 {
|
||||
runtime.stack.push(IValue::ByteArray(vec![]));
|
||||
let memory_view = memory.view();
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
if length == 0 {
|
||||
runtime.stack.push(IValue::ByteArray(vec![]));
|
||||
|
||||
memory_view
|
||||
.check_bounds(runtime.store, pointer, length)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let data = memory_view.read_vec(runtime.store, pointer, length);
|
||||
memory_view
|
||||
.check_bounds(runtime.store, pointer, length)
|
||||
.map_err(|e| InstructionError::from_memory_access(self.instruction.clone(), e))?;
|
||||
|
||||
log::debug!("byte_array.lift_memory: pushing {:?} on the stack", data);
|
||||
runtime.stack.push(IValue::ByteArray(data));
|
||||
let data = memory_view.read_vec(runtime.store, pointer, length);
|
||||
|
||||
Ok(())
|
||||
log::debug!("byte_array.lift_memory: pushing {:?} on the stack", data);
|
||||
runtime.stack.push(IValue::ByteArray(data));
|
||||
|
||||
Ok(())
|
||||
}.boxed()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
struct ByteArrayLowerMemoryAsync {
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
impl_async_executable_instruction!(
|
||||
byte_array_lower_memory(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
Box::new(ByteArrayLowerMemoryAsync{instruction})
|
||||
}
|
||||
|
||||
let array_pointer = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let array: Vec<u8> = to_native(inputs.remove(0), instruction.clone())?;
|
||||
let length = array.len() as u32;
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
ByteArrayLowerMemoryAsync {
|
||||
fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>) -> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let instruction = &self.instruction;
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
})?;
|
||||
|
||||
memory_view
|
||||
.check_bounds(runtime.store, array_pointer, array.len() as u32)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
let array_pointer = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let array: Vec<u8> = to_native(inputs.remove(0), instruction.clone())?;
|
||||
let length = array.len() as u32;
|
||||
|
||||
memory_view.write_bytes(runtime.store, array_pointer, &array);
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
log::debug!("string.lower_memory: pushing {}, {} on the stack", array_pointer, length);
|
||||
runtime.stack.push(IValue::I32(array_pointer as i32));
|
||||
runtime.stack.push(IValue::I32(length as i32));
|
||||
memory_view
|
||||
.check_bounds(runtime.store, array_pointer, array.len() as u32)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
|
||||
Ok(())
|
||||
memory_view.write_bytes(runtime.store, array_pointer, &array);
|
||||
|
||||
log::debug!("string.lower_memory: pushing {}, {} on the stack", array_pointer, length);
|
||||
runtime.stack.push(IValue::I32(array_pointer as i32));
|
||||
runtime.stack.push(IValue::I32(length as i32));
|
||||
|
||||
Ok(())
|
||||
}.boxed()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
struct ByteArraySizeAsync {
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
impl_async_executable_instruction!(
|
||||
byte_array_size(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
match runtime.stack.pop1() {
|
||||
Some(IValue::ByteArray(array)) => {
|
||||
let length = array.len() as i32;
|
||||
Box::new(ByteArraySizeAsync{instruction})
|
||||
}
|
||||
|
||||
log::debug!("byte_array.size: pushing {} on the stack", length);
|
||||
runtime.stack.push(IValue::I32(length));
|
||||
ByteArraySizeAsync {
|
||||
fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>) -> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let instruction = &self.instruction;
|
||||
match runtime.stack.pop1() {
|
||||
Some(IValue::ByteArray(array)) => {
|
||||
let length = array.len() as i32;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
log::debug!("byte_array.size: pushing {} on the stack", length);
|
||||
runtime.stack.push(IValue::I32(length));
|
||||
|
||||
Some(IValue::Array(array)) => {
|
||||
let array = check_array_type(array, &instruction)?;
|
||||
Ok(())
|
||||
},
|
||||
|
||||
let length = array.len() as i32;
|
||||
Some(IValue::Array(array)) => {
|
||||
let array = check_array_type(array, &instruction)?;
|
||||
|
||||
log::debug!("byte_array.size: pushing {} on the stack", length);
|
||||
runtime.stack.push(IValue::I32(length));
|
||||
let length = array.len() as i32;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
log::debug!("byte_array.size: pushing {} on the stack", length);
|
||||
runtime.stack.push(IValue::I32(length));
|
||||
|
||||
Some(value) => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::ByteArray,
|
||||
received_value: (&value).clone(),
|
||||
}
|
||||
),
|
||||
Ok(())
|
||||
},
|
||||
|
||||
None => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 }
|
||||
),
|
||||
}
|
||||
Some(value) => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::ByteArray,
|
||||
received_value: (&value).clone(),
|
||||
}
|
||||
),
|
||||
|
||||
None => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 }
|
||||
),
|
||||
}
|
||||
}.boxed()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -1,56 +1,79 @@
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
errors::{InstructionError, InstructionErrorKind, InstructionResult},
|
||||
interpreter::stack::Stackable,
|
||||
interpreter::wasm::structures::{FunctionIndex, TypedIndex},
|
||||
interpreter::Instruction,
|
||||
interpreter::Runtime,
|
||||
};
|
||||
|
||||
executable_instruction!(
|
||||
use futures::future::BoxFuture;
|
||||
use futures::FutureExt;
|
||||
|
||||
struct CallCoreAsync {
|
||||
function_index: u32,
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
impl_async_executable_instruction!(
|
||||
call_core(function_index: u32, instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let instance = &runtime.wasm_instance;
|
||||
let index = FunctionIndex::new(function_index as usize);
|
||||
Box::new(CallCoreAsync{function_index, instruction})
|
||||
}
|
||||
|
||||
let local_or_import = instance.local_or_import(index).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LocalOrImportIsMissing {
|
||||
function_index,
|
||||
},
|
||||
)
|
||||
})?;
|
||||
let inputs_cardinality = local_or_import.inputs_cardinality();
|
||||
CallCoreAsync {
|
||||
fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>)
|
||||
-> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let instruction = &self.instruction;
|
||||
let function_index = self.function_index;
|
||||
|
||||
let inputs = runtime.stack.pop(inputs_cardinality).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall {
|
||||
needed: inputs_cardinality,
|
||||
},
|
||||
)
|
||||
})?;
|
||||
let instance = &runtime.wasm_instance;
|
||||
let index = FunctionIndex::new(function_index as usize);
|
||||
|
||||
super::check_function_signature(&**instance, local_or_import, &inputs)
|
||||
.map_err(|e| InstructionError::from_error_kind(instruction.clone(), e))?;
|
||||
let local_or_import = instance.local_or_import(index).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LocalOrImportIsMissing {
|
||||
function_index,
|
||||
},
|
||||
)
|
||||
})?;
|
||||
let inputs_cardinality = local_or_import.inputs_cardinality();
|
||||
|
||||
log::debug!("call-core: calling {} with arguments: {:?}", local_or_import.name(), inputs);
|
||||
let inputs = runtime.stack.pop(inputs_cardinality).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall {
|
||||
needed: inputs_cardinality,
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
let outputs = local_or_import.call(runtime.store, &inputs).map_err(|e| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LocalOrImportCall {
|
||||
function_name: local_or_import.name().to_string(),
|
||||
reason: e
|
||||
},
|
||||
)
|
||||
})?;
|
||||
super::check_function_signature(&**instance, local_or_import, &inputs)
|
||||
.map_err(|e| InstructionError::from_error_kind(instruction.clone(), e))?;
|
||||
|
||||
log::debug!("call-core: call to {} succeeded with result {:?}", local_or_import.name(), outputs);
|
||||
log::debug!("call-core: calling {} with arguments: {:?}", local_or_import.name(), inputs);
|
||||
|
||||
for output in outputs.into_iter() {
|
||||
runtime.stack.push(output)
|
||||
}
|
||||
let outputs = local_or_import
|
||||
.call_async(runtime.store, &inputs)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LocalOrImportCall {
|
||||
function_name: local_or_import.name().to_string(),
|
||||
reason: e
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
log::debug!("call-core: call to {} succeeded with result {:?}", local_or_import.name(), outputs);
|
||||
|
||||
for output in outputs.into_iter() {
|
||||
runtime.stack.push(output)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}.boxed()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
interpreter::Instruction,
|
||||
};
|
||||
|
||||
executable_instruction!(
|
||||
impl_sync_executable_instruction!(
|
||||
dup(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let value = runtime.stack.peek1().ok_or_else(|| {
|
||||
|
@ -6,13 +6,16 @@ use it_lilo::traits::Allocatable;
|
||||
use it_lilo::traits::AllocatableError;
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures::FutureExt;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport<Store> + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store> + 'i,
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport<Store>,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: wasm::structures::MemoryView<Store>,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
|
||||
Store: wasm::structures::Store,
|
||||
@ -28,9 +31,9 @@ where
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport<Store> + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store> + 'i,
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport<Store>,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: wasm::structures::MemoryView<Store>,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
|
||||
Store: wasm::structures::Store,
|
||||
@ -50,61 +53,64 @@ where
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView, Store> Allocatable<MemoryView, Store>
|
||||
for LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport<Store> + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store> + 'i,
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport<Store>,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: wasm::structures::MemoryView<Store>,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
|
||||
Store: wasm::structures::Store,
|
||||
{
|
||||
fn allocate(
|
||||
&mut self,
|
||||
store: &mut <Store as wasm::structures::Store>::ActualStore<'_>,
|
||||
fn allocate<'this, 'store: 'this, 'store_inner: 'this>(
|
||||
&'this mut self,
|
||||
store: &'store mut <Store as wasm::structures::Store>::ActualStore<'store_inner>,
|
||||
size: u32,
|
||||
type_tag: u32,
|
||||
) -> Result<(u32, MemoryView), AllocatableError> {
|
||||
use AllocatableError::*;
|
||||
) -> BoxFuture<'this, Result<(u32, MemoryView), AllocatableError>> {
|
||||
async move {
|
||||
use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX;
|
||||
use crate::interpreter::wasm::structures::TypedIndex;
|
||||
use AllocatableError::*;
|
||||
|
||||
use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX;
|
||||
use crate::interpreter::wasm::structures::TypedIndex;
|
||||
let index = FunctionIndex::new(ALLOCATE_FUNC_INDEX as usize);
|
||||
let local_or_import =
|
||||
self.instance
|
||||
.local_or_import(index)
|
||||
.ok_or(AllocateFuncIsMissing {
|
||||
function_index: ALLOCATE_FUNC_INDEX,
|
||||
})?;
|
||||
|
||||
let index = FunctionIndex::new(ALLOCATE_FUNC_INDEX as usize);
|
||||
let local_or_import =
|
||||
self.instance
|
||||
.local_or_import(index)
|
||||
.ok_or(AllocateFuncIsMissing {
|
||||
function_index: ALLOCATE_FUNC_INDEX,
|
||||
})?;
|
||||
let inputs = vec![IValue::I32(size as _), IValue::I32(type_tag as _)];
|
||||
// TODO: we could check it only once on the module startup or memorize check result
|
||||
crate::interpreter::instructions::check_function_signature(
|
||||
self.instance,
|
||||
local_or_import,
|
||||
&inputs,
|
||||
)
|
||||
.map_err(|_| AllocateFuncIncompatibleSignature)?;
|
||||
|
||||
let inputs = vec![IValue::I32(size as _), IValue::I32(type_tag as _)];
|
||||
// TODO: we could check it only once on the module startup or memorize check result
|
||||
crate::interpreter::instructions::check_function_signature(
|
||||
self.instance,
|
||||
local_or_import,
|
||||
&inputs,
|
||||
)
|
||||
.map_err(|_| AllocateFuncIncompatibleSignature)?;
|
||||
let outcome = local_or_import
|
||||
.call_async(store, &inputs)
|
||||
.await
|
||||
.map_err(|e| AllocateCallFailed { reason: e })?;
|
||||
|
||||
let outcome = local_or_import
|
||||
.call(store, &inputs)
|
||||
.map_err(|e| AllocateCallFailed { reason: e })?;
|
||||
|
||||
if outcome.len() != 1 {
|
||||
return Err(AllocateFuncIncompatibleOutput);
|
||||
}
|
||||
|
||||
match outcome[0] {
|
||||
IValue::I32(offset) => {
|
||||
let view =
|
||||
self.instance
|
||||
.memory_view(DEFAULT_MEMORY_INDEX)
|
||||
.ok_or(MemoryIsMissing {
|
||||
memory_index: DEFAULT_MEMORY_INDEX,
|
||||
})?;
|
||||
|
||||
Ok((offset as _, view))
|
||||
if outcome.len() != 1 {
|
||||
return Err(AllocateFuncIncompatibleOutput);
|
||||
}
|
||||
|
||||
match outcome[0] {
|
||||
IValue::I32(offset) => {
|
||||
let view =
|
||||
self.instance
|
||||
.memory_view(DEFAULT_MEMORY_INDEX)
|
||||
.ok_or(MemoryIsMissing {
|
||||
memory_index: DEFAULT_MEMORY_INDEX,
|
||||
})?;
|
||||
|
||||
Ok((offset as _, view))
|
||||
}
|
||||
_ => Err(AllocateFuncIncompatibleOutput),
|
||||
}
|
||||
_ => Err(AllocateFuncIncompatibleOutput),
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use std::convert::TryInto;
|
||||
|
||||
macro_rules! lowering_lifting {
|
||||
($instruction_function_name:ident, $instruction_name:expr, $to_variant:ident, $from_variant:ident) => {
|
||||
executable_instruction!(
|
||||
impl_sync_executable_instruction!(
|
||||
$instruction_function_name(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
match runtime.stack.pop1() {
|
||||
@ -94,7 +94,7 @@ lowering_lifting!(i64_from_u16, "i64.from_u16", I64, U16);
|
||||
lowering_lifting!(i64_from_u32, "i64.from_u32", I64, U32);
|
||||
lowering_lifting!(i64_from_u64, "i64.from_u64", I64, U64);
|
||||
|
||||
executable_instruction!(
|
||||
impl_sync_executable_instruction!(
|
||||
bool_from_i32(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
match runtime.stack.pop1() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::IValue;
|
||||
|
||||
executable_instruction!(
|
||||
impl_sync_executable_instruction!(
|
||||
push_i32(value: i32) -> _ {
|
||||
move |runtime| -> _ {
|
||||
|
||||
@ -12,7 +12,7 @@ executable_instruction!(
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
impl_sync_executable_instruction!(
|
||||
push_i64(value: i64) -> _ {
|
||||
move |runtime| -> _ {
|
||||
|
||||
|
@ -5,21 +5,25 @@ use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::{errors::InstructionError, errors::InstructionErrorKind, interpreter::Instruction};
|
||||
|
||||
use crate::errors::InstructionResult;
|
||||
use crate::interpreter::stack::Stackable;
|
||||
use crate::interpreter::{AsyncExecutableInstructionImpl, ExecutableInstruction, Runtime};
|
||||
use it_lilo::lifter::ILifter;
|
||||
use it_lilo::lowerer::ILowerer;
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures::FutureExt;
|
||||
|
||||
struct RecordLiftMemoryAsync {
|
||||
record_type_id: u64,
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
pub(crate) fn record_lift_memory<Instance, Export, LocalImport, Memory, MemoryView, Store>(
|
||||
record_type_id: u64,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
>
|
||||
) -> ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
@ -34,10 +38,37 @@ where
|
||||
>,
|
||||
Store: crate::interpreter::wasm::structures::Store,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
ExecutableInstruction::Async(Box::new(RecordLiftMemoryAsync {
|
||||
record_type_id,
|
||||
instruction,
|
||||
}))
|
||||
}
|
||||
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
AsyncExecutableInstructionImpl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
for RecordLiftMemoryAsync
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
>,
|
||||
Store: crate::interpreter::wasm::structures::Store,
|
||||
{
|
||||
fn execute<'args>(
|
||||
&'args self,
|
||||
runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>,
|
||||
) -> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let record_type_id = self.record_type_id;
|
||||
let instruction = &self.instruction;
|
||||
|
||||
let mut inputs = runtime.stack.pop(1).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
@ -75,28 +106,28 @@ where
|
||||
|
||||
let li_helper = lilo::LiHelper::new(&**instance);
|
||||
let lifter = ILifter::new(memory_view, &li_helper);
|
||||
let record = it_lilo::lifter::record_lift_memory(runtime.store, &lifter, record_type, offset)
|
||||
.map_err(|e| InstructionError::from_li(instruction.clone(), e))?;
|
||||
let record =
|
||||
it_lilo::lifter::record_lift_memory(runtime.store, &lifter, record_type, offset)
|
||||
.map_err(|e| InstructionError::from_li(instruction.clone(), e))?;
|
||||
|
||||
log::debug!("record.lift_memory: pushing {:?} on the stack", record);
|
||||
runtime.stack.push(record);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
struct RecordLowerMemoryAsync {
|
||||
record_type_id: u64,
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
pub(crate) fn record_lower_memory<Instance, Export, LocalImport, Memory, MemoryView, Store>(
|
||||
record_type_id: u64,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
>
|
||||
) -> ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
@ -111,10 +142,36 @@ where
|
||||
>,
|
||||
Store: crate::interpreter::wasm::structures::Store,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
ExecutableInstruction::Async(Box::new(RecordLowerMemoryAsync {
|
||||
record_type_id,
|
||||
instruction,
|
||||
}))
|
||||
}
|
||||
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
AsyncExecutableInstructionImpl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
for RecordLowerMemoryAsync
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
>,
|
||||
Store: crate::interpreter::wasm::structures::Store,
|
||||
{
|
||||
fn execute<'args>(
|
||||
&'args self,
|
||||
runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>,
|
||||
) -> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let record_type_id = self.record_type_id;
|
||||
let instruction = &self.instruction;
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
|
||||
match runtime.stack.pop1() {
|
||||
@ -126,7 +183,11 @@ where
|
||||
)
|
||||
.map_err(|e| InstructionError::from_error_kind(instruction.clone(), e))?;
|
||||
|
||||
log::debug!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id);
|
||||
log::debug!(
|
||||
"record.lower_memory: obtained {:?} values on the stack for record type = {}",
|
||||
record_fields,
|
||||
record_type_id
|
||||
);
|
||||
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
@ -142,11 +203,13 @@ where
|
||||
let mut lo_helper = lilo::LoHelper::new(&**instance);
|
||||
let mut memory_writer = ILowerer::new(memory_view, &mut lo_helper)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
let offset = it_lilo::lowerer::record_lower_memory(
|
||||
runtime.store,
|
||||
&mut memory_writer,
|
||||
record_fields,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
log::debug!("record.lower_memory: pushing {} on the stack", offset);
|
||||
@ -167,5 +230,6 @@ where
|
||||
),
|
||||
}
|
||||
}
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
@ -3,103 +3,138 @@ use crate::instr_error;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
errors::{InstructionError, InstructionErrorKind, InstructionResult},
|
||||
interpreter::stack::Stackable,
|
||||
interpreter::Instruction,
|
||||
interpreter::Runtime,
|
||||
};
|
||||
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
executable_instruction!(
|
||||
use futures::future::BoxFuture;
|
||||
use futures::FutureExt;
|
||||
|
||||
struct StringLiftMemory {
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
impl_async_executable_instruction!(
|
||||
string_lift_memory(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
Box::new(StringLiftMemory{instruction})
|
||||
}
|
||||
StringLiftMemory {
|
||||
fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>) -> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let instruction = &self.instruction;
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let pointer = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let length = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let memory_view = memory.view();
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?;
|
||||
|
||||
if length == 0 {
|
||||
runtime.stack.push(IValue::String("".into()));
|
||||
let pointer = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let length = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let memory_view = memory.view();
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
if length == 0 {
|
||||
runtime.stack.push(IValue::String("".into()));
|
||||
|
||||
memory_view
|
||||
.check_bounds(runtime.store, pointer, length)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let data = memory_view.read_vec(runtime.store, pointer, length);
|
||||
let string = String::from_utf8(data)
|
||||
.map_err(|error| InstructionError::from_error_kind(instruction.clone(), InstructionErrorKind::String(error)))?;
|
||||
memory_view
|
||||
.check_bounds(runtime.store, pointer, length)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
|
||||
log::debug!("string.lift_memory: pushing {:?} on the stack", string);
|
||||
runtime.stack.push(IValue::String(string));
|
||||
let data = memory_view.read_vec(runtime.store, pointer, length);
|
||||
let string = String::from_utf8(data)
|
||||
.map_err(|error| InstructionError::from_error_kind(instruction.clone(), InstructionErrorKind::String(error)))?;
|
||||
|
||||
Ok(())
|
||||
log::debug!("string.lift_memory: pushing {:?} on the stack", string);
|
||||
runtime.stack.push(IValue::String(string));
|
||||
|
||||
Ok(())
|
||||
}.boxed()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
struct StringLowerMemoryAsync {
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
impl_async_executable_instruction!(
|
||||
string_lower_memory(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let string_pointer = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let string: String = to_native(inputs.remove(0), instruction.clone())?;
|
||||
let string_bytes = string.as_bytes();
|
||||
let string_length: u32 = string_bytes.len() as u32;
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory_view(memory_index)
|
||||
.ok_or_else(|| {
|
||||
Box::new(StringLowerMemoryAsync {instruction})
|
||||
}
|
||||
StringLowerMemoryAsync {
|
||||
fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>) -> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let instruction = &self.instruction;
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
memory_view
|
||||
.check_bounds(runtime.store, string_pointer, string_length)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
let string_pointer = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
|
||||
let string: String = to_native(inputs.remove(0), instruction.clone())?;
|
||||
let string_bytes = string.as_bytes();
|
||||
let string_length: u32 = string_bytes.len() as u32;
|
||||
|
||||
memory_view.write_bytes(runtime.store, string_pointer, string_bytes);
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory_view(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?;
|
||||
|
||||
log::debug!("string.lower_memory: pushing {}, {} on the stack", string_pointer, string_length);
|
||||
runtime.stack.push(IValue::I32(string_pointer as i32));
|
||||
runtime.stack.push(IValue::I32(string_length as i32));
|
||||
memory_view
|
||||
.check_bounds(runtime.store, string_pointer, string_length)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
|
||||
Ok(())
|
||||
memory_view.write_bytes(runtime.store, string_pointer, string_bytes);
|
||||
|
||||
log::debug!("string.lower_memory: pushing {}, {} on the stack", string_pointer, string_length);
|
||||
runtime.stack.push(IValue::I32(string_pointer as i32));
|
||||
runtime.stack.push(IValue::I32(string_length as i32));
|
||||
|
||||
Ok(())
|
||||
}.boxed()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
struct StringSize {
|
||||
instruction: Instruction,
|
||||
}
|
||||
|
||||
impl_async_executable_instruction!(
|
||||
string_size(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
Box::new( StringSize{instruction } )
|
||||
}
|
||||
|
||||
StringSize {
|
||||
fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>) -> BoxFuture<InstructionResult<()>> {
|
||||
async move {
|
||||
let instruction = &self.instruction;
|
||||
match runtime.stack.pop1() {
|
||||
Some(IValue::String(string)) => {
|
||||
let length = string.len() as i32;
|
||||
@ -122,7 +157,8 @@ executable_instruction!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 }
|
||||
),
|
||||
}
|
||||
}
|
||||
}.boxed()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
interpreter::Instruction,
|
||||
};
|
||||
|
||||
executable_instruction!(
|
||||
impl_sync_executable_instruction!(
|
||||
swap2(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let mut values = runtime.stack.pop(2).ok_or_else(|| {
|
||||
|
@ -9,6 +9,9 @@ pub use instructions::Instruction;
|
||||
use crate::errors::{InstructionResult, InterpreterResult};
|
||||
use crate::IValue;
|
||||
use stack::Stack;
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
|
||||
use std::{convert::TryFrom, marker::PhantomData};
|
||||
|
||||
/// Represents the `Runtime`, which is used by an adapter to execute
|
||||
@ -49,14 +52,71 @@ pub(crate) struct Runtime<
|
||||
_phantom: PhantomData<(Export, LocalImport, Memory, MemoryView, Store)>,
|
||||
}
|
||||
|
||||
/// Type alias for an executable instruction. It's an implementation
|
||||
/// details, but an instruction is a boxed dyn AsyncExecutableInstructionImpl instance.
|
||||
pub(crate) type AsyncExecutableInstruction<
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
> = Box<
|
||||
dyn AsyncExecutableInstructionImpl<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>;
|
||||
|
||||
pub(crate) type SyncExecutableInstruction<
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
> = Box<
|
||||
dyn Fn(
|
||||
&mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>,
|
||||
) -> InstructionResult<()>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>;
|
||||
|
||||
/// Type alias for an executable instruction. It's an implementation
|
||||
/// details, but an instruction is a boxed closure instance.
|
||||
pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store> =
|
||||
Box<
|
||||
dyn Fn(&mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>, ) -> InstructionResult<()>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>;
|
||||
pub(crate) enum ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport<Store>,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: wasm::structures::MemoryView<Store>,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
|
||||
Store: wasm::structures::Store,
|
||||
{
|
||||
Sync(SyncExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>),
|
||||
Async(AsyncExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>),
|
||||
}
|
||||
|
||||
pub(crate) trait AsyncExecutableInstructionImpl<
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
Store,
|
||||
> where
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport<Store>,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: wasm::structures::MemoryView<Store>,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
|
||||
Store: wasm::structures::Store,
|
||||
{
|
||||
fn execute<'args>(
|
||||
&'args self,
|
||||
runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>,
|
||||
) -> BoxFuture<'args, InstructionResult<()>>;
|
||||
}
|
||||
|
||||
/// An interpreter is the central piece of this crate. It is a set of
|
||||
/// executable instructions. Each instruction takes the runtime as
|
||||
@ -172,7 +232,7 @@ where
|
||||
/// 2. Create a fresh stack,
|
||||
/// 3. Execute the instructions one after the other, and
|
||||
/// returns the stack.
|
||||
pub fn run(
|
||||
pub async fn run(
|
||||
&self,
|
||||
invocation_inputs: &[IValue],
|
||||
wasm_instance: &mut Instance,
|
||||
@ -187,13 +247,117 @@ where
|
||||
};
|
||||
|
||||
for executable_instruction in self.iter() {
|
||||
executable_instruction(&mut runtime)?;
|
||||
match &executable_instruction {
|
||||
ExecutableInstruction::Sync(instruction) => instruction(&mut runtime)?,
|
||||
ExecutableInstruction::Async(instruction) => {
|
||||
instruction.execute(&mut runtime).await?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(runtime.stack)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// Transforms a `Vec<Instruction>` into an `Interpreter`.
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView, Store> TryFrom<Vec<Instruction>>
|
||||
for Interpreter<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport<Store>,
|
||||
Memory: wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: wasm::structures::MemoryView<Store>,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
|
||||
Store: wasm::structures::Store,
|
||||
{
|
||||
type Error = ();
|
||||
|
||||
fn try_from(instructions: Vec<Instruction>) -> Result<Self, Self::Error> {
|
||||
let executable_instructions = instructions
|
||||
.into_iter()
|
||||
.map(|instruction| match instruction {
|
||||
Instruction::ArgumentGet { index } => {
|
||||
instructions::argument_get(index, instruction)
|
||||
}
|
||||
|
||||
Instruction::CallCore { function_index } => {
|
||||
instructions::call_core(function_index, instruction)
|
||||
}
|
||||
|
||||
Instruction::BoolFromI32 => instructions::bool_from_i32(instruction),
|
||||
Instruction::S8FromI32 => instructions::s8_from_i32(instruction),
|
||||
Instruction::S8FromI64 => instructions::s8_from_i64(instruction),
|
||||
Instruction::S16FromI32 => instructions::s16_from_i32(instruction),
|
||||
Instruction::S16FromI64 => instructions::s16_from_i64(instruction),
|
||||
Instruction::S32FromI32 => instructions::s32_from_i32(instruction),
|
||||
Instruction::S32FromI64 => instructions::s32_from_i64(instruction),
|
||||
Instruction::S64FromI32 => instructions::s64_from_i32(instruction),
|
||||
Instruction::S64FromI64 => instructions::s64_from_i64(instruction),
|
||||
Instruction::I32FromBool => instructions::i32_from_bool(instruction),
|
||||
Instruction::I32FromS8 => instructions::i32_from_s8(instruction),
|
||||
Instruction::I32FromS16 => instructions::i32_from_s16(instruction),
|
||||
Instruction::I32FromS32 => instructions::i32_from_s32(instruction),
|
||||
Instruction::I32FromS64 => instructions::i32_from_s64(instruction),
|
||||
Instruction::I64FromS8 => instructions::i64_from_s8(instruction),
|
||||
Instruction::I64FromS16 => instructions::i64_from_s16(instruction),
|
||||
Instruction::I64FromS32 => instructions::i64_from_s32(instruction),
|
||||
Instruction::I64FromS64 => instructions::i64_from_s64(instruction),
|
||||
Instruction::U8FromI32 => instructions::u8_from_i32(instruction),
|
||||
Instruction::U8FromI64 => instructions::u8_from_i64(instruction),
|
||||
Instruction::U16FromI32 => instructions::u16_from_i32(instruction),
|
||||
Instruction::U16FromI64 => instructions::u16_from_i64(instruction),
|
||||
Instruction::U32FromI32 => instructions::u32_from_i32(instruction),
|
||||
Instruction::U32FromI64 => instructions::u32_from_i64(instruction),
|
||||
Instruction::U64FromI32 => instructions::u64_from_i32(instruction),
|
||||
Instruction::U64FromI64 => instructions::u64_from_i64(instruction),
|
||||
Instruction::I32FromU8 => instructions::i32_from_u8(instruction),
|
||||
Instruction::I32FromU16 => instructions::i32_from_u16(instruction),
|
||||
Instruction::I32FromU32 => instructions::i32_from_u32(instruction),
|
||||
Instruction::I32FromU64 => instructions::i32_from_u64(instruction),
|
||||
Instruction::I64FromU8 => instructions::i64_from_u8(instruction),
|
||||
Instruction::I64FromU16 => instructions::i64_from_u16(instruction),
|
||||
Instruction::I64FromU32 => instructions::i64_from_u32(instruction),
|
||||
Instruction::I64FromU64 => instructions::i64_from_u64(instruction),
|
||||
Instruction::PushI32 { value } => instructions::push_i32(value),
|
||||
Instruction::PushI64 { value } => instructions::push_i64(value),
|
||||
|
||||
Instruction::StringLiftMemory => instructions::string_lift_memory(instruction),
|
||||
Instruction::StringLowerMemory => instructions::string_lower_memory(instruction),
|
||||
Instruction::StringSize => instructions::string_size(instruction),
|
||||
|
||||
Instruction::ByteArrayLiftMemory => {
|
||||
instructions::byte_array_lift_memory(instruction)
|
||||
}
|
||||
Instruction::ByteArrayLowerMemory => {
|
||||
instructions::byte_array_lower_memory(instruction)
|
||||
}
|
||||
Instruction::ByteArraySize => instructions::byte_array_size(instruction),
|
||||
|
||||
Instruction::ArrayLiftMemory { ref value_type } => {
|
||||
let value_type = value_type.clone();
|
||||
instructions::array_lift_memory(instruction, value_type)
|
||||
}
|
||||
Instruction::ArrayLowerMemory { ref value_type } => {
|
||||
let value_type = value_type.clone();
|
||||
instructions::array_lower_memory(instruction, value_type)
|
||||
}
|
||||
Instruction::RecordLiftMemory { record_type_id } => {
|
||||
instructions::record_lift_memory(record_type_id as _, instruction)
|
||||
}
|
||||
Instruction::RecordLowerMemory { record_type_id } => {
|
||||
instructions::record_lower_memory(record_type_id as _, instruction)
|
||||
}
|
||||
Instruction::Dup => instructions::dup(instruction),
|
||||
Instruction::Swap2 => instructions::swap2(instruction),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Interpreter {
|
||||
executable_instructions,
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
/// Transforms a `Vec<Instruction>` into an `Interpreter`.
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView, Store> TryFrom<Vec<Instruction>>
|
||||
for Interpreter<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
|
@ -4,6 +4,10 @@ use crate::ast::FunctionArg;
|
||||
use crate::IRecordType;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures::FutureExt;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use it_memory_traits::{Memory, MemoryAccessError, MemoryView};
|
||||
@ -45,31 +49,34 @@ impl LocalImportIndex for FunctionIndex {
|
||||
type Import = ImportFunctionIndex;
|
||||
}
|
||||
|
||||
pub trait Export {
|
||||
pub trait Export: Send {
|
||||
fn name(&self) -> &str;
|
||||
fn inputs_cardinality(&self) -> usize;
|
||||
fn outputs_cardinality(&self) -> usize;
|
||||
fn arguments(&self) -> &[FunctionArg];
|
||||
fn outputs(&self) -> &[IType];
|
||||
fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, anyhow::Error>;
|
||||
fn call_async<'args>(
|
||||
&'args self,
|
||||
arguments: &'args [IValue],
|
||||
) -> BoxFuture<'args, Result<Vec<IValue>, anyhow::Error>>;
|
||||
}
|
||||
|
||||
pub trait LocalImport<Store: self::Store> {
|
||||
pub trait LocalImport<Store: self::Store>: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
fn inputs_cardinality(&self) -> usize;
|
||||
fn outputs_cardinality(&self) -> usize;
|
||||
fn arguments(&self) -> &[FunctionArg];
|
||||
fn outputs(&self) -> &[IType];
|
||||
fn call(
|
||||
&self,
|
||||
store: &mut <Store as self::Store>::ActualStore<'_>,
|
||||
arguments: &[IValue],
|
||||
) -> Result<Vec<IValue>, anyhow::Error>;
|
||||
fn call_async<'args>(
|
||||
&'args self,
|
||||
store: &'args mut <Store as self::Store>::ActualStore<'_>,
|
||||
arguments: &'args [IValue],
|
||||
) -> BoxFuture<Result<Vec<IValue>, anyhow::Error>>;
|
||||
}
|
||||
|
||||
pub use it_memory_traits::Store;
|
||||
|
||||
pub trait Instance<E, LI, M, MV, S>
|
||||
pub trait Instance<E, LI, M, MV, S>: Send + Sync
|
||||
where
|
||||
E: Export,
|
||||
LI: LocalImport<S>,
|
||||
@ -84,32 +91,6 @@ where
|
||||
fn wit_record_by_id(&self, index: u64) -> Option<&Arc<IRecordType>>;
|
||||
}
|
||||
|
||||
impl Export for () {
|
||||
fn name(&self) -> &str {
|
||||
""
|
||||
}
|
||||
|
||||
fn inputs_cardinality(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn outputs_cardinality(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn arguments(&self) -> &[FunctionArg] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn outputs(&self) -> &[IType] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn call(&self, _arguments: &[IValue]) -> Result<Vec<IValue>, anyhow::Error> {
|
||||
Err(anyhow::anyhow!("some error"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Store: self::Store> LocalImport<Store> for () {
|
||||
fn name(&self) -> &str {
|
||||
""
|
||||
@ -131,12 +112,38 @@ impl<Store: self::Store> LocalImport<Store> for () {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn call(
|
||||
fn call_async(
|
||||
&self,
|
||||
_store: &mut <Store as self::Store>::ActualStore<'_>,
|
||||
_store: &mut <Store as it_memory_traits::Store>::ActualStore<'_>,
|
||||
_arguments: &[IValue],
|
||||
) -> Result<Vec<IValue>, anyhow::Error> {
|
||||
Err(anyhow::anyhow!("some error"))
|
||||
) -> BoxFuture<Result<Vec<IValue>, anyhow::Error>> {
|
||||
async { Err(anyhow::anyhow!("some error")) }.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
impl Export for () {
|
||||
fn name(&self) -> &str {
|
||||
""
|
||||
}
|
||||
|
||||
fn inputs_cardinality(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn outputs_cardinality(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn arguments(&self) -> &[FunctionArg] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn outputs(&self) -> &[IType] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn call_async(&self, _arguments: &[IValue]) -> BoxFuture<Result<Vec<IValue>, anyhow::Error>> {
|
||||
async { Err(anyhow::anyhow!("some error")) }.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ macro_rules! consume {
|
||||
/// // ^ the `x` argument
|
||||
///
|
||||
/// // an executable instruction is a closure that takes a `Runtime` instance
|
||||
/// move |runtime| -> _ {
|
||||
/// move |runtime| -> Pin<Box<dyn Future<Output = Result<(), InstructionError>> + 'static>> _ {
|
||||
/// // Do something.
|
||||
///
|
||||
/// Ok(())
|
||||
@ -65,7 +65,31 @@ macro_rules! consume {
|
||||
/// ```
|
||||
///
|
||||
/// Check the existing executable instruction to get more examples.
|
||||
macro_rules! executable_instruction {
|
||||
macro_rules! impl_async_executable_instruction {
|
||||
($getter_name:ident($($argument_name:ident: $argument_type:ty),*) -> _ $getter_implementation:block $name:ident $($implementation:tt)*) => {
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView, Store> crate::interpreter::AsyncExecutableInstructionImpl<Instance, Export, LocalImport, Memory, MemoryView, Store> for $name
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
|
||||
Store: crate::interpreter::wasm::structures::Store, $($implementation)*
|
||||
|
||||
pub(crate) fn $getter_name<Instance, Export, LocalImport, Memory, MemoryView, Store>($($argument_name: $argument_type),*) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
|
||||
Store: crate::interpreter::wasm::structures::Store, {
|
||||
crate::interpreter::ExecutableInstruction::Async($getter_implementation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_sync_executable_instruction {
|
||||
($name:ident ( $($argument_name:ident: $argument_type:ty),* ) -> _ $implementation:block ) => {
|
||||
pub(crate) fn $name<Instance, Export, LocalImport, Memory, MemoryView, Store>(
|
||||
$($argument_name: $argument_type),*
|
||||
@ -81,7 +105,7 @@ macro_rules! executable_instruction {
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::{stack::Stackable};
|
||||
|
||||
Box::new($implementation)
|
||||
crate::interpreter::ExecutableInstruction::Sync(Box::new($implementation))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user