mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-04 07:10:21 +00:00
Merge pull request #10 from fluencelabs/optimizations
Record&Array passing optimizations, add ByteArray and Boolean
This commit is contained in:
commit
a15a81ad47
82
Cargo.lock
generated
82
Cargo.lock
generated
@ -20,9 +20,15 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "fluence-it-types"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"it-to-bytes",
|
||||
"nom",
|
||||
@ -30,10 +36,29 @@ dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "it-lilo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fluence-it-types",
|
||||
"log",
|
||||
"paste",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "it-to-bytes"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
@ -48,9 +73,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a"
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.7.5"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374"
|
||||
checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
@ -85,6 +110,12 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
@ -96,9 +127,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@ -144,18 +175,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.124"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
|
||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.124"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
|
||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -181,15 +212,35 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.64"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
|
||||
checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
@ -204,22 +255,25 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-interface-types-fl"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
dependencies = [
|
||||
"fluence-it-types",
|
||||
"it-lilo",
|
||||
"it-to-bytes",
|
||||
"itertools",
|
||||
"log",
|
||||
"nom",
|
||||
"safe-transmute",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"wast",
|
||||
]
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/it-lilo",
|
||||
"crates/to-bytes",
|
||||
"crates/it-types",
|
||||
"wasmer-it",
|
||||
|
18
crates/it-lilo/Cargo.toml
Normal file
18
crates/it-lilo/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "it-lilo"
|
||||
version = "0.1.0"
|
||||
authors = ["Fluence Labs"]
|
||||
description = "Defines some helper utils for lifting/lowering IT"
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[lib]
|
||||
name = "it_lilo"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
fluence-it-types = { path = "../it-types/", version = "0.2.0" }
|
||||
|
||||
paste = "1.0.5"
|
||||
thiserror = "1.0.24"
|
||||
log = "0.4.14"
|
36
crates/it-lilo/src/lib.rs
Normal file
36
crates/it-lilo/src/lib.rs
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
pub mod lifter;
|
||||
pub mod lowerer;
|
||||
pub mod traits;
|
||||
pub mod utils;
|
||||
|
||||
pub use fluence_it_types::ne_vec::NEVec;
|
||||
pub use fluence_it_types::IRecordType;
|
||||
pub use fluence_it_types::IType;
|
||||
pub use fluence_it_types::IValue;
|
40
crates/it-lilo/src/lifter/error.rs
Normal file
40
crates/it-lilo/src/lifter/error.rs
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2021 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::traits::RecordResolvableError;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum LiError {
|
||||
#[error(
|
||||
"Out-of-bound Wasm memory access: offset {offset}, size {size}, while memory_size {memory_size}"
|
||||
)]
|
||||
InvalidAccess {
|
||||
offset: usize,
|
||||
size: usize,
|
||||
memory_size: usize,
|
||||
},
|
||||
|
||||
#[error("{0}")]
|
||||
RecordResolvableError(#[from] RecordResolvableError),
|
||||
|
||||
#[error("{0}")]
|
||||
InvalidUTF8String(#[from] std::string::FromUtf8Error),
|
||||
|
||||
/// This error occurred when a record is created from empty values array.
|
||||
#[error("Record with name '{0}' can't be empty")]
|
||||
EmptyRecord(String),
|
||||
}
|
126
crates/it-lilo/src/lifter/lift_array.rs
Normal file
126
crates/it-lilo/src/lifter/lift_array.rs
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2021 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 super::record_lift_memory;
|
||||
use super::ILifter;
|
||||
use super::LiResult;
|
||||
use crate::traits::RecordResolvable;
|
||||
use crate::utils::ser_type_size;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
|
||||
pub fn array_lift_memory<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
value_type: &IType,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
) -> LiResult<IValue> {
|
||||
if elements_count == 0 {
|
||||
return Ok(IValue::Array(vec![]));
|
||||
}
|
||||
|
||||
let reader = &lifter.reader;
|
||||
|
||||
let ivalues = match value_type {
|
||||
IType::Boolean => reader.read_bool_array(offset, elements_count)?,
|
||||
IType::S8 => reader.read_s8_array(offset, elements_count)?,
|
||||
IType::S16 => reader.read_s16_array(offset, elements_count)?,
|
||||
IType::S32 => reader.read_s32_array(offset, elements_count)?,
|
||||
IType::S64 => reader.read_s64_array(offset, elements_count)?,
|
||||
IType::I32 => reader.read_i32_array(offset, elements_count)?,
|
||||
IType::I64 => reader.read_i64_array(offset, elements_count)?,
|
||||
IType::U8 => reader.read_u8_array(offset, elements_count)?,
|
||||
IType::U16 => reader.read_u16_array(offset, elements_count)?,
|
||||
IType::U32 => reader.read_u32_array(offset, elements_count)?,
|
||||
IType::U64 => reader.read_u64_array(offset, elements_count)?,
|
||||
IType::F32 => reader.read_f32_array(offset, elements_count)?,
|
||||
IType::F64 => reader.read_f64_array(offset, elements_count)?,
|
||||
IType::String => read_string_array(lifter, offset, elements_count)?,
|
||||
IType::ByteArray => read_array_array(lifter, &IType::U8, offset, elements_count)?,
|
||||
IType::Array(ty) => read_array_array(lifter, &ty, offset, elements_count)?,
|
||||
IType::Record(record_type_id) => {
|
||||
read_record_array(lifter, *record_type_id, offset, elements_count)?
|
||||
}
|
||||
};
|
||||
|
||||
Ok(IValue::Array(ivalues))
|
||||
}
|
||||
|
||||
fn read_string_array<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
) -> LiResult<Vec<IValue>> {
|
||||
let mut result = Vec::with_capacity(elements_count);
|
||||
let seq_reader = lifter
|
||||
.reader
|
||||
.sequential_reader(offset, ser_type_size(&IType::String) * elements_count)?;
|
||||
|
||||
for _ in 0..elements_count {
|
||||
let offset = seq_reader.read_u32();
|
||||
let size = seq_reader.read_u32();
|
||||
|
||||
let raw_str = lifter.reader.read_raw_u8_array(offset as _, size as _)?;
|
||||
let str = String::from_utf8(raw_str)?;
|
||||
result.push(IValue::String(str));
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn read_array_array<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
ty: &IType,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
) -> LiResult<Vec<IValue>> {
|
||||
let mut result = Vec::with_capacity(elements_count);
|
||||
let seq_reader = lifter
|
||||
.reader
|
||||
.sequential_reader(offset, ser_type_size(ty) * elements_count)?;
|
||||
|
||||
for _ in 0..elements_count {
|
||||
let offset = seq_reader.read_u32();
|
||||
let size = seq_reader.read_u32();
|
||||
|
||||
let array = array_lift_memory(lifter, ty, offset as _, size as _)?;
|
||||
result.push(array);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn read_record_array<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
record_type_id: u64,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
) -> LiResult<Vec<IValue>> {
|
||||
let mut result = Vec::with_capacity(elements_count);
|
||||
let seq_reader = lifter
|
||||
.reader
|
||||
.sequential_reader(offset, ser_type_size(&IType::Record(0)) * elements_count)?;
|
||||
|
||||
for _ in 0..elements_count {
|
||||
let offset = seq_reader.read_u32();
|
||||
let record_ty = lifter.resolver.resolve_record(record_type_id)?;
|
||||
|
||||
let record = record_lift_memory(lifter, &record_ty, offset as _)?;
|
||||
result.push(record);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
116
crates/it-lilo/src/lifter/lift_record.rs
Normal file
116
crates/it-lilo/src/lifter/lift_record.rs
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2021 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 super::ILifter;
|
||||
use super::LiError;
|
||||
use super::LiResult;
|
||||
use super::MemoryReader;
|
||||
use super::SequentialReader;
|
||||
use crate::traits::RecordResolvable;
|
||||
use crate::utils::record_size;
|
||||
use crate::IRecordType;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::NEVec;
|
||||
|
||||
pub fn record_lift_memory<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
record_type: &IRecordType,
|
||||
offset: usize,
|
||||
) -> LiResult<IValue> {
|
||||
let mut values = Vec::with_capacity(record_type.fields.len());
|
||||
|
||||
let size = record_size(record_type);
|
||||
let reader = &lifter.reader;
|
||||
let seq_reader = reader.sequential_reader(offset, size)?;
|
||||
|
||||
for field in (*record_type.fields).iter() {
|
||||
match &field.ty {
|
||||
IType::Boolean => values.push(IValue::Boolean(seq_reader.read_u8() != 0)),
|
||||
IType::S8 => values.push(IValue::S8(seq_reader.read_i8())),
|
||||
IType::S16 => values.push(IValue::S16(seq_reader.read_i16())),
|
||||
IType::S32 => values.push(IValue::S32(seq_reader.read_i32())),
|
||||
IType::S64 => values.push(IValue::S64(seq_reader.read_i64())),
|
||||
IType::I32 => values.push(IValue::I32(seq_reader.read_i32())),
|
||||
IType::I64 => values.push(IValue::I64(seq_reader.read_i64())),
|
||||
IType::U8 => values.push(IValue::U8(seq_reader.read_u8())),
|
||||
IType::U16 => values.push(IValue::U16(seq_reader.read_u16())),
|
||||
IType::U32 => values.push(IValue::U32(seq_reader.read_u32())),
|
||||
IType::U64 => values.push(IValue::U64(seq_reader.read_u64())),
|
||||
IType::F32 => values.push(IValue::F32(seq_reader.read_f32())),
|
||||
IType::F64 => values.push(IValue::F64(seq_reader.read_f64())),
|
||||
IType::String => values.push(IValue::String(read_string(reader, &seq_reader)?)),
|
||||
IType::ByteArray => values.push(read_byte_array(reader, &seq_reader)?),
|
||||
IType::Array(ty) => values.push(read_array(&lifter, &seq_reader, &**ty)?),
|
||||
IType::Record(record_type_id) => {
|
||||
values.push(read_record(lifter, &seq_reader, *record_type_id)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let record = NEVec::new(values.into_iter().collect())
|
||||
.map_err(|_| LiError::EmptyRecord(record_type.name.clone()))?;
|
||||
|
||||
Ok(IValue::Record(record))
|
||||
}
|
||||
|
||||
fn read_string(
|
||||
reader: &MemoryReader<'_>,
|
||||
seq_reader: &SequentialReader<'_, '_>,
|
||||
) -> LiResult<String> {
|
||||
let offset = seq_reader.read_u32();
|
||||
let size = seq_reader.read_u32();
|
||||
|
||||
let string_mem = reader.read_raw_u8_array(offset as _, size as _)?;
|
||||
|
||||
let string = String::from_utf8(string_mem)?;
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
fn read_byte_array(
|
||||
reader: &MemoryReader<'_>,
|
||||
seq_reader: &SequentialReader<'_, '_>,
|
||||
) -> LiResult<IValue> {
|
||||
let offset = seq_reader.read_u32();
|
||||
let size = seq_reader.read_u32();
|
||||
|
||||
let array = reader.read_raw_u8_array(offset as _, size as _)?;
|
||||
|
||||
Ok(IValue::ByteArray(array))
|
||||
}
|
||||
|
||||
fn read_array<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
seq_reader: &SequentialReader<'_, '_>,
|
||||
value_type: &IType,
|
||||
) -> LiResult<IValue> {
|
||||
let offset = seq_reader.read_u32();
|
||||
let size = seq_reader.read_u32();
|
||||
|
||||
super::array_lift_memory(lifter, value_type, offset as _, size as _)
|
||||
}
|
||||
|
||||
fn read_record<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
seq_reader: &SequentialReader<'_, '_>,
|
||||
record_type_id: u64,
|
||||
) -> LiResult<IValue> {
|
||||
let offset = seq_reader.read_u32();
|
||||
|
||||
let record_type = lifter.resolver.resolve_record(record_type_id)?;
|
||||
|
||||
record_lift_memory(lifter, &record_type, offset as _)
|
||||
}
|
117
crates/it-lilo/src/lifter/macros.rs
Normal file
117
crates/it-lilo/src/lifter/macros.rs
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! value_der {
|
||||
($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => {
|
||||
[$($self.reader.memory[$offset + $ids].get()),+]
|
||||
};
|
||||
|
||||
($self:expr, $offset:expr, 1) => {
|
||||
crate::value_der!($self, $offset, @seq_start 0 @seq_end);
|
||||
};
|
||||
|
||||
($self:expr, $offset:expr, 2) => {
|
||||
crate::value_der!($self, $offset, @seq_start 0, 1 @seq_end);
|
||||
};
|
||||
|
||||
($self:expr, $offset:expr, 4) => {
|
||||
crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end);
|
||||
};
|
||||
|
||||
($self:expr, $offset:expr, 8) => {
|
||||
crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end);
|
||||
};
|
||||
|
||||
($self:expr, $offset:expr, 16) => {
|
||||
crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 @seq_end);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! read_ty {
|
||||
($func_name:ident, $ty:ty, 1) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 1));
|
||||
|
||||
self.offset.set(offset + 1);
|
||||
result
|
||||
}
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 2) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 2));
|
||||
|
||||
self.offset.set(offset + 2);
|
||||
result
|
||||
}
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 4) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 4));
|
||||
|
||||
self.offset.set(offset + 4);
|
||||
result
|
||||
}
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 8) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 8));
|
||||
|
||||
self.offset.set(offset + 8);
|
||||
result
|
||||
}
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 16) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 16));
|
||||
|
||||
self.offset.set(offset + 16);
|
||||
result
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! read_array_ty {
|
||||
($func_name:ident, $ty:ident, $ity:ident) => {
|
||||
pub fn $func_name(
|
||||
&self,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
) -> super::LiResult<Vec<crate::IValue>> {
|
||||
let reader =
|
||||
self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?;
|
||||
let mut result = Vec::with_capacity(elements_count);
|
||||
|
||||
for _ in 0..elements_count {
|
||||
let value = paste::paste! { reader.[<read_ $ty>]()};
|
||||
result.push(IValue::$ity(value));
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
};
|
||||
}
|
132
crates/it-lilo/src/lifter/memory_reader.rs
Normal file
132
crates/it-lilo/src/lifter/memory_reader.rs
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2021 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 super::LiError;
|
||||
use super::LiResult;
|
||||
use crate::read_array_ty;
|
||||
use crate::read_ty;
|
||||
use crate::IValue;
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
pub struct MemoryReader<'m> {
|
||||
pub(self) memory: &'m [Cell<u8>],
|
||||
}
|
||||
|
||||
/// Reads values of basic types sequentially from the provided reader.
|
||||
/// It doesn't check memory limits for the optimization purposes,
|
||||
/// so it could be created only by the MemoryReader::sequential_reader method.
|
||||
pub struct SequentialReader<'r, 'm> {
|
||||
reader: &'r MemoryReader<'m>,
|
||||
offset: Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'m> MemoryReader<'m> {
|
||||
pub fn new(memory: &'m [Cell<u8>]) -> Self {
|
||||
Self { memory }
|
||||
}
|
||||
|
||||
/// Returns reader that allows read sequentially. It's important that memory limit is checked
|
||||
/// only inside this function. All others functions of the returned reader don't have any
|
||||
/// checks assuming that reader is well-formed.
|
||||
pub fn sequential_reader(
|
||||
&self,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> LiResult<SequentialReader<'_, '_>> {
|
||||
self.check_access(offset, size)?;
|
||||
|
||||
Ok(SequentialReader::new(&self, offset))
|
||||
}
|
||||
|
||||
pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> LiResult<Vec<u8>> {
|
||||
let reader = self.sequential_reader(offset, elements_count)?;
|
||||
let mut result = Vec::with_capacity(elements_count);
|
||||
|
||||
for _ in 0..elements_count {
|
||||
let value = reader.read_u8();
|
||||
result.push(value);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> LiResult<Vec<IValue>> {
|
||||
let reader = self.sequential_reader(offset, elements_count)?;
|
||||
let mut result = Vec::with_capacity(elements_count);
|
||||
|
||||
for _ in 0..elements_count {
|
||||
let value = reader.read_u8();
|
||||
result.push(IValue::Boolean(value != 0));
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn check_access(&self, offset: usize, size: usize) -> LiResult<()> {
|
||||
let right = offset + size;
|
||||
|
||||
// the first condition is a check for overflow
|
||||
if right < offset || right >= self.memory.len() {
|
||||
return Err(LiError::InvalidAccess {
|
||||
offset,
|
||||
size,
|
||||
memory_size: self.memory.len(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
read_array_ty!(read_u8_array, u8, U8);
|
||||
read_array_ty!(read_s8_array, i8, S8);
|
||||
read_array_ty!(read_u16_array, u16, U16);
|
||||
read_array_ty!(read_s16_array, i16, S16);
|
||||
read_array_ty!(read_u32_array, u32, U32);
|
||||
read_array_ty!(read_s32_array, i32, S32);
|
||||
read_array_ty!(read_i32_array, i32, I32);
|
||||
read_array_ty!(read_f32_array, f32, F32);
|
||||
read_array_ty!(read_u64_array, u64, U64);
|
||||
read_array_ty!(read_s64_array, i64, S64);
|
||||
read_array_ty!(read_i64_array, i64, I64);
|
||||
read_array_ty!(read_f64_array, f64, F64);
|
||||
}
|
||||
|
||||
impl<'r, 'm> SequentialReader<'r, 'm> {
|
||||
pub(self) fn new(reader: &'r MemoryReader<'m>, offset: usize) -> Self {
|
||||
let offset = Cell::new(offset);
|
||||
Self { reader, offset }
|
||||
}
|
||||
|
||||
pub fn read_bool(&self) -> bool {
|
||||
let offset = self.offset.get();
|
||||
let result = self.reader.memory[offset].get() != 0;
|
||||
|
||||
self.offset.set(offset + 1);
|
||||
result
|
||||
}
|
||||
|
||||
read_ty!(read_u8, u8, 1);
|
||||
read_ty!(read_i8, i8, 1);
|
||||
read_ty!(read_u16, u16, 2);
|
||||
read_ty!(read_i16, i16, 2);
|
||||
read_ty!(read_u32, u32, 4);
|
||||
read_ty!(read_i32, i32, 4);
|
||||
read_ty!(read_f32, f32, 4);
|
||||
read_ty!(read_u64, u64, 8);
|
||||
read_ty!(read_i64, i64, 8);
|
||||
read_ty!(read_f64, f64, 8);
|
||||
}
|
45
crates/it-lilo/src/lifter/mod.rs
Normal file
45
crates/it-lilo/src/lifter/mod.rs
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2021 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 error;
|
||||
mod lift_array;
|
||||
mod lift_record;
|
||||
mod macros;
|
||||
mod memory_reader;
|
||||
|
||||
pub use error::LiError;
|
||||
pub use lift_array::array_lift_memory;
|
||||
pub use lift_record::record_lift_memory;
|
||||
pub use memory_reader::MemoryReader;
|
||||
pub use memory_reader::SequentialReader;
|
||||
|
||||
use super::traits::RecordResolvable;
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
pub type LiResult<T> = std::result::Result<T, error::LiError>;
|
||||
|
||||
pub struct ILifter<'m, 'r, R: RecordResolvable> {
|
||||
pub reader: MemoryReader<'m>,
|
||||
pub resolver: &'r R,
|
||||
}
|
||||
|
||||
impl<'m, 'r, R: RecordResolvable> ILifter<'m, 'r, R> {
|
||||
pub fn new(memory: &'m [Cell<u8>], resolver: &'r R) -> Self {
|
||||
let reader = MemoryReader::new(memory);
|
||||
Self { reader, resolver }
|
||||
}
|
||||
}
|
28
crates/it-lilo/src/lowerer/error.rs
Normal file
28
crates/it-lilo/src/lowerer/error.rs
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2021 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::traits::AllocatableError;
|
||||
use crate::traits::RecordResolvableError;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum LoError {
|
||||
#[error("{0}")]
|
||||
AllocatableError(#[from] AllocatableError),
|
||||
|
||||
#[error("{0}")]
|
||||
RecordResolvableError(#[from] RecordResolvableError),
|
||||
}
|
96
crates/it-lilo/src/lowerer/lower_array.rs
Normal file
96
crates/it-lilo/src/lowerer/lower_array.rs
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2021 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 super::ILowerer;
|
||||
use super::LoResult;
|
||||
use crate::traits::Allocatable;
|
||||
use crate::utils::ser_value_size;
|
||||
use crate::utils::type_tag_form_ivalue;
|
||||
use crate::IValue;
|
||||
|
||||
pub struct LoweredArray {
|
||||
pub offset: usize,
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
impl LoweredArray {
|
||||
pub fn new(offset: usize, size: usize) -> Self {
|
||||
Self { offset, size }
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
Self { offset: 0, size: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_lower_memory<A: Allocatable>(
|
||||
lowerer: &ILowerer<'_, A>,
|
||||
array_values: Vec<IValue>,
|
||||
) -> LoResult<LoweredArray> {
|
||||
if array_values.is_empty() {
|
||||
return Ok(LoweredArray::empty());
|
||||
}
|
||||
|
||||
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(size, type_tag)?;
|
||||
|
||||
// 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(&lowerer.writer, value as _),
|
||||
IValue::S8(value) => seq_writer.write_u8(&lowerer.writer, value as _),
|
||||
IValue::S16(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::S32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::S64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::U8(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::U16(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::U32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::U64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::I32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::I64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::F32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::F64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::String(value) => {
|
||||
let offset = lowerer.writer.write_bytes(value.as_bytes())? as u32;
|
||||
|
||||
seq_writer.write_array(&lowerer.writer, offset.to_le_bytes());
|
||||
seq_writer.write_array(&lowerer.writer, (value.len() as u32).to_le_bytes());
|
||||
}
|
||||
IValue::ByteArray(values) => {
|
||||
let offset = lowerer.writer.write_bytes(&values)? as u32;
|
||||
|
||||
seq_writer.write_array(&lowerer.writer, offset.to_le_bytes());
|
||||
seq_writer.write_array(&lowerer.writer, (values.len() as u32).to_le_bytes());
|
||||
}
|
||||
IValue::Array(values) => {
|
||||
let LoweredArray { offset, size } = array_lower_memory(lowerer, values)?;
|
||||
|
||||
seq_writer.write_array(&lowerer.writer, (offset as u32).to_le_bytes());
|
||||
seq_writer.write_array(&lowerer.writer, (size as u32).to_le_bytes());
|
||||
}
|
||||
IValue::Record(values) => {
|
||||
let offset = super::record_lower_memory(lowerer, values)? as u32;
|
||||
seq_writer.write_array(&lowerer.writer, offset.to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let offset = seq_writer.start_offset();
|
||||
let lowered_array = LoweredArray::new(offset as _, elements_count as _);
|
||||
Ok(lowered_array)
|
||||
}
|
78
crates/it-lilo/src/lowerer/lower_record.rs
Normal file
78
crates/it-lilo/src/lowerer/lower_record.rs
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2021 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 super::ILowerer;
|
||||
use super::LoResult;
|
||||
use super::LoweredArray;
|
||||
use crate::traits::Allocatable;
|
||||
use crate::IValue;
|
||||
use crate::NEVec;
|
||||
|
||||
pub fn record_lower_memory<A: Allocatable>(
|
||||
lowerer: &ILowerer<'_, A>,
|
||||
values: NEVec<IValue>,
|
||||
) -> LoResult<i32> {
|
||||
let average_field_size = 4;
|
||||
// TODO: avoid this additional allocation after fixing github.com/fluencelabs/fce/issues/77
|
||||
let mut result: Vec<u8> = Vec::with_capacity(average_field_size * values.len());
|
||||
|
||||
for value in values.into_vec() {
|
||||
match value {
|
||||
IValue::Boolean(value) => result.push(value as _),
|
||||
IValue::S8(value) => result.push(value as _),
|
||||
IValue::S16(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::S32(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::S64(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::U8(value) => result.push(value),
|
||||
IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()),
|
||||
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(value.as_bytes())? as u32;
|
||||
|
||||
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(&value)? as u32;
|
||||
|
||||
result.extend_from_slice(&offset.to_le_bytes());
|
||||
result.extend_from_slice(&(value.len() as u32).to_le_bytes());
|
||||
}
|
||||
|
||||
IValue::Array(values) => {
|
||||
let LoweredArray { offset, size } = super::array_lower_memory(lowerer, values)?;
|
||||
|
||||
result.extend_from_slice(&(offset as u32).to_le_bytes());
|
||||
result.extend_from_slice(&(size as u32).to_le_bytes());
|
||||
}
|
||||
|
||||
IValue::Record(values) => {
|
||||
let offset = record_lower_memory(lowerer, values)? as u32;
|
||||
|
||||
result.extend_from_slice(&offset.to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result_pointer = lowerer.writer.write_bytes(&result)?;
|
||||
|
||||
Ok(result_pointer as _)
|
||||
}
|
128
crates/it-lilo/src/lowerer/memory_writer.rs
Normal file
128
crates/it-lilo/src/lowerer/memory_writer.rs
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2021 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 super::LoResult;
|
||||
use crate::traits::Allocatable;
|
||||
use crate::traits::MemSlice;
|
||||
use crate::traits::DEFAULT_MEMORY_INDEX;
|
||||
use crate::utils::type_tag_form_itype;
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
pub struct MemoryWriter<'i, R: Allocatable> {
|
||||
heap_manager: &'i R,
|
||||
pub(self) memory: Cell<MemSlice<'i>>,
|
||||
}
|
||||
|
||||
pub struct SequentialWriter {
|
||||
start_offset: usize,
|
||||
offset: Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'i, A: Allocatable> MemoryWriter<'i, A> {
|
||||
pub fn new(heap_manager: &'i A) -> LoResult<Self> {
|
||||
let mem_slice = heap_manager.memory_slice(DEFAULT_MEMORY_INDEX)?;
|
||||
let memory = Cell::new(mem_slice);
|
||||
|
||||
let writer = Self {
|
||||
heap_manager,
|
||||
memory,
|
||||
};
|
||||
Ok(writer)
|
||||
}
|
||||
|
||||
pub fn write_bytes(&self, bytes: &[u8]) -> LoResult<usize> {
|
||||
let byte_type_tag = type_tag_form_itype(&crate::IType::U8);
|
||||
let seq_writer = self.sequential_writer(bytes.len() as _, byte_type_tag)?;
|
||||
seq_writer.write_bytes(self, bytes);
|
||||
|
||||
Ok(seq_writer.start_offset())
|
||||
}
|
||||
|
||||
pub fn sequential_writer(&self, size: u32, type_tag: u32) -> LoResult<SequentialWriter> {
|
||||
let offset = self.heap_manager.allocate(size, type_tag)?;
|
||||
|
||||
let new_mem_slice = self.heap_manager.memory_slice(DEFAULT_MEMORY_INDEX)?;
|
||||
self.memory.set(new_mem_slice);
|
||||
|
||||
Ok(SequentialWriter::new(offset))
|
||||
}
|
||||
}
|
||||
|
||||
impl SequentialWriter {
|
||||
pub(self) fn new(offset: usize) -> Self {
|
||||
Self {
|
||||
offset: Cell::new(offset),
|
||||
start_offset: offset,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_offset(&self) -> usize {
|
||||
self.start_offset
|
||||
}
|
||||
|
||||
pub fn write_array<A: Allocatable, const N: usize>(
|
||||
&self,
|
||||
writer: &MemoryWriter<'_, A>,
|
||||
values: [u8; N],
|
||||
) {
|
||||
let offset = self.offset.get();
|
||||
|
||||
writer.memory.get()[offset..offset + N]
|
||||
.iter()
|
||||
.zip(values.iter())
|
||||
.for_each(|(cell, &byte)| cell.set(byte));
|
||||
|
||||
self.offset.set(offset + N);
|
||||
}
|
||||
|
||||
// specialization of write_array for u8
|
||||
pub fn write_u8<A: Allocatable>(&self, writer: &MemoryWriter<'_, A>, value: u8) {
|
||||
let offset = self.offset.get();
|
||||
|
||||
writer.memory.get()[offset].set(value);
|
||||
|
||||
self.offset.set(offset + 1);
|
||||
}
|
||||
|
||||
// specialization of write_array for u32
|
||||
pub fn write_u32<A: Allocatable>(&self, writer: &MemoryWriter<'_, A>, value: u32) {
|
||||
let offset = self.offset.get();
|
||||
|
||||
let value = value.to_le_bytes();
|
||||
let memory = writer.memory.get();
|
||||
|
||||
memory[offset].set(value[0]);
|
||||
memory[offset + 1].set(value[1]);
|
||||
memory[offset + 2].set(value[2]);
|
||||
memory[offset + 3].set(value[3]);
|
||||
|
||||
self.offset.set(offset + 4);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn write_bytes<A: Allocatable>(&self, writer: &MemoryWriter<'_, A>, bytes: &[u8]) {
|
||||
let offset = self.offset.get();
|
||||
|
||||
let memory = writer.memory.get();
|
||||
memory[offset..offset + bytes.len()]
|
||||
.iter()
|
||||
.zip(bytes)
|
||||
.for_each(|(cell, &byte)| cell.set(byte));
|
||||
|
||||
self.offset.set(offset + bytes.len());
|
||||
}
|
||||
}
|
43
crates/it-lilo/src/lowerer/mod.rs
Normal file
43
crates/it-lilo/src/lowerer/mod.rs
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2021 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 error;
|
||||
mod lower_array;
|
||||
mod lower_record;
|
||||
mod memory_writer;
|
||||
|
||||
use crate::lowerer::memory_writer::MemoryWriter;
|
||||
use crate::traits::Allocatable;
|
||||
|
||||
pub use error::LoError;
|
||||
pub use lower_array::array_lower_memory;
|
||||
pub use lower_array::LoweredArray;
|
||||
pub use lower_record::record_lower_memory;
|
||||
|
||||
pub type LoResult<T> = std::result::Result<T, error::LoError>;
|
||||
|
||||
pub struct ILowerer<'m, A: Allocatable> {
|
||||
pub writer: MemoryWriter<'m, A>,
|
||||
}
|
||||
|
||||
impl<'m, A: Allocatable> ILowerer<'m, A> {
|
||||
pub fn new(allocatable: &'m A) -> LoResult<Self> {
|
||||
let writer = MemoryWriter::new(allocatable)?;
|
||||
let lowerer = Self { writer };
|
||||
|
||||
Ok(lowerer)
|
||||
}
|
||||
}
|
68
crates/it-lilo/src/traits/allocatable.rs
Normal file
68
crates/it-lilo/src/traits/allocatable.rs
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2021 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::cell::Cell;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub const DEFAULT_MEMORY_INDEX: usize = 0;
|
||||
|
||||
pub type MemSlice<'m> = &'m [Cell<u8>];
|
||||
|
||||
pub trait Allocatable {
|
||||
fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError>;
|
||||
|
||||
fn memory_slice(&self, memory_index: usize) -> Result<MemSlice<'_>, AllocatableError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum AllocatableError {
|
||||
/// The memory doesn't exist.
|
||||
#[error("memory `{memory_index}` does not exist")]
|
||||
MemoryIsMissing {
|
||||
/// The memory index.
|
||||
memory_index: usize,
|
||||
},
|
||||
|
||||
/// The local or import function doesn't exist.
|
||||
#[error("the allocate function with index `{function_index}` doesn't exist in Wasm module")]
|
||||
AllocateFuncIsMissing {
|
||||
/// The local or import function index.
|
||||
function_index: u32,
|
||||
},
|
||||
|
||||
/// Failed to call a allocate function.
|
||||
#[error("call to allocated was failed")]
|
||||
AllocateCallFailed,
|
||||
|
||||
/// Allocate input types doesn't match with needed.
|
||||
#[error(
|
||||
"allocate func doesn't receive two i32 values,\
|
||||
probably a Wasm module's built with unsupported sdk version"
|
||||
)]
|
||||
AllocateFuncIncompatibleSignature,
|
||||
|
||||
/// Allocate output types doesn't match with needed.
|
||||
#[error(
|
||||
"allocate func doesn't return a one value of I32 type,\
|
||||
probably a Wasm module's built with unsupported sdk version"
|
||||
)]
|
||||
AllocateFuncIncompatibleOutput,
|
||||
|
||||
// TODO: make it generic in future.
|
||||
/// User defined error.
|
||||
#[error("{0}")]
|
||||
UserDefinedError(String),
|
||||
}
|
21
crates/it-lilo/src/traits/mod.rs
Normal file
21
crates/it-lilo/src/traits/mod.rs
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2021 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 allocatable;
|
||||
mod record_resolvable;
|
||||
|
||||
pub use allocatable::*;
|
||||
pub use record_resolvable::*;
|
29
crates/it-lilo/src/traits/record_resolvable.rs
Normal file
29
crates/it-lilo/src/traits/record_resolvable.rs
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2021 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::IRecordType;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub trait RecordResolvable {
|
||||
fn resolve_record(&self, record_type_id: u64) -> Result<&IRecordType, RecordResolvableError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum RecordResolvableError {
|
||||
/// Record for such type is wasn't found.
|
||||
#[error("Record with type id '{0}' not found")]
|
||||
RecordNotFound(u64),
|
||||
}
|
95
crates/it-lilo/src/utils.rs
Normal file
95
crates/it-lilo/src/utils.rs
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2021 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::IRecordType;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
|
||||
/// Size of a value in a serialized view.
|
||||
pub fn ser_type_size(ty: &IType) -> usize {
|
||||
const WASM_POINTER_SIZE: usize = 4;
|
||||
|
||||
match ty {
|
||||
IType::Boolean | IType::S8 | IType::U8 => 1,
|
||||
IType::S16 | IType::U16 => 2,
|
||||
IType::S32 | IType::U32 | IType::I32 | IType::F32 => 4,
|
||||
IType::Record(_) => 4,
|
||||
// Vec-like types are passed by pointer and size
|
||||
IType::String | IType::ByteArray | IType::Array(_) => 2 * WASM_POINTER_SIZE,
|
||||
IType::S64 | IType::U64 | IType::I64 | IType::F64 => 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Size of a value in a serialized view.
|
||||
pub fn ser_value_size(value: &IValue) -> u32 {
|
||||
match value {
|
||||
IValue::Boolean(_) | IValue::S8(_) | IValue::U8(_) => 1,
|
||||
IValue::S16(_) | IValue::U16(_) => 2,
|
||||
IValue::S32(_) | IValue::U32(_) | IValue::F32(_) | IValue::I32(_) => 4,
|
||||
IValue::S64(_) | IValue::U64(_) | IValue::F64(_) | IValue::I64(_) => 8,
|
||||
IValue::String(_) | IValue::ByteArray(_) | IValue::Array(_) => 2 * 4,
|
||||
IValue::Record(_) => 4,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the record size in bytes.
|
||||
pub fn record_size(record_type: &IRecordType) -> usize {
|
||||
record_type
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| ser_type_size(&f.ty))
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn type_tag_form_itype(itype: &IType) -> u32 {
|
||||
const POINTER_CODE: u32 = 3; // u32 in the sdk
|
||||
|
||||
match itype {
|
||||
IType::Boolean => 0, // u8
|
||||
IType::U8 => 1, // u8
|
||||
IType::U16 => 2, // u16
|
||||
IType::U32 => 3, // u32
|
||||
IType::U64 => 4, // u64
|
||||
IType::S8 => 5, // i8
|
||||
IType::S16 => 6, // i16
|
||||
IType::S32 | IType::I32 => 7, // i32
|
||||
IType::S64 | IType::I64 => 8, // i64
|
||||
IType::F32 => 9, // f32
|
||||
IType::F64 => 10, // f64
|
||||
IType::ByteArray | IType::Array(_) | IType::Record(_) | IType::String => POINTER_CODE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_tag_form_ivalue(itype: &IValue) -> u32 {
|
||||
const POINTER_CODE: u32 = 3; // u32 in the sdk
|
||||
|
||||
match itype {
|
||||
IValue::Boolean(_) => 0, // u8
|
||||
IValue::U8(_) => 1, // u8
|
||||
IValue::U16(_) => 2, // u16
|
||||
IValue::U32(_) => 3, // u32
|
||||
IValue::U64(_) => 4, // u64
|
||||
IValue::S8(_) => 5, // i8
|
||||
IValue::S16(_) => 6, // i16
|
||||
IValue::S32(_) | IValue::I32(_) => 7, // i32
|
||||
IValue::S64(_) | IValue::I64(_) => 8, // i64
|
||||
IValue::F32(_) => 9, // f32
|
||||
IValue::F64(_) => 10, // f64
|
||||
IValue::ByteArray(_) | IValue::Array(_) | IValue::Record(_) | IValue::String(_) => {
|
||||
POINTER_CODE
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,15 @@
|
||||
[package]
|
||||
name = "fluence-it-types"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
description = "Definitions of IValue and IType"
|
||||
authors = ["Fluence Labs"]
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[lib]
|
||||
name = "fluence_it_types"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
it-to-bytes = { path = "../to-bytes/", version = "0.1.0" }
|
||||
|
||||
|
@ -18,6 +18,7 @@ where
|
||||
{
|
||||
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
|
||||
match self {
|
||||
IType::Boolean => 0x0b_u8.to_bytes(writer),
|
||||
IType::S8 => 0x00_u8.to_bytes(writer),
|
||||
IType::S16 => 0x01_u8.to_bytes(writer),
|
||||
IType::S32 => 0x02_u8.to_bytes(writer),
|
||||
@ -29,11 +30,11 @@ where
|
||||
IType::F32 => 0x08_u8.to_bytes(writer),
|
||||
IType::F64 => 0x09_u8.to_bytes(writer),
|
||||
IType::String => 0x0a_u8.to_bytes(writer),
|
||||
IType::ByteArray => 0x3C_u8.to_bytes(writer),
|
||||
IType::Array(ty) => {
|
||||
0x36_u8.to_bytes(writer)?;
|
||||
ty.to_bytes(writer)
|
||||
}
|
||||
IType::Anyref => 0x0b_u8.to_bytes(writer),
|
||||
IType::I32 => 0x0c_u8.to_bytes(writer),
|
||||
IType::I64 => 0x0d_u8.to_bytes(writer),
|
||||
IType::Record(record_id) => {
|
||||
@ -77,6 +78,7 @@ mod keyword {
|
||||
custom_keyword!(field);
|
||||
|
||||
// New types.
|
||||
custom_keyword!(boolean);
|
||||
custom_keyword!(s8);
|
||||
custom_keyword!(s16);
|
||||
custom_keyword!(s32);
|
||||
@ -92,7 +94,11 @@ mod keyword {
|
||||
impl Parse<'_> for IType {
|
||||
fn parse(parser: Parser<'_>) -> Result<IType, ParseError> {
|
||||
let mut lookahead = parser.lookahead1();
|
||||
if lookahead.peek::<keyword::s8>() {
|
||||
if lookahead.peek::<keyword::boolean>() {
|
||||
parser.parse::<keyword::boolean>()?;
|
||||
|
||||
Ok(IType::Boolean)
|
||||
} else if lookahead.peek::<keyword::s8>() {
|
||||
parser.parse::<keyword::s8>()?;
|
||||
|
||||
Ok(IType::S8)
|
||||
@ -142,10 +148,6 @@ impl Parse<'_> for IType {
|
||||
let array_type = parser.parens(|p| p.parse())?;
|
||||
|
||||
Ok(IType::Array(Box::new(array_type)))
|
||||
} else if lookahead.peek::<keyword::anyref>() {
|
||||
parser.parse::<keyword::anyref>()?;
|
||||
|
||||
Ok(IType::Anyref)
|
||||
} else if lookahead.peek::<keyword::i32>() {
|
||||
parser.parse::<keyword::i32>()?;
|
||||
|
||||
|
@ -22,14 +22,14 @@ macro_rules! native {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&IValue> for $native_type {
|
||||
impl TryFrom<IValue> for $native_type {
|
||||
type Error = WasmValueNativeCastError;
|
||||
|
||||
fn try_from(w: &IValue) -> Result<Self, Self::Error> {
|
||||
fn try_from(w: IValue) -> Result<Self, Self::Error> {
|
||||
match w {
|
||||
IValue::$variant(n) => Ok(n.clone()),
|
||||
IValue::$variant(n) => Ok(n),
|
||||
_ => Err(WasmValueNativeCastError {
|
||||
from: w.clone(),
|
||||
from: w,
|
||||
to: <$native_type>::INTERFACE_TYPE,
|
||||
}),
|
||||
}
|
||||
@ -49,3 +49,46 @@ native!(u64, U64);
|
||||
native!(f32, F32);
|
||||
native!(f64, F64);
|
||||
native!(String, String);
|
||||
|
||||
impl NativeType for Vec<u8> {
|
||||
const INTERFACE_TYPE: IType = IType::ByteArray;
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for IValue {
|
||||
fn from(n: Vec<u8>) -> Self {
|
||||
IValue::ByteArray(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IValue> for Vec<u8> {
|
||||
type Error = WasmValueNativeCastError;
|
||||
|
||||
fn try_from(w: IValue) -> Result<Self, Self::Error> {
|
||||
match w {
|
||||
IValue::ByteArray(n) => Ok(n),
|
||||
IValue::Array(ivalues) => try_to_byte_array(ivalues),
|
||||
_ => Err(WasmValueNativeCastError {
|
||||
from: w,
|
||||
to: Vec::<u8>::INTERFACE_TYPE,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_to_byte_array(ivalues: Vec<IValue>) -> Result<Vec<u8>, WasmValueNativeCastError> {
|
||||
let mut result = Vec::with_capacity(ivalues.len());
|
||||
|
||||
for value in &ivalues {
|
||||
match value {
|
||||
IValue::U8(byte) => result.push(*byte),
|
||||
_ => {
|
||||
return Err(WasmValueNativeCastError {
|
||||
from: IValue::Array(ivalues),
|
||||
to: Vec::<u8>::INTERFACE_TYPE,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -8,6 +8,9 @@ use serde::Serialize;
|
||||
/// Represents the types supported by WIT.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
|
||||
pub enum IType {
|
||||
/// Boolean.
|
||||
Boolean,
|
||||
|
||||
/// A 8-bits signed integer.
|
||||
S8,
|
||||
|
||||
@ -41,12 +44,12 @@ pub enum IType {
|
||||
/// A string.
|
||||
String,
|
||||
|
||||
/// Specialization of arrays for byte vector.
|
||||
ByteArray,
|
||||
|
||||
/// An array of values of the same type.
|
||||
Array(Box<IType>),
|
||||
|
||||
/// An `any` reference.
|
||||
Anyref,
|
||||
|
||||
/// A 32-bits integer (as defined in WebAssembly core).
|
||||
I32,
|
||||
|
||||
@ -98,6 +101,7 @@ impl Default for RecordType {
|
||||
impl ToString for &IType {
|
||||
fn to_string(&self) -> String {
|
||||
match &self {
|
||||
IType::Boolean => "bool".to_string(),
|
||||
IType::S8 => "s8".to_string(),
|
||||
IType::S16 => "s16".to_string(),
|
||||
IType::S32 => "s32".to_string(),
|
||||
@ -109,8 +113,8 @@ impl ToString for &IType {
|
||||
IType::F32 => "f32".to_string(),
|
||||
IType::F64 => "f64".to_string(),
|
||||
IType::String => "string".to_string(),
|
||||
IType::ByteArray => "array (u8)".to_string(),
|
||||
IType::Array(ty) => format!("array ({})", ty.as_ref().to_string()),
|
||||
IType::Anyref => "anyref".to_string(),
|
||||
IType::I32 => "i32".to_string(),
|
||||
IType::I64 => "i64".to_string(),
|
||||
IType::Record(record_type_id) => format!("record {}", record_type_id),
|
||||
|
@ -5,6 +5,9 @@ use crate::ne_vec::NEVec;
|
||||
/// A WIT value.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum IValue {
|
||||
/// Boolean value.
|
||||
Boolean(bool),
|
||||
|
||||
/// A 8-bits signed integer.
|
||||
S8(i8),
|
||||
|
||||
@ -38,14 +41,16 @@ pub enum IValue {
|
||||
/// A string.
|
||||
String(String),
|
||||
|
||||
/// Specialization of array type for byte vector.
|
||||
ByteArray(Vec<u8>),
|
||||
|
||||
/// A byte array.
|
||||
Array(Vec<IValue>),
|
||||
|
||||
//Anyref(?),
|
||||
/// A 32-bits integer (as defined in WebAssembly core).
|
||||
I32(i32),
|
||||
|
||||
/// A 64-bits integer (as defiend in WebAssembly core).
|
||||
/// A 64-bits integer (as defined in WebAssembly core).
|
||||
I64(i64),
|
||||
|
||||
/// A record.
|
||||
|
@ -5,3 +5,7 @@ authors = ["Fluence Labs"]
|
||||
description = "Defines trait ToBytes used for IT serialization"
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[lib]
|
||||
name = "it_to_bytes"
|
||||
path = "src/lib.rs"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-interface-types-fl"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
description = "WebAssembly Interface Types library for Wasmer"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -8,8 +8,9 @@ repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
fluence-it-types = { path = "../crates/it-types", version = "0.1.0", features = ["impls"] }
|
||||
fluence-it-types = { path = "../crates/it-types", version = "0.2.0", features = ["impls"] }
|
||||
it-to-bytes = { path = "../crates/to-bytes", version = "0.1.0" }
|
||||
it-lilo = { path = "../crates/it-lilo", version = "0.1.0" }
|
||||
|
||||
nom = "5.1"
|
||||
wast = "8.0"
|
||||
@ -21,7 +22,9 @@ serde = { version = "1.0", features = ["derive", "rc"], optional = true }
|
||||
serde_json = "1.0"
|
||||
safe-transmute = "0.11.0"
|
||||
log = "0.4.11"
|
||||
itertools = "0.10.0"
|
||||
|
||||
thiserror = "1.0.24"
|
||||
semver = "0.11.0"
|
||||
|
||||
[features]
|
||||
|
@ -112,6 +112,7 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
|
||||
consume!((input, opcode) = byte(input)?);
|
||||
|
||||
let ty = match opcode {
|
||||
0x0b => IType::Boolean,
|
||||
0x00 => IType::S8,
|
||||
0x01 => IType::S16,
|
||||
0x02 => IType::S32,
|
||||
@ -123,12 +124,12 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
|
||||
0x08 => IType::F32,
|
||||
0x09 => IType::F64,
|
||||
0x0a => IType::String,
|
||||
0x3c => IType::ByteArray,
|
||||
0x36 => {
|
||||
consume!((input, array_value_type) = ty(input)?);
|
||||
|
||||
IType::Array(Box::new(array_value_type))
|
||||
}
|
||||
0x0b => IType::Anyref,
|
||||
0x0c => IType::I32,
|
||||
0x0d => IType::I64,
|
||||
0x0e => {
|
||||
@ -297,6 +298,10 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
||||
0x23 => (input, Instruction::StringLowerMemory),
|
||||
0x24 => (input, Instruction::StringSize),
|
||||
|
||||
0x43 => (input, Instruction::ByteArrayLiftMemory),
|
||||
0x44 => (input, Instruction::ByteArrayLowerMemory),
|
||||
0x45 => (input, Instruction::ByteArraySize),
|
||||
|
||||
0x37 => {
|
||||
consume!((input, value_type) = ty(input)?);
|
||||
|
||||
@ -307,30 +312,6 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
||||
|
||||
(input, Instruction::ArrayLowerMemory { value_type })
|
||||
}
|
||||
/*
|
||||
0x39 => (input, Instruction::ArraySize),
|
||||
|
||||
0x25 => {
|
||||
consume!((input, argument_0) = uleb(input)?);
|
||||
|
||||
(
|
||||
input,
|
||||
Instruction::RecordLift {
|
||||
type_index: argument_0 as u32,
|
||||
},
|
||||
)
|
||||
}
|
||||
0x26 => {
|
||||
consume!((input, argument_0) = uleb(input)?);
|
||||
|
||||
(
|
||||
input,
|
||||
Instruction::RecordLower {
|
||||
type_index: argument_0 as u32,
|
||||
},
|
||||
)
|
||||
}
|
||||
*/
|
||||
0x3A => {
|
||||
consume!((input, record_type_id) = uleb(input)?);
|
||||
|
||||
@ -356,6 +337,31 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
||||
|
||||
0x35 => (input, Instruction::Swap2),
|
||||
|
||||
0x3E => (input, Instruction::BoolFromI32),
|
||||
0x3F => (input, Instruction::I32FromBool),
|
||||
|
||||
0x40 => {
|
||||
consume!((input, value) = uleb(input)?);
|
||||
|
||||
(
|
||||
input,
|
||||
Instruction::PushI32 {
|
||||
value: value as i32,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
0x41 => {
|
||||
consume!((input, value) = uleb(input)?);
|
||||
|
||||
(
|
||||
input,
|
||||
Instruction::PushI64 {
|
||||
value: value as i64,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
|
||||
})
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ mod keyword {
|
||||
// Instructions.
|
||||
custom_keyword!(argument_get = "arg.get");
|
||||
custom_keyword!(call_core = "call-core");
|
||||
custom_keyword!(bool_from_i32 = "bool.from_i32");
|
||||
custom_keyword!(s8_from_i32 = "s8.from_i32");
|
||||
custom_keyword!(s8_from_i64 = "s8.from_i64");
|
||||
custom_keyword!(s16_from_i32 = "s16.from_i32");
|
||||
@ -47,14 +48,17 @@ mod keyword {
|
||||
custom_keyword!(s32_from_i64 = "s32.from_i64");
|
||||
custom_keyword!(s64_from_i32 = "s64.from_i32");
|
||||
custom_keyword!(s64_from_i64 = "s64.from_i64");
|
||||
custom_keyword!(i32_from_bool = "i32.from_bool");
|
||||
custom_keyword!(i32_from_s8 = "i32.from_s8");
|
||||
custom_keyword!(i32_from_s16 = "i32.from_s16");
|
||||
custom_keyword!(i32_from_s32 = "i32.from_s32");
|
||||
custom_keyword!(i32_from_s64 = "i32.from_s64");
|
||||
custom_keyword!(i32_push = "i32.push");
|
||||
custom_keyword!(i64_from_s8 = "i64.from_s8");
|
||||
custom_keyword!(i64_from_s16 = "i64.from_s16");
|
||||
custom_keyword!(i64_from_s32 = "i64.from_s32");
|
||||
custom_keyword!(i64_from_s64 = "i64.from_s64");
|
||||
custom_keyword!(i64_push = "i64.push");
|
||||
custom_keyword!(u8_from_i32 = "u8.from_i32");
|
||||
custom_keyword!(u8_from_i64 = "u8.from_i64");
|
||||
custom_keyword!(u16_from_i32 = "u16.from_i32");
|
||||
@ -71,9 +75,14 @@ mod keyword {
|
||||
custom_keyword!(i64_from_u16 = "i64.from_u16");
|
||||
custom_keyword!(i64_from_u32 = "i64.from_u32");
|
||||
custom_keyword!(i64_from_u64 = "i64.from_u64");
|
||||
custom_keyword!(f32_push = "f32.push");
|
||||
custom_keyword!(f64_push = "f64.push");
|
||||
custom_keyword!(string_lift_memory = "string.lift_memory");
|
||||
custom_keyword!(string_lower_memory = "string.lower_memory");
|
||||
custom_keyword!(string_size = "string.size");
|
||||
custom_keyword!(byte_array_lift_memory = "byte_array.lift_memory");
|
||||
custom_keyword!(byte_array_lower_memory = "byte_array.lower_memory");
|
||||
custom_keyword!(byte_array_size = "byte_array.size");
|
||||
custom_keyword!(array_lift_memory = "array.lift_memory");
|
||||
custom_keyword!(array_lower_memory = "array.lower_memory");
|
||||
custom_keyword!(array_size = "array.size");
|
||||
@ -151,6 +160,12 @@ impl<'a> Parse<'a> for Instruction {
|
||||
parser.parse::<keyword::i32_from_s64>()?;
|
||||
|
||||
Ok(Instruction::I32FromS64)
|
||||
} else if lookahead.peek::<keyword::i32_push>() {
|
||||
parser.parse::<keyword::i32_push>()?;
|
||||
|
||||
Ok(Instruction::PushI32 {
|
||||
value: parser.parse()?,
|
||||
})
|
||||
} else if lookahead.peek::<keyword::i64_from_s8>() {
|
||||
parser.parse::<keyword::i64_from_s8>()?;
|
||||
|
||||
@ -167,6 +182,12 @@ impl<'a> Parse<'a> for Instruction {
|
||||
parser.parse::<keyword::i64_from_s64>()?;
|
||||
|
||||
Ok(Instruction::I64FromS64)
|
||||
} else if lookahead.peek::<keyword::i64_push>() {
|
||||
parser.parse::<keyword::i64_push>()?;
|
||||
|
||||
Ok(Instruction::PushI64 {
|
||||
value: parser.parse()?,
|
||||
})
|
||||
} else if lookahead.peek::<keyword::u8_from_i32>() {
|
||||
parser.parse::<keyword::u8_from_i32>()?;
|
||||
|
||||
@ -242,6 +263,18 @@ impl<'a> Parse<'a> for Instruction {
|
||||
} else if lookahead.peek::<keyword::string_size>() {
|
||||
parser.parse::<keyword::string_size>()?;
|
||||
|
||||
Ok(Instruction::StringSize)
|
||||
} else if lookahead.peek::<keyword::byte_array_lift_memory>() {
|
||||
parser.parse::<keyword::byte_array_lift_memory>()?;
|
||||
|
||||
Ok(Instruction::StringLiftMemory)
|
||||
} else if lookahead.peek::<keyword::byte_array_lower_memory>() {
|
||||
parser.parse::<keyword::byte_array_lower_memory>()?;
|
||||
|
||||
Ok(Instruction::StringLowerMemory)
|
||||
} else if lookahead.peek::<keyword::byte_array_size>() {
|
||||
parser.parse::<keyword::byte_array_size>()?;
|
||||
|
||||
Ok(Instruction::StringSize)
|
||||
} else if lookahead.peek::<keyword::array_lift_memory>() {
|
||||
parser.parse::<keyword::array_lift_memory>()?;
|
||||
|
@ -196,6 +196,7 @@ where
|
||||
(*function_index as u64).to_bytes(writer)?;
|
||||
}
|
||||
|
||||
Instruction::BoolFromI32 => 0x3E_u8.to_bytes(writer)?,
|
||||
Instruction::S8FromI32 => 0x02_u8.to_bytes(writer)?,
|
||||
Instruction::S8FromI64 => 0x03_u8.to_bytes(writer)?,
|
||||
Instruction::S16FromI32 => 0x04_u8.to_bytes(writer)?,
|
||||
@ -204,6 +205,7 @@ where
|
||||
Instruction::S32FromI64 => 0x07_u8.to_bytes(writer)?,
|
||||
Instruction::S64FromI32 => 0x08_u8.to_bytes(writer)?,
|
||||
Instruction::S64FromI64 => 0x09_u8.to_bytes(writer)?,
|
||||
Instruction::I32FromBool => 0x3F_u8.to_bytes(writer)?,
|
||||
Instruction::I32FromS8 => 0x0a_u8.to_bytes(writer)?,
|
||||
Instruction::I32FromS16 => 0x0b_u8.to_bytes(writer)?,
|
||||
Instruction::I32FromS32 => 0x0c_u8.to_bytes(writer)?,
|
||||
@ -233,6 +235,10 @@ where
|
||||
Instruction::StringLowerMemory => 0x23_u8.to_bytes(writer)?,
|
||||
Instruction::StringSize => 0x24_u8.to_bytes(writer)?,
|
||||
|
||||
Instruction::ByteArrayLiftMemory => 0x43_u8.to_bytes(writer)?,
|
||||
Instruction::ByteArrayLowerMemory => 0x44_u8.to_bytes(writer)?,
|
||||
Instruction::ByteArraySize => 0x45_u8.to_bytes(writer)?,
|
||||
|
||||
Instruction::ArrayLiftMemory { value_type } => {
|
||||
0x37_u8.to_bytes(writer)?;
|
||||
value_type.to_bytes(writer)?
|
||||
@ -241,17 +247,6 @@ where
|
||||
0x38_u8.to_bytes(writer)?;
|
||||
value_type.to_bytes(writer)?
|
||||
}
|
||||
/*
|
||||
Instruction::ArraySize => 0x39_u8.to_bytes(writer)?,
|
||||
Instruction::RecordLift { type_index } => {
|
||||
0x25_u8.to_bytes(writer)?;
|
||||
(*type_index as u64).to_bytes(writer)?
|
||||
}
|
||||
Instruction::RecordLower { type_index } => {
|
||||
0x26_u8.to_bytes(writer)?;
|
||||
(*type_index as u64).to_bytes(writer)?
|
||||
}
|
||||
*/
|
||||
Instruction::RecordLiftMemory {
|
||||
record_type_id: type_index,
|
||||
} => {
|
||||
@ -266,6 +261,14 @@ where
|
||||
}
|
||||
Instruction::Dup => 0x34_u8.to_bytes(writer)?,
|
||||
Instruction::Swap2 => 0x35_u8.to_bytes(writer)?,
|
||||
Instruction::PushI32 { value } => {
|
||||
0x40_u8.to_bytes(writer)?;
|
||||
(*value as u64).to_bytes(writer)?
|
||||
}
|
||||
Instruction::PushI64 { value } => {
|
||||
0x41_u8.to_bytes(writer)?;
|
||||
(*value as u64).to_bytes(writer)?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -65,6 +65,7 @@ impl ToString for &Instruction {
|
||||
match self {
|
||||
Instruction::ArgumentGet { index } => format!("arg.get {}", index),
|
||||
Instruction::CallCore { function_index } => format!("call-core {}", function_index),
|
||||
Instruction::BoolFromI32 => "bool.from_i32".into(),
|
||||
Instruction::S8FromI32 => "s8.from_i32".into(),
|
||||
Instruction::S8FromI64 => "s8.from_i64".into(),
|
||||
Instruction::S16FromI32 => "s16.from_i32".into(),
|
||||
@ -73,6 +74,7 @@ impl ToString for &Instruction {
|
||||
Instruction::S32FromI64 => "s32.from_i64".into(),
|
||||
Instruction::S64FromI32 => "s64.from_i32".into(),
|
||||
Instruction::S64FromI64 => "s64.from_i64".into(),
|
||||
Instruction::I32FromBool => "i32.from_bool".into(),
|
||||
Instruction::I32FromS8 => "i32.from_s8".into(),
|
||||
Instruction::I32FromS16 => "i32.from_s16".into(),
|
||||
Instruction::I32FromS32 => "i32.from_s32".into(),
|
||||
@ -100,17 +102,17 @@ impl ToString for &Instruction {
|
||||
Instruction::StringLiftMemory => "string.lift_memory".into(),
|
||||
Instruction::StringLowerMemory => "string.lower_memory".into(),
|
||||
Instruction::StringSize => "string.size".into(),
|
||||
|
||||
Instruction::ByteArrayLiftMemory => "byte_array.lift_memory".into(),
|
||||
Instruction::ByteArrayLowerMemory => "byte_array.lower_memory".into(),
|
||||
Instruction::ByteArraySize => "byte_array.size".into(),
|
||||
|
||||
Instruction::ArrayLiftMemory { value_type } => {
|
||||
format!("array.lift_memory {}", value_type.to_string())
|
||||
}
|
||||
Instruction::ArrayLowerMemory { value_type } => {
|
||||
format!("array.lower_memory {}", value_type.to_string())
|
||||
}
|
||||
/*
|
||||
Instruction::ArraySize => "byte_array.size".into(),
|
||||
Instruction::RecordLift { type_index } => format!("record.lift {}", type_index),
|
||||
Instruction::RecordLower { type_index } => format!("record.lower {}", type_index),
|
||||
*/
|
||||
Instruction::RecordLiftMemory {
|
||||
record_type_id: type_index,
|
||||
} => format!("record.lift_memory {}", type_index),
|
||||
@ -119,6 +121,8 @@ impl ToString for &Instruction {
|
||||
} => format!("record.lower_memory {}", type_index),
|
||||
Instruction::Dup => "dup".into(),
|
||||
Instruction::Swap2 => "swap2".into(),
|
||||
Instruction::PushI32 { value } => format!("i32.push {}", value),
|
||||
Instruction::PushI64 { value } => format!("i64.push {}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,7 +358,6 @@ mod tests {
|
||||
(&IType::F32).to_string(),
|
||||
(&IType::F64).to_string(),
|
||||
(&IType::String).to_string(),
|
||||
(&IType::Anyref).to_string(),
|
||||
(&IType::I32).to_string(),
|
||||
(&IType::I64).to_string(),
|
||||
(&IType::Record(RecordType {
|
||||
|
@ -12,6 +12,10 @@ use std::{
|
||||
string::{self, ToString},
|
||||
};
|
||||
|
||||
use it_lilo::lifter::LiError;
|
||||
use it_lilo::lowerer::LoError;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub use fluence_it_types::WasmValueNativeCastError;
|
||||
|
||||
/// A type alias for instruction's results.
|
||||
@ -31,16 +35,40 @@ pub struct InstructionError {
|
||||
}
|
||||
|
||||
impl InstructionError {
|
||||
pub(crate) fn new(instruction: Instruction, error_kind: InstructionErrorKind) -> Self {
|
||||
pub(crate) fn from_error_kind(
|
||||
instruction: Instruction,
|
||||
error_kind: InstructionErrorKind,
|
||||
) -> Self {
|
||||
Self {
|
||||
instruction,
|
||||
error_kind,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_li(instruction: Instruction, li: LiError) -> Self {
|
||||
let error_kind = InstructionErrorKind::LiError(li);
|
||||
Self::from_error_kind(instruction, error_kind)
|
||||
}
|
||||
|
||||
pub(crate) fn from_lo(instruction: Instruction, lo: LoError) -> Self {
|
||||
let error_kind = InstructionErrorKind::LoError(lo);
|
||||
Self::from_error_kind(instruction, error_kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for InstructionError {}
|
||||
|
||||
/// Allows you to shorten the expression creates a new InstructionError.
|
||||
#[macro_export]
|
||||
macro_rules! instr_error {
|
||||
($instruction:expr, $error_kind:expr) => {
|
||||
Err(crate::errors::InstructionError::from_error_kind(
|
||||
$instruction,
|
||||
$error_kind,
|
||||
))
|
||||
};
|
||||
}
|
||||
|
||||
impl Display for InstructionError {
|
||||
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||
write!(
|
||||
@ -53,18 +81,21 @@ impl Display for InstructionError {
|
||||
}
|
||||
|
||||
/// The kind of instruction errors.
|
||||
#[derive(Debug)]
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum InstructionErrorKind {
|
||||
/// The instruction needs to read an invocation input at index `index`, but it's missing.
|
||||
#[error("cannot access invocation inputs #{index} because it doesn't exist")]
|
||||
InvocationInputIsMissing {
|
||||
/// The invocation input index.
|
||||
index: u32,
|
||||
},
|
||||
|
||||
/// Failed to cast from a WIT value to a native value.
|
||||
ToNative(WasmValueNativeCastError),
|
||||
#[error("failed to cast the WIT value `{0}` to its native type")]
|
||||
ToNative(#[from] WasmValueNativeCastError),
|
||||
|
||||
/// Failed to cast from `from` to `to`.
|
||||
#[error("failed to cast `{from:?}` to `{to:?}`")]
|
||||
LoweringLifting {
|
||||
/// The initial type.
|
||||
from: IType,
|
||||
@ -75,6 +106,7 @@ pub enum InstructionErrorKind {
|
||||
|
||||
/// Read a value from the stack, but it doesn't have the expected
|
||||
/// type.
|
||||
#[error("read a value `{expected_type:?}` from the stack, that can't be converted to `{received_value:?}`")]
|
||||
InvalidValueOnTheStack {
|
||||
/// The expected type.
|
||||
expected_type: IType,
|
||||
@ -85,12 +117,16 @@ pub enum InstructionErrorKind {
|
||||
|
||||
/// Need to read some values from the stack, but it doesn't
|
||||
/// contain enough data.
|
||||
#[error(
|
||||
"needed to read `{needed}` value(s) from the stack, but it doesn't contain enough data"
|
||||
)]
|
||||
StackIsTooSmall {
|
||||
/// The number of values that were needed.
|
||||
needed: usize,
|
||||
},
|
||||
|
||||
/// The local or import function doesn't exist.
|
||||
#[error("the local or import function `{function_index}` doesn't exist")]
|
||||
LocalOrImportIsMissing {
|
||||
/// The local or import function index.
|
||||
function_index: u32,
|
||||
@ -98,6 +134,12 @@ pub enum InstructionErrorKind {
|
||||
|
||||
/// Values given to a local or import function doesn't match the
|
||||
/// function signature.
|
||||
#[error(
|
||||
"the local or import function `{function_index}` has the signature\
|
||||
`{:?} -> {:?}`\
|
||||
but it received values of kind `{:?} -> {:?}`",
|
||||
.expected.0, .expected.1, .received.0, .received.1,
|
||||
)]
|
||||
LocalOrImportSignatureMismatch {
|
||||
/// The local or import function index.
|
||||
function_index: u32,
|
||||
@ -110,18 +152,21 @@ pub enum InstructionErrorKind {
|
||||
},
|
||||
|
||||
/// Failed to call a local or import function.
|
||||
#[error("failed while calling the local or import function `{function_name}`")]
|
||||
LocalOrImportCall {
|
||||
/// The local or import function name that has been called.
|
||||
function_name: String,
|
||||
},
|
||||
|
||||
/// The memory doesn't exist.
|
||||
#[error("memory `{memory_index}` does not exist")]
|
||||
MemoryIsMissing {
|
||||
/// The memory indeX.
|
||||
memory_index: u32,
|
||||
/// The memory index.
|
||||
memory_index: usize,
|
||||
},
|
||||
|
||||
/// Tried to read out of bounds of the memory.
|
||||
#[error("read out of the memory bounds (index {index} > memory length {length})")]
|
||||
MemoryOutOfBoundsAccess {
|
||||
/// The access index.
|
||||
index: usize,
|
||||
@ -131,33 +176,43 @@ pub enum InstructionErrorKind {
|
||||
},
|
||||
|
||||
/// The string contains invalid UTF-8 encoding.
|
||||
#[error("{0}")]
|
||||
String(string::FromUtf8Error),
|
||||
|
||||
/// Out of range integral type conversion attempted.
|
||||
#[error("attempted to convert `{subject}`, but it appears to be a negative value")]
|
||||
NegativeValue {
|
||||
/// The variable name that triggered the error.
|
||||
subject: &'static str,
|
||||
},
|
||||
|
||||
/// The type doesn't exist.
|
||||
#[error("the type `{type_index}` doesn't exist")]
|
||||
TypeIsMissing {
|
||||
/// The type index.
|
||||
type_index: u32,
|
||||
},
|
||||
|
||||
/// The searched by name type doesn't exist.
|
||||
/// The searched by id type doesn't exist.
|
||||
#[error("type with `{record_type_id}` is missing in a Wasm binary")]
|
||||
RecordTypeByNameIsMissing {
|
||||
/// The record type name.
|
||||
record_type_id: u64,
|
||||
},
|
||||
|
||||
/// Corrupted array's been popped from the stack.
|
||||
#[error("{0}")]
|
||||
CorruptedArray(String),
|
||||
|
||||
/// Corrupted record's been popped from the stack.
|
||||
#[error("{0}")]
|
||||
CorruptedRecord(String),
|
||||
|
||||
/// Read a type that has an unexpected type.
|
||||
#[error(
|
||||
"read a type of kind `{received_kind:?}`,\
|
||||
but the kind `{expected_kind:?}` was expected"
|
||||
)]
|
||||
InvalidTypeKind {
|
||||
/// The expected kind.
|
||||
expected_kind: TypeKind,
|
||||
@ -167,119 +222,16 @@ pub enum InstructionErrorKind {
|
||||
},
|
||||
|
||||
/// Errors related to Serialization/deserialization of record.
|
||||
#[error("serde error: {0}")]
|
||||
SerdeError(String),
|
||||
}
|
||||
|
||||
impl Error for InstructionErrorKind {}
|
||||
/// Errors related to lifting/lowering records.
|
||||
#[error("{0}")]
|
||||
LiError(#[from] LiError),
|
||||
|
||||
impl Display for InstructionErrorKind {
|
||||
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvocationInputIsMissing { index } => write!(
|
||||
formatter,
|
||||
"cannot access invocation inputs #{} because it doesn't exist",
|
||||
index
|
||||
),
|
||||
|
||||
Self::ToNative(WasmValueNativeCastError { from, .. }) => write!(
|
||||
formatter,
|
||||
"failed to cast the WIT value `{:?}` to its native type",
|
||||
from,
|
||||
),
|
||||
|
||||
Self::LoweringLifting { from, to } => {
|
||||
write!(formatter, "failed to cast `{:?}` to `{:?}`", from, to)
|
||||
}
|
||||
|
||||
Self::InvalidValueOnTheStack {
|
||||
expected_type,
|
||||
received_value,
|
||||
} => write!(
|
||||
formatter,
|
||||
"read a value `{:?}` from the stack, that can't be converted to `{:?}`",
|
||||
received_value, expected_type,
|
||||
),
|
||||
|
||||
Self::StackIsTooSmall { needed } => write!(
|
||||
formatter,
|
||||
"needed to read `{}` value(s) from the stack, but it doesn't contain enough data",
|
||||
needed
|
||||
),
|
||||
|
||||
Self::LocalOrImportIsMissing { function_index } => write!(
|
||||
formatter,
|
||||
"the local or import function `{}` doesn't exist",
|
||||
function_index
|
||||
),
|
||||
|
||||
Self::LocalOrImportSignatureMismatch { function_index, expected, received } => write!(
|
||||
formatter,
|
||||
"the local or import function `{}` has the signature `{:?} -> {:?}` but it received values of kind `{:?} -> {:?}`",
|
||||
function_index, expected.0, expected.1, received.0, received.1,
|
||||
),
|
||||
|
||||
Self::LocalOrImportCall { function_name } => write!(
|
||||
formatter,
|
||||
"failed while calling the local or import function `{}`",
|
||||
function_name
|
||||
),
|
||||
|
||||
Self::MemoryIsMissing { memory_index } => write!(
|
||||
formatter,
|
||||
"memory `{}` does not exist",
|
||||
memory_index,
|
||||
),
|
||||
|
||||
Self::MemoryOutOfBoundsAccess { index, length } => write!(
|
||||
formatter,
|
||||
"read out of the memory bounds (index {} > memory length {})",
|
||||
index, length,
|
||||
),
|
||||
|
||||
Self::String(error) => write!(formatter, "{}", error),
|
||||
|
||||
Self::NegativeValue { subject } => write!(
|
||||
formatter,
|
||||
"attempted to convert `{}` but it appears to be a negative value",
|
||||
subject
|
||||
),
|
||||
|
||||
Self::TypeIsMissing { type_index } => write!(
|
||||
formatter,
|
||||
"the type `{}` doesn't exist",
|
||||
type_index
|
||||
),
|
||||
|
||||
Self::InvalidTypeKind { expected_kind, received_kind } => write!(
|
||||
formatter,
|
||||
"read a type of kind `{:?}`, but the kind `{:?}` was expected",
|
||||
received_kind, expected_kind
|
||||
),
|
||||
|
||||
Self::RecordTypeByNameIsMissing { record_type_id: type_name } => write!(
|
||||
formatter,
|
||||
"type with `{}` is missing in a Wasm binary",
|
||||
type_name
|
||||
),
|
||||
|
||||
Self::CorruptedArray(err) => write!(
|
||||
formatter,
|
||||
"{}",
|
||||
err
|
||||
),
|
||||
|
||||
Self::CorruptedRecord(err) => write!(
|
||||
formatter,
|
||||
"{}",
|
||||
err
|
||||
),
|
||||
|
||||
Self::SerdeError(err) => write!(
|
||||
formatter,
|
||||
"serde error: {}", err,
|
||||
),
|
||||
}
|
||||
}
|
||||
/// Errors related to incorrect writing to memory.
|
||||
#[error("{0}")]
|
||||
LoError(#[from] LoError),
|
||||
}
|
||||
|
||||
impl From<(TryFromIntError, &'static str)> for InstructionErrorKind {
|
||||
|
@ -1,7 +1,5 @@
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
};
|
||||
use crate::instr_error;
|
||||
use crate::{errors::InstructionErrorKind, interpreter::Instruction};
|
||||
|
||||
executable_instruction!(
|
||||
argument_get(index: u32, instruction: Instruction) -> _ {
|
||||
@ -9,10 +7,10 @@ executable_instruction!(
|
||||
let invocation_inputs = runtime.invocation_inputs;
|
||||
|
||||
if (index as usize) >= invocation_inputs.len() {
|
||||
return Err(InstructionError::new(
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvocationInputIsMissing { index },
|
||||
));
|
||||
InstructionErrorKind::InvocationInputIsMissing { index }
|
||||
);
|
||||
}
|
||||
|
||||
log::debug!("arg.get: pushing {:?} on the stack", invocation_inputs[index as usize]);
|
||||
|
@ -1,188 +1,18 @@
|
||||
use super::read_from_instance_mem;
|
||||
use super::write_to_instance_mem;
|
||||
use super::lilo;
|
||||
|
||||
use crate::instr_error;
|
||||
use crate::interpreter::instructions::to_native;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
IType, IValue,
|
||||
};
|
||||
use it_lilo::lifter::ILifter;
|
||||
use it_lilo::lowerer::ILowerer;
|
||||
use it_lilo::lowerer::LoweredArray;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub(super) fn array_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
value_type: &IType,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
instruction: Instruction,
|
||||
) -> Result<Vec<IValue>, InstructionError>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
|
||||
+ 'instance,
|
||||
{
|
||||
use safe_transmute::guard::AllOrNothingGuard;
|
||||
use safe_transmute::transmute_many;
|
||||
use safe_transmute::transmute_vec;
|
||||
|
||||
if size == 0 {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?;
|
||||
|
||||
let result_array = match value_type {
|
||||
IType::S8 => {
|
||||
let data = transmute_vec::<u8, i8>(data).unwrap();
|
||||
data.into_iter().map(IValue::S8).collect::<Vec<_>>()
|
||||
}
|
||||
IType::S16 => {
|
||||
let data = transmute_many::<i16, AllOrNothingGuard>(&data).unwrap();
|
||||
|
||||
data.iter().map(|v| IValue::S16(*v)).collect::<Vec<_>>()
|
||||
}
|
||||
IType::S32 => {
|
||||
let data = transmute_many::<i32, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter().map(|v| IValue::S32(*v)).collect::<Vec<_>>()
|
||||
}
|
||||
IType::S64 => {
|
||||
let data = transmute_many::<i64, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter().map(|v| IValue::S64(*v)).collect::<Vec<_>>()
|
||||
}
|
||||
IType::I32 => {
|
||||
let data = transmute_many::<i32, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter().map(|v| IValue::I32(*v)).collect::<Vec<_>>()
|
||||
}
|
||||
IType::I64 => {
|
||||
let data = transmute_many::<i64, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter().map(|v| IValue::S64(*v)).collect::<Vec<_>>()
|
||||
}
|
||||
IType::U8 => data.into_iter().map(IValue::U8).collect::<Vec<_>>(),
|
||||
IType::U16 => {
|
||||
let data = transmute_many::<u16, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter().map(|v| IValue::U16(*v)).collect::<Vec<_>>()
|
||||
}
|
||||
IType::U32 => {
|
||||
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter().map(|v| IValue::U32(*v)).collect::<Vec<_>>()
|
||||
}
|
||||
IType::U64 => {
|
||||
let data = transmute_many::<u64, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter().map(|v| IValue::U64(*v)).collect::<Vec<_>>()
|
||||
}
|
||||
IType::F32 => {
|
||||
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter()
|
||||
.map(|v| IValue::F32(f32::from_bits(*v)))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
IType::F64 => {
|
||||
let data = transmute_many::<u64, AllOrNothingGuard>(&data).unwrap();
|
||||
data.iter()
|
||||
.map(|v| IValue::F64(f64::from_bits(*v)))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
IType::Anyref => unimplemented!(),
|
||||
IType::String => {
|
||||
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
|
||||
|
||||
if data.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let mut result = Vec::with_capacity(data.len() / 2);
|
||||
let mut data = data.iter();
|
||||
|
||||
while let Some(string_offset) = data.next() {
|
||||
let string_size = data.next().ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::CorruptedArray(String::from(
|
||||
"serialized array must contain even count of elements",
|
||||
)),
|
||||
)
|
||||
})?;
|
||||
|
||||
let string_mem = read_from_instance_mem(
|
||||
instance,
|
||||
instruction.clone(),
|
||||
*string_offset as _,
|
||||
*string_size as _,
|
||||
)?;
|
||||
|
||||
// TODO: check
|
||||
let string = String::from_utf8(string_mem).unwrap();
|
||||
result.push(IValue::String(string));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
IType::Array(ty) => {
|
||||
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
|
||||
|
||||
if data.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let mut result = Vec::with_capacity(data.len() / 2);
|
||||
let mut data = data.iter();
|
||||
|
||||
while let Some(array_offset) = data.next() {
|
||||
let array_size = data.next().ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::CorruptedArray(String::from(
|
||||
"serialized array must contain even count of elements",
|
||||
)),
|
||||
)
|
||||
})?;
|
||||
|
||||
let value = array_lift_memory_(
|
||||
instance,
|
||||
&*ty,
|
||||
*array_offset as _,
|
||||
*array_size as _,
|
||||
instruction.clone(),
|
||||
)?;
|
||||
|
||||
result.push(IValue::Array(value));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
IType::Record(record_type_id) => {
|
||||
let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::RecordTypeByNameIsMissing {
|
||||
record_type_id: *record_type_id,
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
|
||||
|
||||
let mut result = Vec::with_capacity(data.len());
|
||||
|
||||
for record_offset in data {
|
||||
result.push(super::record_lift_memory_(
|
||||
instance,
|
||||
record_type,
|
||||
*record_offset as _,
|
||||
instruction.clone(),
|
||||
)?);
|
||||
}
|
||||
result
|
||||
}
|
||||
};
|
||||
|
||||
Ok(result_array)
|
||||
}
|
||||
|
||||
pub(crate) fn array_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instruction: Instruction,
|
||||
value_type: IType,
|
||||
@ -199,22 +29,22 @@ where
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let offset: usize = to_native::<i32>(&inputs[0], instruction.clone())?
|
||||
let offset: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "offset").into())
|
||||
.map_err(|k| InstructionError::new(instruction.clone(), k))?;
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
|
||||
let size: usize = to_native::<i32>(&inputs[1], instruction.clone())?
|
||||
let size: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "size").into())
|
||||
.map_err(|k| InstructionError::new(instruction.clone(), k))?;
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
|
||||
log::trace!(
|
||||
"array.lift_memory: lifting memory for value type: {:?}, popped offset {}, size {}",
|
||||
@ -224,88 +54,33 @@ where
|
||||
);
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let array = array_lift_memory_(
|
||||
*instance,
|
||||
&value_type,
|
||||
offset as _,
|
||||
size as _,
|
||||
instruction.clone(),
|
||||
)?;
|
||||
|
||||
let memory_index = 0;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
let memory = memory_view.deref();
|
||||
|
||||
let li_helper = lilo::LiHelper::new(&**instance);
|
||||
let lifter = ILifter::new(memory, &li_helper);
|
||||
let array =
|
||||
it_lilo::lifter::array_lift_memory(&lifter, &value_type, offset as _, size as _)
|
||||
.map_err(|e| InstructionError::from_li(instruction.clone(), e))?;
|
||||
|
||||
log::trace!("array.lift_memory: pushing {:?} on the stack", array);
|
||||
runtime.stack.push(IValue::Array(array));
|
||||
runtime.stack.push(array);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn array_lower_memory_<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &mut Instance,
|
||||
instruction: Instruction,
|
||||
array_values: Vec<IValue>,
|
||||
) -> Result<(usize, usize), InstructionError>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let mut result: Vec<u64> = Vec::with_capacity(array_values.len());
|
||||
|
||||
// here it's known that all interface values have the same type
|
||||
for value in array_values {
|
||||
match value {
|
||||
IValue::S8(value) => result.push(value as _),
|
||||
IValue::S16(value) => result.push(value as _),
|
||||
IValue::S32(value) => result.push(value as _),
|
||||
IValue::S64(value) => result.push(value as _),
|
||||
IValue::U8(value) => result.push(value as _),
|
||||
IValue::U16(value) => result.push(value as _),
|
||||
IValue::U32(value) => result.push(value as _),
|
||||
IValue::U64(value) => result.push(value as _),
|
||||
IValue::I32(value) => result.push(value as _),
|
||||
IValue::I64(value) => result.push(value as _),
|
||||
IValue::F32(value) => result.push(value as _),
|
||||
IValue::F64(value) => result.push(value.to_bits()),
|
||||
IValue::String(value) => {
|
||||
let string_pointer = if !value.is_empty() {
|
||||
write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
result.push(string_pointer as _);
|
||||
result.push(value.len() as _);
|
||||
}
|
||||
|
||||
IValue::Array(values) => {
|
||||
let (array_offset, array_size) = if !values.is_empty() {
|
||||
array_lower_memory_(instance, instruction.clone(), values)?
|
||||
} else {
|
||||
(0, 0)
|
||||
};
|
||||
|
||||
result.push(array_offset as _);
|
||||
result.push(array_size as _);
|
||||
}
|
||||
|
||||
IValue::Record(values) => {
|
||||
let record_offset =
|
||||
super::record_lower_memory_(instance, instruction.clone(), values)?;
|
||||
result.push(record_offset as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = safe_transmute::transmute_to_bytes::<u64>(&result);
|
||||
let result_pointer = write_to_instance_mem(instance, instruction, &result)?;
|
||||
|
||||
Ok((result_pointer as _, result.len() as _))
|
||||
}
|
||||
|
||||
pub(crate) fn array_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instruction: Instruction,
|
||||
value_type: IType,
|
||||
@ -324,7 +99,7 @@ where
|
||||
move |runtime| -> _ {
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let stack_value = runtime.stack.pop1().ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)
|
||||
@ -335,16 +110,19 @@ where
|
||||
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,
|
||||
instruction.clone(),
|
||||
)?;
|
||||
super::is_value_compatible_to_type(&**instance, &value_type, &value)
|
||||
.map_err(|e| {
|
||||
InstructionError::from_error_kind(instruction.clone(), e)
|
||||
})?;
|
||||
}
|
||||
|
||||
let (offset, size) =
|
||||
array_lower_memory_(*instance, instruction.clone(), values)?;
|
||||
let lo_helper = lilo::LoHelper::new(&**instance);
|
||||
let lowerer = ILowerer::new(&lo_helper)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
let LoweredArray { offset, size } =
|
||||
it_lilo::lowerer::array_lower_memory(&lowerer, values)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
log::trace!(
|
||||
"array.lower_memory: pushing {}, {} on the stack",
|
||||
@ -356,13 +134,34 @@ where
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(InstructionError::new(
|
||||
IValue::ByteArray(bytearray) => {
|
||||
let lo_helper = lilo::LoHelper::new(&**instance);
|
||||
let lowerer = ILowerer::new(&lo_helper)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
let offset = lowerer
|
||||
.writer
|
||||
.write_bytes(&bytearray)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
let size = bytearray.len();
|
||||
|
||||
log::trace!(
|
||||
"array.lower_memory: pushing bytes {}, {} on the stack",
|
||||
offset,
|
||||
size
|
||||
);
|
||||
runtime.stack.push(IValue::I32(offset as _));
|
||||
runtime.stack.push(IValue::I32(size as _));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::Array(Box::new(value_type.clone())),
|
||||
received_value: stack_value.clone(),
|
||||
},
|
||||
)),
|
||||
received_value: stack_value.clone()
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
179
wasmer-it/src/interpreter/instructions/byte_arrays.rs
Normal file
179
wasmer-it/src/interpreter/instructions/byte_arrays.rs
Normal file
@ -0,0 +1,179 @@
|
||||
use super::to_native;
|
||||
use crate::instr_error;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
};
|
||||
|
||||
use std::{cell::Cell, convert::TryInto};
|
||||
|
||||
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 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let memory_index = 0;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?;
|
||||
|
||||
let pointer: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "pointer").into())
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
let length: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "length").into())
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
|
||||
let memory_view = memory.view();
|
||||
|
||||
if length == 0 {
|
||||
runtime.stack.push(IValue::ByteArray(vec![]));
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if memory_view.len() < pointer + length {
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryOutOfBoundsAccess {
|
||||
index: pointer + length,
|
||||
length: memory_view.len(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let data: Vec<u8> = (&memory_view[pointer..pointer + length])
|
||||
.iter()
|
||||
.map(Cell::get)
|
||||
.collect();
|
||||
|
||||
log::debug!("byte_array.lift_memory: pushing {:?} on the stack", data);
|
||||
runtime.stack.push(IValue::ByteArray(data));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
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 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let array_pointer: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "pointer").into())
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
let array: Vec<u8> = to_native(inputs.remove(0), instruction.clone())?;
|
||||
let length: i32 = array.len().try_into().map_err(|_| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::NegativeValue { subject: "array_length" },
|
||||
)
|
||||
})?;
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index = 0;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
for (nth, byte) in array.iter().enumerate() {
|
||||
memory_view[array_pointer as usize + nth].set(*byte);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
byte_array_size(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
match runtime.stack.pop1() {
|
||||
Some(IValue::ByteArray(array)) => {
|
||||
let length = array.len() as i32;
|
||||
|
||||
log::debug!("byte_array.size: pushing {} on the stack", length);
|
||||
runtime.stack.push(IValue::I32(length));
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
||||
Some(IValue::Array(array)) => {
|
||||
let array = check_array_type(array, &instruction)?;
|
||||
|
||||
let length = array.len() as i32;
|
||||
|
||||
log::debug!("byte_array.size: pushing {} on the stack", length);
|
||||
runtime.stack.push(IValue::I32(length));
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
||||
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 }
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
fn check_array_type(
|
||||
ivalues: Vec<IValue>,
|
||||
instruction: &Instruction,
|
||||
) -> Result<Vec<IValue>, InstructionError> {
|
||||
if ivalues.is_empty() {
|
||||
return Ok(ivalues);
|
||||
}
|
||||
|
||||
match &ivalues[0] {
|
||||
IValue::U8(_) => Ok(ivalues),
|
||||
_ => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::ByteArray,
|
||||
received_value: IValue::Array(ivalues),
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ executable_instruction!(
|
||||
let index = FunctionIndex::new(function_index as usize);
|
||||
|
||||
let local_or_import = instance.local_or_import(index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LocalOrImportIsMissing {
|
||||
function_index,
|
||||
@ -21,7 +21,7 @@ executable_instruction!(
|
||||
let inputs_cardinality = local_or_import.inputs_cardinality();
|
||||
|
||||
let inputs = runtime.stack.pop(inputs_cardinality).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall {
|
||||
needed: inputs_cardinality,
|
||||
@ -29,12 +29,13 @@ executable_instruction!(
|
||||
)
|
||||
})?;
|
||||
|
||||
super::check_function_signature(&**instance, local_or_import, &inputs, instruction.clone())?;
|
||||
super::check_function_signature(&**instance, local_or_import, &inputs)
|
||||
.map_err(|e| InstructionError::from_error_kind(instruction.clone(), e))?;
|
||||
|
||||
log::debug!("call-core: calling {} with arguments: {:?}", local_or_import.name(), inputs);
|
||||
|
||||
let outputs = local_or_import.call(&inputs).map_err(|_| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LocalOrImportCall {
|
||||
function_name: local_or_import.name().to_string(),
|
||||
|
@ -7,7 +7,7 @@ executable_instruction!(
|
||||
dup(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let value = runtime.stack.peek1().ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)
|
||||
|
61
wasmer-it/src/interpreter/instructions/lilo/li_helper.rs
Normal file
61
wasmer-it/src/interpreter/instructions/lilo/li_helper.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use crate::interpreter::wasm;
|
||||
use crate::IRecordType;
|
||||
|
||||
use it_lilo::traits::RecordResolvable;
|
||||
use it_lilo::traits::RecordResolvableError;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
pub(crate) instance: &'i Instance,
|
||||
_export: PhantomData<Export>,
|
||||
_local_import: PhantomData<LocalImport>,
|
||||
_memory: PhantomData<Memory>,
|
||||
_memory_view: PhantomData<MemoryView>,
|
||||
}
|
||||
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
pub(crate) fn new(instance: &'i Instance) -> Self {
|
||||
Self {
|
||||
instance,
|
||||
_export: PhantomData,
|
||||
_local_import: PhantomData,
|
||||
_memory: PhantomData,
|
||||
_memory_view: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView> RecordResolvable
|
||||
for LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
fn resolve_record(&self, record_type_id: u64) -> Result<&IRecordType, RecordResolvableError> {
|
||||
let record = self
|
||||
.instance
|
||||
.wit_record_by_id(record_type_id)
|
||||
.ok_or(RecordResolvableError::RecordNotFound(record_type_id))?;
|
||||
|
||||
Ok(record)
|
||||
}
|
||||
}
|
97
wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs
Normal file
97
wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use crate::interpreter::wasm;
|
||||
use crate::interpreter::wasm::structures::FunctionIndex;
|
||||
use crate::IValue;
|
||||
|
||||
use it_lilo::traits::Allocatable;
|
||||
use it_lilo::traits::AllocatableError;
|
||||
use it_lilo::traits::MemSlice;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
pub(crate) instance: &'i Instance,
|
||||
_export: PhantomData<Export>,
|
||||
_local_import: PhantomData<LocalImport>,
|
||||
_memory: PhantomData<Memory>,
|
||||
_memory_view: PhantomData<MemoryView>,
|
||||
}
|
||||
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
pub(crate) fn new(instance: &'i Instance) -> Self {
|
||||
Self {
|
||||
instance,
|
||||
_export: PhantomData,
|
||||
_local_import: PhantomData,
|
||||
_memory: PhantomData,
|
||||
_memory_view: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView> Allocatable
|
||||
for LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError> {
|
||||
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 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(&inputs)
|
||||
.map_err(|_| AllocateCallFailed)?;
|
||||
|
||||
if outcome.len() != 1 {
|
||||
return Err(AllocateFuncIncompatibleOutput);
|
||||
}
|
||||
|
||||
match outcome[0] {
|
||||
IValue::I32(offset) => Ok(offset as _),
|
||||
_ => Err(AllocateFuncIncompatibleOutput),
|
||||
}
|
||||
}
|
||||
|
||||
fn memory_slice(&self, memory_index: usize) -> Result<MemSlice<'_>, AllocatableError> {
|
||||
self.instance
|
||||
.memory_slice(memory_index)
|
||||
.ok_or(AllocatableError::MemoryIsMissing { memory_index })
|
||||
}
|
||||
}
|
5
wasmer-it/src/interpreter/instructions/lilo/mod.rs
Normal file
5
wasmer-it/src/interpreter/instructions/lilo/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
mod li_helper;
|
||||
mod lo_helper;
|
||||
|
||||
pub(crate) use li_helper::LiHelper;
|
||||
pub(crate) use lo_helper::LoHelper;
|
@ -1,12 +1,14 @@
|
||||
mod argument_get;
|
||||
mod arrays;
|
||||
mod byte_arrays;
|
||||
mod call_core;
|
||||
mod dup;
|
||||
pub(self) mod lilo;
|
||||
mod numbers;
|
||||
mod push;
|
||||
mod records;
|
||||
mod strings;
|
||||
mod swap2;
|
||||
mod utils;
|
||||
|
||||
use crate::errors::{
|
||||
InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError,
|
||||
@ -15,15 +17,17 @@ use crate::interpreter::wasm;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::NEVec;
|
||||
|
||||
pub(crate) use argument_get::argument_get;
|
||||
pub(crate) use arrays::*;
|
||||
pub(crate) use byte_arrays::*;
|
||||
pub(crate) use call_core::call_core;
|
||||
pub(crate) use dup::dup;
|
||||
pub(crate) use numbers::*;
|
||||
pub(crate) use push::*;
|
||||
pub(crate) use records::*;
|
||||
pub(crate) use strings::*;
|
||||
pub(crate) use swap2::swap2;
|
||||
pub(self) use utils::*;
|
||||
|
||||
use fluence_it_types::NativeType;
|
||||
use serde::Deserialize;
|
||||
@ -48,6 +52,9 @@ pub enum Instruction {
|
||||
function_index: u32,
|
||||
},
|
||||
|
||||
/// The bool.from_i32` instruction.
|
||||
BoolFromI32,
|
||||
|
||||
/// The `s8.from_i32` instruction.
|
||||
S8FromI32,
|
||||
|
||||
@ -72,6 +79,9 @@ pub enum Instruction {
|
||||
/// The `s64.from_i64` instruction.
|
||||
S64FromI64,
|
||||
|
||||
/// The i32.from_bool instruction.
|
||||
I32FromBool,
|
||||
|
||||
/// The `i32.from_s8` instruction.
|
||||
I32FromS8,
|
||||
|
||||
@ -150,6 +160,15 @@ pub enum Instruction {
|
||||
/// The `string.lower_memory` instruction.
|
||||
StringLowerMemory,
|
||||
|
||||
/// The `byte_array.size` instruction.
|
||||
ByteArraySize,
|
||||
|
||||
/// The `byte_array.lift_memory` instruction.
|
||||
ByteArrayLiftMemory,
|
||||
|
||||
/// The `byte_array.lower_memory` instruction.
|
||||
ByteArrayLowerMemory,
|
||||
|
||||
/// The `string.size` instruction.
|
||||
StringSize,
|
||||
|
||||
@ -165,20 +184,6 @@ pub enum Instruction {
|
||||
value_type: IType,
|
||||
},
|
||||
|
||||
/*
|
||||
/// The `record.lift` instruction.
|
||||
RecordLift {
|
||||
/// The type index of the record.
|
||||
type_index: u32,
|
||||
},
|
||||
|
||||
/// The `record.lower` instruction.
|
||||
RecordLower {
|
||||
/// The type index of the record.
|
||||
type_index: u32,
|
||||
},
|
||||
|
||||
*/
|
||||
/// The `record.lift_memory` instruction.
|
||||
RecordLiftMemory {
|
||||
/// The type index of the record.
|
||||
@ -191,6 +196,18 @@ pub enum Instruction {
|
||||
record_type_id: u32,
|
||||
},
|
||||
|
||||
/// The `i32.push` instruction.
|
||||
PushI32 {
|
||||
/// The value that should be pushed on the stack.
|
||||
value: i32,
|
||||
},
|
||||
|
||||
/// The `i64.push` instruction.
|
||||
PushI64 {
|
||||
/// The value that should be pushed on the stack.
|
||||
value: i64,
|
||||
},
|
||||
|
||||
/// The `dup` instructions.
|
||||
Dup,
|
||||
|
||||
@ -200,15 +217,13 @@ pub enum Instruction {
|
||||
|
||||
/// Just a short helper to map the error of a cast from an
|
||||
/// `IValue` to a native value.
|
||||
pub(crate) fn to_native<'a, T>(
|
||||
wit_value: &'a IValue,
|
||||
instruction: Instruction,
|
||||
) -> InstructionResult<T>
|
||||
pub(crate) fn to_native<'a, T>(wit_value: IValue, instruction: Instruction) -> InstructionResult<T>
|
||||
where
|
||||
T: NativeType + TryFrom<&'a IValue, Error = WasmValueNativeCastError>,
|
||||
T: NativeType + TryFrom<IValue, Error = WasmValueNativeCastError>,
|
||||
{
|
||||
T::try_from(wit_value)
|
||||
.map_err(|error| InstructionError::new(instruction, InstructionErrorKind::ToNative(error)))
|
||||
T::try_from(wit_value).map_err(|error| {
|
||||
InstructionError::from_error_kind(instruction, InstructionErrorKind::ToNative(error))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn check_function_signature<
|
||||
@ -222,8 +237,7 @@ pub(crate) fn check_function_signature<
|
||||
instance: &'instance Instance,
|
||||
local_import: &LocalImport,
|
||||
values: &[IValue],
|
||||
instruction: Instruction,
|
||||
) -> Result<(), InstructionError>
|
||||
) -> Result<(), InstructionErrorKind>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
@ -234,7 +248,7 @@ where
|
||||
let func_inputs = local_import.arguments();
|
||||
|
||||
for (func_input_arg, value) in func_inputs.iter().zip(values.iter()) {
|
||||
is_value_compatible_to_type(instance, &func_input_arg.ty, value, instruction.clone())?;
|
||||
is_value_compatible_to_type(instance, &func_input_arg.ty, value)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -252,8 +266,7 @@ pub(crate) fn is_value_compatible_to_type<
|
||||
instance: &'instance Instance,
|
||||
interface_type: &IType,
|
||||
interface_value: &IValue,
|
||||
instruction: Instruction,
|
||||
) -> Result<(), InstructionError>
|
||||
) -> Result<(), InstructionErrorKind>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
@ -262,6 +275,7 @@ where
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
match (&interface_type, interface_value) {
|
||||
(IType::Boolean, IValue::Boolean(_)) => Ok(()),
|
||||
(IType::S8, IValue::S8(_)) => Ok(()),
|
||||
(IType::S16, IValue::S16(_)) => Ok(()),
|
||||
(IType::S32, IValue::S32(_)) => Ok(()),
|
||||
@ -275,30 +289,40 @@ where
|
||||
(IType::F32, IValue::F32(_)) => Ok(()),
|
||||
(IType::F64, IValue::F64(_)) => Ok(()),
|
||||
(IType::String, IValue::String(_)) => Ok(()),
|
||||
(IType::ByteArray, IValue::ByteArray(_)) => Ok(()),
|
||||
(IType::Array(ty), IValue::Array(values)) => {
|
||||
for value in values {
|
||||
is_value_compatible_to_type(instance, ty, value, instruction.clone())?
|
||||
is_value_compatible_to_type(instance, ty, value)?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
(IType::Record(ref record_type_id), IValue::Record(record_fields)) => {
|
||||
is_record_fields_compatible_to_type(
|
||||
instance,
|
||||
*record_type_id,
|
||||
record_fields,
|
||||
instruction,
|
||||
)?;
|
||||
(IType::ByteArray, IValue::Array(values)) => {
|
||||
for value in values {
|
||||
is_value_compatible_to_type(instance, &IType::U8, value)?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
(IType::Array(ty), IValue::ByteArray(_)) => {
|
||||
if ty.as_ref() == &IType::U8 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: interface_type.clone(),
|
||||
received_value: interface_value.clone(),
|
||||
},
|
||||
)),
|
||||
})
|
||||
}
|
||||
(IType::Record(ref record_type_id), IValue::Record(record_fields)) => {
|
||||
is_record_fields_compatible_to_type(instance, *record_type_id, record_fields)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: interface_type.clone(),
|
||||
received_value: interface_value.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,8 +337,7 @@ pub(crate) fn is_record_fields_compatible_to_type<
|
||||
instance: &'instance Instance,
|
||||
record_type_id: u64,
|
||||
record_fields: &[IValue],
|
||||
instruction: Instruction,
|
||||
) -> Result<(), InstructionError>
|
||||
) -> Result<(), InstructionErrorKind>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
@ -322,33 +345,22 @@ where
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id },
|
||||
)
|
||||
})?;
|
||||
let record_type = instance
|
||||
.wit_record_by_id(record_type_id)
|
||||
.ok_or(InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id })?;
|
||||
|
||||
if record_fields.len() != record_type.fields.len() {
|
||||
return Err(InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::Record(record_type_id),
|
||||
// unwrap is safe here - len's been already checked
|
||||
received_value: IValue::Record(NEVec::new(record_fields.to_vec()).unwrap()),
|
||||
},
|
||||
));
|
||||
return Err(InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::Record(record_type_id),
|
||||
// unwrap is safe here - len's been already checked
|
||||
received_value: IValue::Record(NEVec::new(record_fields.to_vec()).unwrap()),
|
||||
});
|
||||
}
|
||||
|
||||
for (record_type_field, record_value_field) in
|
||||
record_type.fields.iter().zip(record_fields.iter())
|
||||
{
|
||||
is_value_compatible_to_type(
|
||||
instance,
|
||||
&record_type_field.ty,
|
||||
record_value_field,
|
||||
instruction.clone(),
|
||||
)?;
|
||||
is_value_compatible_to_type(instance, &record_type_field.ty, record_value_field)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1,9 +1,11 @@
|
||||
use crate::instr_error;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
};
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
macro_rules! lowering_lifting {
|
||||
@ -18,7 +20,7 @@ macro_rules! lowering_lifting {
|
||||
.push({
|
||||
let converted_value = IValue::$to_variant(value.try_into().map_err(
|
||||
|_| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LoweringLifting {
|
||||
from: IType::$from_variant,
|
||||
@ -34,20 +36,20 @@ macro_rules! lowering_lifting {
|
||||
})
|
||||
}
|
||||
Some(wrong_value) => {
|
||||
return Err(InstructionError::new(
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::$from_variant,
|
||||
received_value: wrong_value,
|
||||
}
|
||||
))
|
||||
)
|
||||
},
|
||||
|
||||
None => {
|
||||
return Err(InstructionError::new(
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
))
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,6 +68,7 @@ lowering_lifting!(s32_from_i32, "s32.from_i32", S32, I32);
|
||||
lowering_lifting!(s32_from_i64, "s32.from_i64", S32, I64);
|
||||
lowering_lifting!(s64_from_i32, "s64.from_i32", S64, I32);
|
||||
lowering_lifting!(s64_from_i64, "s64.from_i64", S64, I64);
|
||||
lowering_lifting!(i32_from_bool, "i32.from_bool", I32, Boolean);
|
||||
lowering_lifting!(i32_from_s8, "i32.from_s8", I32, S8);
|
||||
lowering_lifting!(i32_from_s16, "i32.from_s16", I32, S16);
|
||||
lowering_lifting!(i32_from_s32, "i32.from_s32", I32, S32);
|
||||
@ -91,6 +94,44 @@ 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!(
|
||||
bool_from_i32(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
match runtime.stack.pop1() {
|
||||
Some(IValue::I32(value)) => {
|
||||
runtime
|
||||
.stack
|
||||
.push({
|
||||
let converted_value = IValue::Boolean(value != 0);
|
||||
|
||||
log::trace!("bool.from_i32: converting {:?} to {:?}" , value, converted_value);
|
||||
|
||||
converted_value
|
||||
})
|
||||
}
|
||||
Some(wrong_value) => {
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::I32,
|
||||
received_value: wrong_value,
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
None => {
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
test_executable_instruction!(
|
||||
|
25
wasmer-it/src/interpreter/instructions/push.rs
Normal file
25
wasmer-it/src/interpreter/instructions/push.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use crate::IValue;
|
||||
|
||||
executable_instruction!(
|
||||
push_i32(value: i32) -> _ {
|
||||
move |runtime| -> _ {
|
||||
|
||||
log::trace!("push_i32: push {} on the stack", value);
|
||||
runtime.stack.push(IValue::I32(value));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
push_i64(value: i64) -> _ {
|
||||
move |runtime| -> _ {
|
||||
|
||||
log::trace!("push_i32: push {} on the stack", value);
|
||||
runtime.stack.push(IValue::I64(value));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
@ -1,248 +1,15 @@
|
||||
use super::read_from_instance_mem;
|
||||
use super::write_to_instance_mem;
|
||||
|
||||
use super::lilo;
|
||||
use crate::instr_error;
|
||||
use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native};
|
||||
use crate::IRecordType;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::NEVec;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
};
|
||||
use crate::{errors::InstructionError, errors::InstructionErrorKind, interpreter::Instruction};
|
||||
|
||||
use it_lilo::lifter::ILifter;
|
||||
use it_lilo::lowerer::ILowerer;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
/*
|
||||
/// Build an `IValue::Record` based on values on the stack.
|
||||
///
|
||||
/// To fill a record, every field `field_1` to `field_n` must get its
|
||||
/// value from the stack with `value_1` to `value_n`. It is not
|
||||
/// possible to use `Stack::pop` because the one-pass algorithm does
|
||||
/// not know exactly the number of values to read from the stack
|
||||
/// ahead-of-time, so `Stack::pop1` is used. It implies that values
|
||||
/// are read one after the other from the stack, in a natural reverse
|
||||
/// order, from `value_n` to `value_1`. Thus, the `values` vector must
|
||||
/// be filled from the end to the beginning. It is not safely possible
|
||||
/// to fill the `values` vector with empty values though (so that it
|
||||
/// is possible to access to last positions). So a `VecDeque` type is
|
||||
/// used: it is a double-ended queue.
|
||||
fn record_lift_(
|
||||
stack: &mut Stack<IValue>,
|
||||
record_type: &RecordType,
|
||||
) -> Result<IValue, InstructionErrorKind> {
|
||||
let length = record_type.fields.len();
|
||||
let mut values = VecDeque::with_capacity(length);
|
||||
for field in record_type.fields.iter().rev() {
|
||||
match field {
|
||||
IType::Record(record_type) => {
|
||||
values.push_front(record_lift_(stack, &record_type)?)
|
||||
}
|
||||
ty => {
|
||||
let value = stack.pop1().unwrap();
|
||||
let value_type = (&value).into();
|
||||
if ty != &value_type {
|
||||
return Err(InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: ty.clone(),
|
||||
received_type: value_type,
|
||||
});
|
||||
}
|
||||
values.push_front(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(IValue::Record(
|
||||
NEVec::new(values.into_iter().collect())
|
||||
.expect("Record must have at least one field, zero given"),
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn record_lift<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
type_index: u32,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let instance = &runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::TypeIsMissing { type_index },
|
||||
)
|
||||
})? {
|
||||
Type::Record(record_type) => record_type,
|
||||
Type::Function { .. } => {
|
||||
return Err(InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidTypeKind {
|
||||
expected_kind: TypeKind::Record,
|
||||
received_kind: TypeKind::Function,
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
let record = record_lift_(&mut runtime.stack, &record_type)
|
||||
.map_err(|k| InstructionError::new(instruction.clone(), k))?;
|
||||
runtime.stack.push(record);
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
pub(super) fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
record_type: &IRecordType,
|
||||
offset: usize,
|
||||
instruction: Instruction,
|
||||
) -> Result<IValue, InstructionError>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
|
||||
+ 'instance,
|
||||
{
|
||||
fn record_size(record_type: &IRecordType) -> usize {
|
||||
let mut record_size = 0;
|
||||
|
||||
for field_type in record_type.fields.iter() {
|
||||
let params_count = match field_type.ty {
|
||||
IType::String | IType::Array(_) => 2,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
record_size += std::mem::size_of::<u64>() * params_count;
|
||||
}
|
||||
|
||||
record_size
|
||||
}
|
||||
|
||||
let length = record_type.fields.len();
|
||||
let mut values = Vec::with_capacity(length);
|
||||
let size = record_size(record_type);
|
||||
let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?;
|
||||
// TODO: add error handling
|
||||
let data =
|
||||
safe_transmute::transmute_many::<u64, safe_transmute::SingleManyGuard>(&data).unwrap();
|
||||
|
||||
let mut field_id = 0;
|
||||
for field in (*record_type.fields).iter() {
|
||||
let value = data[field_id];
|
||||
match &field.ty {
|
||||
IType::S8 => {
|
||||
values.push(IValue::S8(value as _));
|
||||
}
|
||||
IType::S16 => {
|
||||
values.push(IValue::S16(value as _));
|
||||
}
|
||||
IType::S32 => {
|
||||
values.push(IValue::S32(value as _));
|
||||
}
|
||||
IType::S64 => {
|
||||
values.push(IValue::S64(value as _));
|
||||
}
|
||||
IType::I32 => {
|
||||
values.push(IValue::I32(value as _));
|
||||
}
|
||||
IType::I64 => {
|
||||
values.push(IValue::I64(value as _));
|
||||
}
|
||||
IType::U8 => {
|
||||
values.push(IValue::U8(value as _));
|
||||
}
|
||||
IType::U16 => {
|
||||
values.push(IValue::U16(value as _));
|
||||
}
|
||||
IType::U32 => {
|
||||
values.push(IValue::U32(value as _));
|
||||
}
|
||||
IType::U64 => {
|
||||
values.push(IValue::U64(value as _));
|
||||
}
|
||||
IType::F32 => {
|
||||
values.push(IValue::F32(value as _));
|
||||
}
|
||||
IType::F64 => values.push(IValue::F64(f64::from_bits(value))),
|
||||
IType::Anyref => {}
|
||||
IType::String => {
|
||||
let string_offset = value;
|
||||
field_id += 1;
|
||||
let string_size = data[field_id];
|
||||
|
||||
if string_size != 0 {
|
||||
let string_mem = read_from_instance_mem(
|
||||
instance,
|
||||
instruction.clone(),
|
||||
string_offset as _,
|
||||
string_size as _,
|
||||
)?;
|
||||
|
||||
// TODO: check
|
||||
let string = String::from_utf8(string_mem).unwrap();
|
||||
values.push(IValue::String(string));
|
||||
} else {
|
||||
values.push(IValue::String(String::new()));
|
||||
}
|
||||
}
|
||||
IType::Array(ty) => {
|
||||
let array_offset = value;
|
||||
field_id += 1;
|
||||
let array_size = data[field_id];
|
||||
|
||||
if array_size != 0 {
|
||||
let array = super::array_lift_memory_(
|
||||
instance,
|
||||
&**ty,
|
||||
array_offset as _,
|
||||
array_size as _,
|
||||
instruction.clone(),
|
||||
)?;
|
||||
values.push(IValue::Array(array));
|
||||
} else {
|
||||
values.push(IValue::Array(vec![]));
|
||||
}
|
||||
}
|
||||
IType::Record(record_type_id) => {
|
||||
let offset = value;
|
||||
|
||||
let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::RecordTypeByNameIsMissing {
|
||||
record_type_id: *record_type_id,
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
values.push(record_lift_memory_(
|
||||
instance,
|
||||
record_type,
|
||||
offset as _,
|
||||
instruction.clone(),
|
||||
)?)
|
||||
}
|
||||
}
|
||||
field_id += 1;
|
||||
}
|
||||
|
||||
Ok(IValue::Record(
|
||||
NEVec::new(values.into_iter().collect())
|
||||
.expect("Record must have at least one field, zero given"),
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn record_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
record_type_id: u64,
|
||||
instruction: Instruction,
|
||||
@ -259,22 +26,22 @@ where
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let inputs = runtime.stack.pop(1).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
let mut inputs = runtime.stack.pop(1).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let offset: usize = to_native::<i32>(&inputs[0], instruction.clone())?
|
||||
let offset: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "offset").into())
|
||||
.map_err(|k| InstructionError::new(instruction.clone(), k))?;
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
|
||||
// TODO: size = 0
|
||||
let instance = &runtime.wasm_instance;
|
||||
let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id },
|
||||
)
|
||||
@ -286,8 +53,22 @@ where
|
||||
record_type_id
|
||||
);
|
||||
|
||||
let record =
|
||||
record_lift_memory_(&**instance, record_type, offset, instruction.clone())?;
|
||||
let memory_index = 0;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
let memory = memory_view.deref();
|
||||
|
||||
let li_helper = lilo::LiHelper::new(&**instance);
|
||||
let lifter = ILifter::new(memory, &li_helper);
|
||||
let record = it_lilo::lifter::record_lift_memory(&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);
|
||||
@ -297,71 +78,6 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn record_lower_memory_<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &mut Instance,
|
||||
instruction: Instruction,
|
||||
values: NEVec<IValue>,
|
||||
) -> Result<i32, InstructionError>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let mut result: Vec<u64> = Vec::with_capacity(values.len());
|
||||
|
||||
for value in values.into_vec() {
|
||||
match value {
|
||||
IValue::S8(value) => result.push(value as _),
|
||||
IValue::S16(value) => result.push(value as _),
|
||||
IValue::S32(value) => result.push(value as _),
|
||||
IValue::S64(value) => result.push(value as _),
|
||||
IValue::U8(value) => result.push(value as _),
|
||||
IValue::U16(value) => result.push(value as _),
|
||||
IValue::U32(value) => result.push(value as _),
|
||||
IValue::U64(value) => result.push(value as _),
|
||||
IValue::I32(value) => result.push(value as _),
|
||||
IValue::I64(value) => result.push(value as _),
|
||||
IValue::F32(value) => result.push(value as _),
|
||||
IValue::F64(value) => result.push(value.to_bits()),
|
||||
IValue::String(value) => {
|
||||
let string_pointer = if !value.is_empty() {
|
||||
write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
result.push(string_pointer as _);
|
||||
result.push(value.len() as _);
|
||||
}
|
||||
|
||||
IValue::Array(values) => {
|
||||
let (offset, size) = if !values.is_empty() {
|
||||
super::array_lower_memory_(instance, instruction.clone(), values)?
|
||||
} else {
|
||||
(0, 0)
|
||||
};
|
||||
|
||||
result.push(offset as _);
|
||||
result.push(size as _);
|
||||
}
|
||||
|
||||
IValue::Record(values) => {
|
||||
let record_ptr = record_lower_memory_(instance, instruction.clone(), values)?;
|
||||
|
||||
result.push(record_ptr as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = safe_transmute::transmute_to_bytes::<u64>(&result);
|
||||
let result_pointer = write_to_instance_mem(instance, instruction, &result)?;
|
||||
|
||||
Ok(result_pointer as _)
|
||||
}
|
||||
|
||||
pub(crate) fn record_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
record_type_id: u64,
|
||||
instruction: Instruction,
|
||||
@ -386,93 +102,35 @@ where
|
||||
&**instance,
|
||||
record_type_id,
|
||||
&record_fields,
|
||||
instruction.clone(),
|
||||
)?;
|
||||
)
|
||||
.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);
|
||||
|
||||
let lo_helper = lilo::LoHelper::new(&**instance);
|
||||
let memory_writer = ILowerer::new(&lo_helper)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
let offset =
|
||||
record_lower_memory_(*instance, instruction.clone(), record_fields)?;
|
||||
it_lilo::lowerer::record_lower_memory(&memory_writer, record_fields)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
log::debug!("record.lower_memory: pushing {} on the stack", offset);
|
||||
runtime.stack.push(IValue::I32(offset));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Some(value) => Err(InstructionError::new(
|
||||
Some(value) => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::Record(record_type_id),
|
||||
received_value: value,
|
||||
},
|
||||
)),
|
||||
None => Err(InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
pub(crate) fn record_lower<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
type_index: u32,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let instance = &runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::TypeIsMissing { type_index },
|
||||
)
|
||||
})? {
|
||||
Type::Record(record_type) => record_type,
|
||||
Type::Function { .. } => {
|
||||
return Err(InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidTypeKind {
|
||||
expected_kind: TypeKind::Record,
|
||||
received_kind: TypeKind::Function,
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
match runtime.stack.pop1() {
|
||||
Some(IValue::Record(record_values))
|
||||
if record_type == &(&*record_values).into() =>
|
||||
{
|
||||
let values = FlattenIValueIterator::new(&record_values);
|
||||
for value in values {
|
||||
runtime.stack.push(value.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Some(value) => Err(InstructionError::new(
|
||||
),
|
||||
None => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::Record(record_type.clone()),
|
||||
received_type: (&value).into(),
|
||||
},
|
||||
)),
|
||||
None => Err(InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 }
|
||||
),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
@ -1,41 +1,43 @@
|
||||
use super::to_native;
|
||||
use crate::instr_error;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
};
|
||||
|
||||
use std::{cell::Cell, convert::TryInto};
|
||||
|
||||
executable_instruction!(
|
||||
string_lift_memory(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let memory_index: u32 = 0;
|
||||
let memory_index = 0;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index as usize)
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?;
|
||||
|
||||
let pointer: usize = to_native::<i32>(&inputs[0], instruction.clone())?
|
||||
let pointer: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "pointer").into())
|
||||
.map_err(|k| InstructionError::new(instruction.clone(), k))?;
|
||||
let length: usize = to_native::<i32>(&inputs[1], instruction.clone())?
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
let length: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "length").into())
|
||||
.map_err(|k| InstructionError::new(instruction.clone(), k))?;
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
let memory_view = memory.view();
|
||||
|
||||
if length == 0 {
|
||||
@ -45,13 +47,13 @@ executable_instruction!(
|
||||
}
|
||||
|
||||
if memory_view.len() < pointer + length {
|
||||
return Err(InstructionError::new(
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryOutOfBoundsAccess {
|
||||
index: pointer + length,
|
||||
length: memory_view.len(),
|
||||
},
|
||||
));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let data: Vec<u8> = (&memory_view[pointer..pointer + length])
|
||||
@ -60,7 +62,7 @@ executable_instruction!(
|
||||
.collect();
|
||||
|
||||
let string = String::from_utf8(data)
|
||||
.map_err(|error| InstructionError::new(instruction.clone(), InstructionErrorKind::String(error)))?;
|
||||
.map_err(|error| InstructionError::from_error_kind(instruction.clone(), InstructionErrorKind::String(error)))?;
|
||||
|
||||
log::debug!("string.lift_memory: pushing {:?} on the stack", string);
|
||||
runtime.stack.push(IValue::String(string));
|
||||
@ -73,32 +75,32 @@ executable_instruction!(
|
||||
executable_instruction!(
|
||||
string_lower_memory(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let string_pointer: usize = to_native::<i32>(&inputs[0], instruction.clone())?
|
||||
let string_pointer: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "pointer").into())
|
||||
.map_err(|k| InstructionError::new(instruction.clone(), k))?;
|
||||
let string: String = to_native(&inputs[1], instruction.clone())?;
|
||||
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
|
||||
let string: String = to_native(inputs.remove(0), instruction.clone())?;
|
||||
let string_bytes = string.as_bytes();
|
||||
let string_length: i32 = string_bytes.len().try_into().map_err(|_| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::NegativeValue { subject: "string_length" },
|
||||
)
|
||||
})?;
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index: u32 = 0;
|
||||
let memory_index = 0;
|
||||
let memory_view = instance
|
||||
.memory(memory_index as usize)
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
@ -131,18 +133,18 @@ executable_instruction!(
|
||||
Ok(())
|
||||
},
|
||||
|
||||
Some(value) => Err(InstructionError::new(
|
||||
Some(value) => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: IType::String,
|
||||
received_value: (&value).clone(),
|
||||
},
|
||||
)),
|
||||
}
|
||||
),
|
||||
|
||||
None => Err(InstructionError::new(
|
||||
None => instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 }
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ executable_instruction!(
|
||||
swap2(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let mut values = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)
|
||||
|
@ -1,170 +0,0 @@
|
||||
use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX;
|
||||
use crate::interpreter::wasm;
|
||||
use crate::interpreter::wasm::structures::{FunctionIndex, TypedIndex};
|
||||
|
||||
use crate::interpreter::instructions::to_native;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
};
|
||||
|
||||
pub(super) fn read_from_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
instruction: Instruction,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> Result<Vec<u8>, InstructionError>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let memory_index: u32 = 0;
|
||||
let memory_view = instance
|
||||
.memory(memory_index as usize)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
log::trace!("reading {} bytes from offset {}", size, offset);
|
||||
|
||||
let right = offset + size;
|
||||
if right < offset || right >= memory_view.len() {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::MemoryOutOfBoundsAccess {
|
||||
index: right,
|
||||
length: memory_view.len(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
Ok((&memory_view[offset..offset + size])
|
||||
.iter()
|
||||
.map(std::cell::Cell::get)
|
||||
.collect::<Vec<u8>>())
|
||||
}
|
||||
|
||||
pub(super) fn write_to_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
instruction: Instruction,
|
||||
bytes: &[u8],
|
||||
) -> Result<usize, InstructionError>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let offset = allocate(instance, instruction.clone(), bytes.len() as _)?;
|
||||
|
||||
let memory_index: u32 = 0;
|
||||
let memory_view = instance
|
||||
.memory(memory_index as usize)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
log::trace!("writing {} bytes from offset {}", bytes.len(), offset);
|
||||
|
||||
let right = offset + bytes.len();
|
||||
if right < offset || right >= memory_view.len() {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::MemoryOutOfBoundsAccess {
|
||||
index: right,
|
||||
length: memory_view.len(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
for (byte_id, byte) in bytes.iter().enumerate() {
|
||||
memory_view[offset + byte_id].set(*byte);
|
||||
}
|
||||
|
||||
Ok(offset)
|
||||
}
|
||||
|
||||
pub(super) fn allocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
instruction: Instruction,
|
||||
size: usize,
|
||||
) -> Result<usize, InstructionError>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let values = call_core(
|
||||
instance,
|
||||
ALLOCATE_FUNC_INDEX,
|
||||
instruction.clone(),
|
||||
vec![IValue::I32(size as _)],
|
||||
)?;
|
||||
if values.len() != 1 {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::LocalOrImportSignatureMismatch {
|
||||
function_index: ALLOCATE_FUNC_INDEX,
|
||||
expected: (vec![IType::I32], vec![]),
|
||||
received: (vec![], vec![]),
|
||||
},
|
||||
));
|
||||
}
|
||||
to_native::<i32>(&values[0], instruction).map(|v| v as usize)
|
||||
}
|
||||
|
||||
fn call_core<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
function_index: u32,
|
||||
instruction: Instruction,
|
||||
inputs: Vec<IValue>,
|
||||
) -> Result<Vec<IValue>, InstructionError>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let index = FunctionIndex::new(function_index as usize);
|
||||
let local_or_import = instance.local_or_import(index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LocalOrImportIsMissing { function_index },
|
||||
)
|
||||
})?;
|
||||
|
||||
crate::interpreter::instructions::check_function_signature(
|
||||
instance,
|
||||
local_or_import,
|
||||
&inputs,
|
||||
instruction.clone(),
|
||||
)?;
|
||||
|
||||
let outputs = local_or_import.call(&inputs).map_err(|_| {
|
||||
InstructionError::new(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::LocalOrImportCall {
|
||||
function_name: local_or_import.name().to_string(),
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(outputs)
|
||||
}
|
@ -4,9 +4,10 @@ mod instructions;
|
||||
pub mod stack;
|
||||
pub mod wasm;
|
||||
|
||||
pub use instructions::Instruction;
|
||||
|
||||
use crate::errors::{InstructionResult, InterpreterResult};
|
||||
use crate::IValue;
|
||||
pub use instructions::Instruction;
|
||||
use stack::Stack;
|
||||
use std::{convert::TryFrom, marker::PhantomData};
|
||||
|
||||
@ -198,6 +199,7 @@ where
|
||||
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),
|
||||
@ -206,6 +208,7 @@ where
|
||||
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),
|
||||
@ -230,10 +233,21 @@ where
|
||||
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)
|
||||
@ -242,15 +256,6 @@ where
|
||||
let value_type = value_type.clone();
|
||||
instructions::array_lower_memory(instruction, value_type)
|
||||
}
|
||||
|
||||
/*
|
||||
Instruction::RecordLift { type_index } => {
|
||||
instructions::record_lift(*type_index, instruction)
|
||||
}
|
||||
Instruction::RecordLower { type_index } => {
|
||||
instructions::record_lower(*type_index, instruction)
|
||||
}
|
||||
*/
|
||||
Instruction::RecordLiftMemory { record_type_id } => {
|
||||
instructions::record_lift_memory(record_type_id as _, instruction)
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ where
|
||||
fn export(&self, export_name: &str) -> Option<&E>;
|
||||
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, index: I) -> Option<&LI>;
|
||||
fn memory(&self, index: usize) -> Option<&M>;
|
||||
fn memory_slice(&self, index: usize) -> Option<&[Cell<u8>]>;
|
||||
fn wit_record_by_id(&self, index: u64) -> Option<&Rc<IRecordType>>;
|
||||
}
|
||||
|
||||
@ -168,6 +169,10 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn memory_slice(&self, _: usize) -> Option<&[Cell<u8>]> {
|
||||
None
|
||||
}
|
||||
|
||||
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, _index: I) -> Option<&LI> {
|
||||
None
|
||||
}
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
broken_intra_doc_links,
|
||||
rustdoc::broken_intra_doc_links,
|
||||
missing_docs,
|
||||
nonstandard_style,
|
||||
unreachable_patterns,
|
||||
@ -65,6 +65,7 @@ mod serde;
|
||||
mod values;
|
||||
|
||||
// re-exports
|
||||
pub use fluence_it_types::ne_vec;
|
||||
pub use fluence_it_types::ne_vec::NEVec;
|
||||
pub use fluence_it_types::IRecordFieldType;
|
||||
pub use fluence_it_types::IRecordType;
|
||||
|
@ -206,6 +206,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self.iterator.peek() {
|
||||
Some(IValue::Boolean(_)) => self.deserialize_bool(visitor),
|
||||
Some(IValue::S8(_)) => self.deserialize_i8(visitor),
|
||||
Some(IValue::S16(_)) => self.deserialize_i16(visitor),
|
||||
Some(IValue::S32(_)) => self.deserialize_i32(visitor),
|
||||
@ -217,6 +218,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
Some(IValue::F32(_)) => self.deserialize_f32(visitor),
|
||||
Some(IValue::F64(_)) => self.deserialize_f64(visitor),
|
||||
Some(IValue::String(_)) => self.deserialize_string(visitor),
|
||||
Some(IValue::ByteArray(_)) => self.deserialize_bytes(visitor),
|
||||
Some(IValue::Array(_)) => self.deserialize_bytes(visitor),
|
||||
Some(IValue::I32(_)) => self.deserialize_i32(visitor),
|
||||
Some(IValue::I64(_)) => self.deserialize_i64(visitor),
|
||||
@ -225,11 +227,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_bool<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
unimplemented!("`bool` is not supported by WIT for the moment.")
|
||||
visitor.visit_bool(self.next_u8()? != 0)
|
||||
}
|
||||
|
||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
|
Loading…
Reference in New Issue
Block a user