mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-02 01:21:34 +00:00
Some changes
This commit is contained in:
parent
e6bf41a10c
commit
c3a3ad83fa
1
pwasm-emscripten/.gitignore
vendored
Normal file
1
pwasm-emscripten/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
target
|
7
pwasm-emscripten/Cargo.toml
Normal file
7
pwasm-emscripten/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "pwasm-emscripten"
|
||||
version = "0.1.0"
|
||||
authors = ["Sergey Pepyakin <s.pepyakin@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
parity-wasm = { path = ".." }
|
258
pwasm-emscripten/src/lib.rs
Normal file
258
pwasm-emscripten/src/lib.rs
Normal file
@ -0,0 +1,258 @@
|
||||
extern crate parity_wasm;
|
||||
|
||||
//This module provides some of the simplest exports
|
||||
//from the Emscripten runtime, such as `STACKTOP` or `abort`.
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use parity_wasm::builder::module;
|
||||
use parity_wasm::elements::{ExportEntry, Internal, ValueType};
|
||||
use parity_wasm::interpreter::Error;
|
||||
use parity_wasm::interpreter::{native_module, UserDefinedElements, UserFunctionDescriptor, UserFunctionExecutor};
|
||||
use parity_wasm::interpreter::{CallerContext, ModuleInstance, ModuleInstanceInterface};
|
||||
use parity_wasm::interpreter::RuntimeValue;
|
||||
use parity_wasm::interpreter::ProgramInstance;
|
||||
use parity_wasm::interpreter::{VariableInstance, VariableType};
|
||||
|
||||
/// Memory address, at which stack begins.
|
||||
const DEFAULT_STACK_TOP: u32 = 256 * 1024;
|
||||
/// Memory, allocated for stack.
|
||||
const DEFAULT_TOTAL_STACK: u32 = 5 * 1024 * 1024;
|
||||
/// Total memory, allocated by default.
|
||||
const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024;
|
||||
/// Whether memory can be enlarged, or not.
|
||||
const DEFAULT_ALLOW_MEMORY_GROWTH: bool = true;
|
||||
/// Default tableBase variable value.
|
||||
const DEFAULT_TABLE_BASE: u32 = 0;
|
||||
/// Default tableBase variable value.
|
||||
const DEFAULT_MEMORY_BASE: u32 = 0;
|
||||
|
||||
/// Default table size.
|
||||
const DEFAULT_TABLE_SIZE: u32 = 64;
|
||||
|
||||
/// Index of default memory.
|
||||
const INDEX_MEMORY: u32 = 0;
|
||||
|
||||
/// Index of default table.
|
||||
const INDEX_TABLE: u32 = 0;
|
||||
|
||||
const LINEAR_MEMORY_PAGE_SIZE: u32 = 64 * 1024;
|
||||
|
||||
/// Emscripten environment parameters.
|
||||
pub struct EnvParams {
|
||||
/// Stack size in bytes.
|
||||
pub total_stack: u32,
|
||||
/// Total memory size in bytes.
|
||||
pub total_memory: u32,
|
||||
/// Allow memory growth.
|
||||
pub allow_memory_growth: bool,
|
||||
/// Table size.
|
||||
pub table_size: u32,
|
||||
/// Static reserve, if any
|
||||
pub static_size: Option<u32>,
|
||||
}
|
||||
|
||||
struct EmscriptenFunctionExecutor {
|
||||
abort_global: Arc<VariableInstance>,
|
||||
total_mem_global: Arc<VariableInstance>,
|
||||
}
|
||||
|
||||
impl<'a> UserFunctionExecutor for EmscriptenFunctionExecutor {
|
||||
fn execute(
|
||||
&mut self,
|
||||
name: &str,
|
||||
context: CallerContext,
|
||||
) -> Result<Option<RuntimeValue>, Error> {
|
||||
match name {
|
||||
"_abort" | "abort" => {
|
||||
self.abort_global.set(RuntimeValue::I32(1))?;
|
||||
Err(Error::Trap("abort".into()).into())
|
||||
}
|
||||
"assert" => {
|
||||
let condition = context.value_stack.pop_as::<i32>()?;
|
||||
if condition == 0 {
|
||||
self.abort_global.set(RuntimeValue::I32(1))?;
|
||||
Err(Error::Trap("assertion failed".into()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
"enlargeMemory" => {
|
||||
// TODO: support memory enlarge
|
||||
Ok(Some(RuntimeValue::I32(0)))
|
||||
}
|
||||
"getTotalMemory" => {
|
||||
let total_memory = self.total_mem_global.get();
|
||||
Ok(Some(total_memory))
|
||||
}
|
||||
_ => Err(Error::Trap("not implemented".into()).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env_module(params: EnvParams) -> Result<Arc<ModuleInstanceInterface>, Error> {
|
||||
debug_assert!(params.total_stack < params.total_memory);
|
||||
debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
|
||||
debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);
|
||||
|
||||
let stack_top = params.static_size.unwrap_or(DEFAULT_STACK_TOP);
|
||||
|
||||
// Build module with defined memory and table,
|
||||
// instantiate it and wrap into an Arc.
|
||||
let instance = {
|
||||
let builder = module()
|
||||
// memory regions
|
||||
.memory()
|
||||
.with_min(params.total_memory / LINEAR_MEMORY_PAGE_SIZE)
|
||||
.with_max(params.max_memory().map(|m| m / LINEAR_MEMORY_PAGE_SIZE))
|
||||
.build()
|
||||
.with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY)))
|
||||
// tables
|
||||
.table()
|
||||
.with_min(params.table_size)
|
||||
.build()
|
||||
.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)));
|
||||
let mut instance = ModuleInstance::new(Weak::default(), "env".into(), builder.build())?;
|
||||
instance.instantiate(None)?;
|
||||
Arc::new(instance)
|
||||
};
|
||||
|
||||
let abort_global = Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32(0)
|
||||
).unwrap()
|
||||
);
|
||||
let total_mem_global = Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32(params.total_memory as i32),
|
||||
).unwrap(),
|
||||
);
|
||||
|
||||
let function_executor = EmscriptenFunctionExecutor {
|
||||
abort_global: Arc::clone(&abort_global),
|
||||
total_mem_global: Arc::clone(&total_mem_global),
|
||||
};
|
||||
|
||||
const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
UserFunctionDescriptor::Static("_abort", &[], None),
|
||||
UserFunctionDescriptor::Static("abort", &[], None),
|
||||
UserFunctionDescriptor::Static("assert", &[ValueType::I32], None),
|
||||
UserFunctionDescriptor::Static("enlargeMemory", &[], Some(ValueType::I32)),
|
||||
UserFunctionDescriptor::Static("getTotalMemory", &[], Some(ValueType::I32)),
|
||||
];
|
||||
|
||||
let elements = UserDefinedElements {
|
||||
executor: Some(function_executor),
|
||||
globals: vec![
|
||||
(
|
||||
"STACK_BASE".into(),
|
||||
Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32(stack_top as i32),
|
||||
).unwrap(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"STACKTOP".into(),
|
||||
Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32(stack_top as i32),
|
||||
).unwrap(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"STACK_MAX".into(),
|
||||
Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32((stack_top + params.total_stack) as i32),
|
||||
).unwrap(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"DYNAMIC_BASE".into(),
|
||||
Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32((stack_top + params.total_stack) as i32),
|
||||
).unwrap(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"DYNAMICTOP_PTR".into(),
|
||||
Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32((stack_top + params.total_stack) as i32),
|
||||
).unwrap(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"EXITSTATUS".into(),
|
||||
Arc::new(
|
||||
VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(0)).unwrap(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"tableBase".into(),
|
||||
Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32(DEFAULT_TABLE_BASE as i32),
|
||||
).unwrap(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"memoryBase".into(),
|
||||
Arc::new(
|
||||
VariableInstance::new(
|
||||
false,
|
||||
VariableType::I32,
|
||||
RuntimeValue::I32(DEFAULT_MEMORY_BASE as i32),
|
||||
).unwrap(),
|
||||
),
|
||||
),
|
||||
("TOTAL_MEMORY".into(), total_mem_global),
|
||||
("ABORT".into(), abort_global),
|
||||
].into_iter()
|
||||
.collect(),
|
||||
functions: ::std::borrow::Cow::from(SIGNATURES),
|
||||
};
|
||||
|
||||
Ok(native_module(instance, elements)?)
|
||||
}
|
||||
|
||||
impl Default for EnvParams {
|
||||
fn default() -> Self {
|
||||
EnvParams {
|
||||
total_stack: DEFAULT_TOTAL_STACK,
|
||||
total_memory: DEFAULT_TOTAL_MEMORY,
|
||||
allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH,
|
||||
table_size: DEFAULT_TABLE_SIZE,
|
||||
static_size: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EnvParams {
|
||||
fn max_memory(&self) -> Option<u32> {
|
||||
if self.allow_memory_growth { None } else { Some(self.total_memory) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn program_with_emscripten(params: EnvParams) -> ProgramInstance {
|
||||
let program = ProgramInstance::new();
|
||||
program.insert_loaded_module("env", env_module(params).unwrap()).unwrap();
|
||||
program
|
||||
}
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
use parking_lot::RwLock;
|
||||
use elements::Module;
|
||||
use interpreter::Error;
|
||||
use interpreter::emscripten::{EmscriptenParams, env_module};
|
||||
use interpreter::emscripten::{self, env_module};
|
||||
use interpreter::module::{ModuleInstance, ModuleInstanceInterface};
|
||||
|
||||
/// Program instance. Program is a set of instantiated modules.
|
||||
@ -29,10 +29,12 @@ impl ProgramInstance {
|
||||
/// Create new program instance with added Emscripten's `env` module.
|
||||
///
|
||||
/// You can specify desired environment params. Or you can just pass `Default::default()`.
|
||||
pub fn with_emscripten_env(params: EmscriptenParams) -> Result<Self, Error> {
|
||||
Ok(ProgramInstance {
|
||||
essence: Arc::new(ProgramInstanceEssence::with_env_params(params)?),
|
||||
})
|
||||
pub fn with_emscripten_env(params: emscripten::EnvParams) -> Result<Self, Error> {
|
||||
let instance = ProgramInstance {
|
||||
essence: Arc::new(ProgramInstanceEssence::new()),
|
||||
};
|
||||
// instance.essence.modules.write().insert("env".into(), env_module(params)?);
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
/// Instantiate module with validation.
|
||||
@ -47,9 +49,9 @@ impl ProgramInstance {
|
||||
}
|
||||
|
||||
/// Insert instantiated module.
|
||||
pub fn insert_loaded_module(&self, name: &str, module_instance: Arc<ModuleInstance>) -> Result<Arc<ModuleInstance>, Error> {
|
||||
pub fn insert_loaded_module(&self, name: &str, module_instance: Arc<ModuleInstanceInterface>) -> Result<Arc<ModuleInstanceInterface>, Error> {
|
||||
// replace existing module with the same name with new one
|
||||
self.essence.modules.write().insert(name.into(), module_instance.clone());
|
||||
self.essence.modules.write().insert(name.into(), Arc::clone(&module_instance));
|
||||
Ok(module_instance)
|
||||
}
|
||||
|
||||
@ -67,19 +69,6 @@ impl ProgramInstanceEssence {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_env_params(env_params: EmscriptenParams) -> Result<Self, Error> {
|
||||
let env_mod = env_module(env_params)?;
|
||||
Ok(ProgramInstanceEssence::with_env_module(env_mod))
|
||||
}
|
||||
|
||||
pub fn with_env_module(env_module: Arc<ModuleInstanceInterface>) -> Self {
|
||||
let mut modules = HashMap::new();
|
||||
modules.insert("env".into(), env_module);
|
||||
ProgramInstanceEssence {
|
||||
modules: RwLock::new(modules),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get module reference.
|
||||
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> {
|
||||
self.modules.read().get(name).cloned()
|
||||
|
Loading…
x
Reference in New Issue
Block a user