Memory units (#42)
* Initial implementation * Not use grow as it is makes debug builds very slow * Use Pages::BYTE_SIZE for LINEAR_MEMORY_PAGE_SIZE * Tidy docs. * Use memory_units from git.
This commit is contained in:
parent
a3ad4b0e49
commit
483736b1bd
|
@ -11,6 +11,7 @@ exclude = [ "res/*", "spec/*" ]
|
|||
[dependencies]
|
||||
parity-wasm = "0.23"
|
||||
byteorder = "1.0"
|
||||
memory_units = { git = "https://github.com/pepyakin/memory_units.git", rev = "e09093e" }
|
||||
|
||||
[dev-dependencies]
|
||||
wabt = "0.1.2"
|
||||
|
|
|
@ -16,6 +16,7 @@ use wasmi::{
|
|||
Module, Signature, MemoryDescriptor, Trap,
|
||||
TableDescriptor, GlobalDescriptor, FuncInstance, RuntimeArgs,
|
||||
};
|
||||
use wasmi::memory_units::Pages;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
|
@ -43,7 +44,7 @@ impl SpecModule {
|
|||
fn new() -> Self {
|
||||
SpecModule {
|
||||
table: TableInstance::alloc(10, Some(20)).unwrap(),
|
||||
memory: MemoryInstance::alloc(1, Some(2)).unwrap(),
|
||||
memory: MemoryInstance::alloc(Pages(1), Some(Pages(2))).unwrap(),
|
||||
global_i32: GlobalInstance::alloc(RuntimeValue::I32(666), false),
|
||||
global_i64: GlobalInstance::alloc(RuntimeValue::I64(666), false),
|
||||
global_f32: GlobalInstance::alloc(RuntimeValue::F32(666.0), false),
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
extern crate wabt;
|
||||
extern crate parity_wasm;
|
||||
extern crate byteorder;
|
||||
extern crate memory_units as memory_units_crate;
|
||||
|
||||
#[cfg(all(not(feature = "32bit_opt_in"), target_pointer_width = "32"))]
|
||||
compile_error! {"32-bit targets are not supported at the moment.
|
||||
|
@ -360,6 +361,12 @@ pub use self::global::{GlobalInstance, GlobalRef};
|
|||
pub use self::func::{FuncInstance, FuncRef};
|
||||
pub use self::types::{Signature, ValueType, GlobalDescriptor, TableDescriptor, MemoryDescriptor};
|
||||
|
||||
/// WebAssembly-specific sizes and units.
|
||||
pub mod memory_units {
|
||||
pub use memory_units_crate::wasm32::*;
|
||||
pub use memory_units_crate::{Bytes, ByteSize, RoundUpTo, size_of};
|
||||
}
|
||||
|
||||
/// Deserialized module prepared for instantiation.
|
||||
pub struct Module {
|
||||
labels: HashMap<usize, HashMap<usize, usize>>,
|
||||
|
|
199
src/memory.rs
199
src/memory.rs
|
@ -6,17 +6,17 @@ use std::rc::Rc;
|
|||
use std::cell::RefCell;
|
||||
use parity_wasm::elements::ResizableLimits;
|
||||
use Error;
|
||||
use module::check_limits;
|
||||
use memory_units::{RoundUpTo, Pages, Bytes};
|
||||
|
||||
/// Size of a page of [linear memory][`MemoryInstance`] - 64KiB.
|
||||
///
|
||||
/// The size of a memory is always a integer multiple of a page size.
|
||||
///
|
||||
/// [`MemoryInstance`]: struct.MemoryInstance.html
|
||||
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
|
||||
pub const LINEAR_MEMORY_PAGE_SIZE: Bytes = Bytes(65536);
|
||||
|
||||
/// Maximal number of pages.
|
||||
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;
|
||||
const LINEAR_MEMORY_MAX_PAGES: Pages = Pages(65536);
|
||||
|
||||
/// Reference to a memory (See [`MemoryInstance`] for details).
|
||||
///
|
||||
|
@ -52,8 +52,8 @@ pub struct MemoryInstance {
|
|||
limits: ResizableLimits,
|
||||
/// Linear memory buffer.
|
||||
buffer: RefCell<Vec<u8>>,
|
||||
/// Maximum buffer size.
|
||||
maximum_size: u32,
|
||||
initial: Pages,
|
||||
maximum: Option<Pages>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for MemoryInstance {
|
||||
|
@ -61,7 +61,8 @@ impl fmt::Debug for MemoryInstance {
|
|||
f.debug_struct("MemoryInstance")
|
||||
.field("limits", &self.limits)
|
||||
.field("buffer.len", &self.buffer.borrow().len())
|
||||
.field("maximum_size", &self.maximum_size)
|
||||
.field("maximum", &self.maximum)
|
||||
.field("initial", &self.initial)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -92,12 +93,12 @@ impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>>
|
|||
impl MemoryInstance {
|
||||
/// Allocate a memory instance.
|
||||
///
|
||||
/// The memory allocated with initial number of pages specified by `initial_pages`.
|
||||
/// Minimal possible value for `initial_pages` is 0 and maximum possible is `65536`.
|
||||
/// The memory allocated with initial number of pages specified by `initial`.
|
||||
/// Minimal possible value for `initial` is 0 and maximum possible is `65536`.
|
||||
/// (Since maximum addressible memory is 2<sup>32</sup> = 4GiB = 65536 * [64KiB][`LINEAR_MEMORY_PAGE_SIZE`]).
|
||||
///
|
||||
/// It is possible to limit maximum number of pages this memory instance can have by specifying
|
||||
/// `maximum_page`. If not specified, this memory instance would be able to allocate up to 4GiB.
|
||||
/// `maximum`. If not specified, this memory instance would be able to allocate up to 4GiB.
|
||||
///
|
||||
/// Allocated memory is always zeroed.
|
||||
///
|
||||
|
@ -105,39 +106,28 @@ impl MemoryInstance {
|
|||
///
|
||||
/// Returns `Err` if:
|
||||
///
|
||||
/// - `initial_pages` is greater than `maximum_pages`
|
||||
/// - either `initial_pages` or `maximum_pages` is greater than `65536`.
|
||||
/// - `initial` is greater than `maximum`
|
||||
/// - either `initial` or `maximum` is greater than `65536`.
|
||||
///
|
||||
/// [`LINEAR_MEMORY_PAGE_SIZE`]: constant.LINEAR_MEMORY_PAGE_SIZE.html
|
||||
pub fn alloc(initial_pages: u32, maximum_pages: Option<u32>) -> Result<MemoryRef, Error> {
|
||||
let memory = MemoryInstance::new(ResizableLimits::new(initial_pages, maximum_pages))?;
|
||||
pub fn alloc(initial: Pages, maximum: Option<Pages>) -> Result<MemoryRef, Error> {
|
||||
validate_memory(initial, maximum).map_err(Error::Memory)?;
|
||||
|
||||
let memory = MemoryInstance::new(initial, maximum);
|
||||
Ok(MemoryRef(Rc::new(memory)))
|
||||
}
|
||||
|
||||
/// Create new linear memory instance.
|
||||
fn new(limits: ResizableLimits) -> Result<Self, Error> {
|
||||
check_limits(&limits)?;
|
||||
fn new(initial: Pages, maximum: Option<Pages>) -> Self {
|
||||
let limits = ResizableLimits::new(initial.0 as u32, maximum.map(|p| p.0 as u32));
|
||||
|
||||
let initial_pages = limits.initial();
|
||||
let maximum_pages = limits.maximum().unwrap_or(LINEAR_MEMORY_MAX_PAGES);
|
||||
|
||||
if initial_pages > LINEAR_MEMORY_MAX_PAGES {
|
||||
return Err(Error::Memory(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES)));
|
||||
}
|
||||
if maximum_pages > LINEAR_MEMORY_MAX_PAGES {
|
||||
return Err(Error::Memory(format!("maximum memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES)));
|
||||
}
|
||||
|
||||
let maximum_size = maximum_pages.saturating_mul(LINEAR_MEMORY_PAGE_SIZE);
|
||||
let initial_size = initial_pages.saturating_mul(LINEAR_MEMORY_PAGE_SIZE);
|
||||
|
||||
let memory = MemoryInstance {
|
||||
let initial_size: Bytes = initial.into();
|
||||
MemoryInstance {
|
||||
limits: limits,
|
||||
buffer: RefCell::new(vec![0; initial_size as usize]),
|
||||
maximum_size: maximum_size,
|
||||
};
|
||||
|
||||
Ok(memory)
|
||||
buffer: RefCell::new(vec![0; initial_size.0]),
|
||||
initial: initial,
|
||||
maximum: maximum,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return linear memory limits.
|
||||
|
@ -146,24 +136,47 @@ impl MemoryInstance {
|
|||
}
|
||||
|
||||
/// Returns number of pages this `MemoryInstance` was created with.
|
||||
pub fn initial_pages(&self) -> u32 {
|
||||
self.limits.initial()
|
||||
pub fn initial(&self) -> Pages {
|
||||
self.initial
|
||||
}
|
||||
|
||||
/// Returns maximum amount of pages this `MemoryInstance` can grow to.
|
||||
///
|
||||
/// Returns `None` if there is no limit set.
|
||||
/// This means that memory can grow up to 4GiB.
|
||||
pub fn maximum_pages(&self) -> Option<u32> {
|
||||
self.limits.maximum()
|
||||
/// Maximum memory size cannot exceed `65536` pages or 4GiB.
|
||||
pub fn maximum(&self) -> Option<Pages> {
|
||||
self.maximum
|
||||
}
|
||||
|
||||
/// Return linear memory size (in pages).
|
||||
pub fn size(&self) -> u32 {
|
||||
self.buffer.borrow().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
|
||||
/// Returns current linear memory size.
|
||||
///
|
||||
/// Maximum memory size cannot exceed `65536` pages or 4GiB.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// To convert number of pages to number of bytes you can use the following code:
|
||||
///
|
||||
/// ```rust
|
||||
/// use wasmi::MemoryInstance;
|
||||
/// use wasmi::memory_units::*;
|
||||
///
|
||||
/// let memory = MemoryInstance::alloc(Pages(1), None).unwrap();
|
||||
/// let byte_size: Bytes = memory.current_size().into();
|
||||
/// assert_eq!(
|
||||
/// byte_size,
|
||||
/// Bytes(65536),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn current_size(&self) -> Pages {
|
||||
Bytes(self.buffer.borrow().len()).round_up_to()
|
||||
}
|
||||
|
||||
/// Copy data from memory at given offset.
|
||||
///
|
||||
/// This will allocate vector for you.
|
||||
/// If you can provide a mutable slice you can use [`get_into`].
|
||||
///
|
||||
/// [`get_into`]: #method.get_into
|
||||
pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
|
||||
let buffer = self.buffer.borrow();
|
||||
let region = self.checked_region(&buffer, offset as usize, size)?;
|
||||
|
@ -196,27 +209,42 @@ impl MemoryInstance {
|
|||
}
|
||||
|
||||
/// Increases the size of the linear memory by given number of pages.
|
||||
/// Returns previous memory size (in pages) if succeeds.
|
||||
/// Returns previous memory size if succeeds.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `Err` if attempted to allocate more memory than permited by the limit.
|
||||
pub fn grow(&self, pages: u32) -> Result<u32, Error> {
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
let old_size = buffer.len() as u32;
|
||||
match calculate_memory_size(old_size, pages, self.maximum_size) {
|
||||
None => Err(Error::Memory(
|
||||
format!(
|
||||
"Trying to grow memory by {} pages when already have {}",
|
||||
pages,
|
||||
old_size / LINEAR_MEMORY_PAGE_SIZE,
|
||||
)
|
||||
)),
|
||||
Some(new_size) => {
|
||||
buffer.resize(new_size as usize, 0);
|
||||
Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
|
||||
},
|
||||
pub fn grow(&self, additional: Pages) -> Result<Pages, Error> {
|
||||
let size_before_grow: Pages = self.current_size();
|
||||
println!("grow({:?}) = {:?}", additional, size_before_grow);
|
||||
|
||||
if additional == Pages(0) {
|
||||
return Ok(size_before_grow);
|
||||
}
|
||||
if additional > Pages(65536) {
|
||||
return Err(Error::Memory(format!(
|
||||
"Trying to grow memory by more than 65536 pages"
|
||||
)));
|
||||
}
|
||||
|
||||
let new_size: Pages = size_before_grow + additional;
|
||||
let maximum = self.maximum.unwrap_or(LINEAR_MEMORY_MAX_PAGES);
|
||||
if new_size > maximum {
|
||||
return Err(Error::Memory(format!(
|
||||
"Trying to grow memory by {} pages when already have {}",
|
||||
additional.0, size_before_grow.0,
|
||||
)));
|
||||
}
|
||||
|
||||
// Resize underlying buffer up to a new size filling newly allocated space with zeroes.
|
||||
// This size is guaranteed to be larger than current size.
|
||||
let new_buffer_length: Bytes = new_size.into();
|
||||
{
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
debug_assert!(new_buffer_length.0 > buffer.len());
|
||||
buffer.resize(new_buffer_length.0, 0);
|
||||
}
|
||||
Ok(size_before_grow)
|
||||
}
|
||||
|
||||
fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
|
||||
|
@ -313,21 +341,32 @@ impl MemoryInstance {
|
|||
}
|
||||
}
|
||||
|
||||
fn calculate_memory_size(old_size: u32, additional_pages: u32, maximum_size: u32) -> Option<u32> {
|
||||
let size = additional_pages
|
||||
.saturating_mul(LINEAR_MEMORY_PAGE_SIZE);
|
||||
match size.checked_add(old_size) {
|
||||
Some(size) if size <= maximum_size => Some(size),
|
||||
_ => None,
|
||||
pub fn validate_memory(initial: Pages, maximum: Option<Pages>) -> Result<(), String> {
|
||||
if initial > LINEAR_MEMORY_MAX_PAGES {
|
||||
return Err(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES.0));
|
||||
}
|
||||
if let Some(maximum) = maximum {
|
||||
if initial > maximum {
|
||||
return Err(format!(
|
||||
"maximum limit {} is less than minimum {}",
|
||||
maximum.0,
|
||||
initial.0,
|
||||
));
|
||||
}
|
||||
|
||||
if maximum > LINEAR_MEMORY_MAX_PAGES {
|
||||
return Err(format!("maximum memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES.0));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::{MemoryInstance, LINEAR_MEMORY_MAX_PAGES};
|
||||
use super::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE};
|
||||
use Error;
|
||||
use parity_wasm::elements::ResizableLimits;
|
||||
use memory_units::Pages;
|
||||
|
||||
#[test]
|
||||
fn alloc() {
|
||||
|
@ -338,16 +377,19 @@ mod tests {
|
|||
(1, Some(1), true),
|
||||
(0, Some(1), true),
|
||||
(1, Some(0), false),
|
||||
(0, Some(LINEAR_MEMORY_MAX_PAGES), true),
|
||||
(LINEAR_MEMORY_MAX_PAGES, Some(LINEAR_MEMORY_MAX_PAGES), true),
|
||||
(LINEAR_MEMORY_MAX_PAGES, Some(0), false),
|
||||
(LINEAR_MEMORY_MAX_PAGES, None, true),
|
||||
(0, Some(65536), true),
|
||||
(65536, Some(65536), true),
|
||||
(65536, Some(0), false),
|
||||
(65536, None, true),
|
||||
];
|
||||
for &(initial, maybe_max, expected_ok) in fixtures {
|
||||
let result = MemoryInstance::alloc(initial, maybe_max);
|
||||
for (index, &(initial, maybe_max, expected_ok)) in fixtures.iter().enumerate() {
|
||||
let initial: Pages = Pages(initial);
|
||||
let maximum: Option<Pages> = maybe_max.map(|m| Pages(m));
|
||||
let result = MemoryInstance::alloc(initial, maximum);
|
||||
if result.is_ok() != expected_ok {
|
||||
panic!(
|
||||
"unexpected error, initial={}, max={:?}, expected={}, result={:?}",
|
||||
"unexpected error at {}, initial={:?}, max={:?}, expected={}, result={:?}",
|
||||
index,
|
||||
initial,
|
||||
maybe_max,
|
||||
expected_ok,
|
||||
|
@ -357,9 +399,14 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ensure_page_size() {
|
||||
use memory_units::ByteSize;
|
||||
assert_eq!(LINEAR_MEMORY_PAGE_SIZE, Pages::byte_size());
|
||||
}
|
||||
|
||||
fn create_memory(initial_content: &[u8]) -> MemoryInstance {
|
||||
let mem = MemoryInstance::new(ResizableLimits::new(1, Some(1)))
|
||||
.expect("MemoryInstance created successfuly");
|
||||
let mem = MemoryInstance::new(Pages(1), Some(Pages(1)));
|
||||
mem.set(0, initial_content).expect("Successful initialize the memory");
|
||||
mem
|
||||
}
|
||||
|
@ -418,7 +465,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn get_into() {
|
||||
let mem = MemoryInstance::new(ResizableLimits::new(1, None)).expect("memory instance creation should not fail");
|
||||
let mem = MemoryInstance::new(Pages(1), None);
|
||||
mem.set(6, &[13, 17, 129]).expect("memory set should not fail");
|
||||
|
||||
let mut data = [0u8; 2];
|
||||
|
|
|
@ -14,6 +14,7 @@ use memory::MemoryRef;
|
|||
use host::Externals;
|
||||
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
||||
use types::{GlobalDescriptor, TableDescriptor, MemoryDescriptor};
|
||||
use memory_units::Pages;
|
||||
|
||||
/// Reference to a [`ModuleInstance`].
|
||||
///
|
||||
|
@ -325,10 +326,11 @@ impl ModuleInstance {
|
|||
&[],
|
||||
)
|
||||
{
|
||||
let memory = MemoryInstance::alloc(
|
||||
memory_type.limits().initial(),
|
||||
memory_type.limits().maximum()
|
||||
)?;
|
||||
let initial: Pages = Pages(memory_type.limits().initial() as usize);
|
||||
let maximum: Option<Pages> = memory_type.limits().maximum().map(|m| Pages(m as usize));
|
||||
|
||||
let memory = MemoryInstance::alloc(initial, maximum)
|
||||
.expect("Due to validation `initial` and `maximum` should be valid");
|
||||
instance.push_memory(memory);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use host::Externals;
|
|||
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType};
|
||||
use common::stack::StackWithLimit;
|
||||
use common::{DEFAULT_FRAME_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT};
|
||||
use memory_units::Pages;
|
||||
|
||||
/// Function interpreter.
|
||||
pub struct Interpreter<'a, E: Externals + 'a> {
|
||||
|
@ -643,7 +644,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
|||
let m = context.module()
|
||||
.memory_by_index(DEFAULT_MEMORY_INDEX)
|
||||
.expect("Due to validation memory should exists");
|
||||
let s = m.size();
|
||||
let s = m.current_size().0;
|
||||
context
|
||||
.value_stack_mut()
|
||||
.push(RuntimeValue::I32(s as i32))?;
|
||||
|
@ -657,9 +658,10 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
|||
let m = context.module()
|
||||
.memory_by_index(DEFAULT_MEMORY_INDEX)
|
||||
.expect("Due to validation memory should exists");
|
||||
// Pushes -1 if allocation fails or previous memory size, if succeeds.
|
||||
let m = m.grow(pages)
|
||||
.unwrap_or(u32::MAX);
|
||||
let m = match m.grow(Pages(pages as usize)) {
|
||||
Ok(Pages(new_size)) => new_size as u32,
|
||||
Err(_) => u32::MAX, // Returns -1 (or 0xFFFFFFFF) in case of error.
|
||||
};
|
||||
context
|
||||
.value_stack_mut()
|
||||
.push(RuntimeValue::I32(m as i32))?;
|
||||
|
|
|
@ -4,6 +4,7 @@ use {
|
|||
RuntimeValue, RuntimeArgs, TableDescriptor, MemoryDescriptor, Trap, TrapKind,
|
||||
};
|
||||
use types::ValueType;
|
||||
use memory_units::Pages;
|
||||
use super::parse_wat;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -36,7 +37,7 @@ struct TestHost {
|
|||
impl TestHost {
|
||||
fn new() -> TestHost {
|
||||
TestHost {
|
||||
memory: Some(MemoryInstance::alloc(1, Some(1)).unwrap()),
|
||||
memory: Some(MemoryInstance::alloc(Pages(1), Some(Pages(1))).unwrap()),
|
||||
instance: None,
|
||||
}
|
||||
}
|
||||
|
@ -483,7 +484,7 @@ fn defer_providing_externals() {
|
|||
// Create HostImportResolver with some initialized memory instance.
|
||||
// This memory instance will be provided as 'mem' export.
|
||||
let host_import_resolver =
|
||||
HostImportResolver { mem: MemoryInstance::alloc(1, Some(1)).unwrap() };
|
||||
HostImportResolver { mem: MemoryInstance::alloc(Pages(1), Some(Pages(1))).unwrap() };
|
||||
|
||||
// Instantiate module with `host_import_resolver` as import resolver for "host" module.
|
||||
let instance = ModuleInstance::new(
|
||||
|
|
|
@ -3,6 +3,7 @@ use {
|
|||
MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue,
|
||||
TableInstance, TableRef, Module, GlobalDescriptor, TableDescriptor, MemoryDescriptor,
|
||||
};
|
||||
use memory_units::Pages;
|
||||
use std::fs::File;
|
||||
|
||||
struct Env {
|
||||
|
@ -17,7 +18,7 @@ impl Env {
|
|||
Env {
|
||||
table_base: GlobalInstance::alloc(RuntimeValue::I32(0), false),
|
||||
memory_base: GlobalInstance::alloc(RuntimeValue::I32(0), false),
|
||||
memory: MemoryInstance::alloc(256, None).unwrap(),
|
||||
memory: MemoryInstance::alloc(Pages(256), None).unwrap(),
|
||||
table: TableInstance::alloc(64, None).unwrap(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use parity_wasm::elements::{
|
|||
use common::stack;
|
||||
use self::context::ModuleContextBuilder;
|
||||
use self::func::Validator;
|
||||
use memory_units::Pages;
|
||||
|
||||
mod context;
|
||||
mod func;
|
||||
|
@ -267,7 +268,7 @@ fn validate_limits(limits: &ResizableLimits) -> Result<(), Error> {
|
|||
if let Some(maximum) = limits.maximum() {
|
||||
if limits.initial() > maximum {
|
||||
return Err(Error(format!(
|
||||
"maximum limit {} is lesser than minimum {}",
|
||||
"maximum limit {} is less than minimum {}",
|
||||
maximum,
|
||||
limits.initial()
|
||||
)));
|
||||
|
@ -277,7 +278,9 @@ fn validate_limits(limits: &ResizableLimits) -> Result<(), Error> {
|
|||
}
|
||||
|
||||
fn validate_memory_type(memory_type: &MemoryType) -> Result<(), Error> {
|
||||
validate_limits(memory_type.limits())
|
||||
let initial: Pages = Pages(memory_type.limits().initial() as usize);
|
||||
let maximum: Option<Pages> = memory_type.limits().maximum().map(|m| Pages(m as usize));
|
||||
::memory::validate_memory(initial, maximum).map_err(Error)
|
||||
}
|
||||
|
||||
fn validate_table_type(table_type: &TableType) -> Result<(), Error> {
|
||||
|
|
Loading…
Reference in New Issue