Major fixes for WebAssembly
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
0961b199ff
commit
703fd2c147
|
@ -1,3 +1,4 @@
|
||||||
/target
|
/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
.idea/
|
.idea/
|
||||||
|
types.toml
|
|
@ -505,7 +505,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
.set(ability_script)
|
.set(ability_script)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
// Ensure the ability script gets initialized with the parameters for the ability.
|
// Ensure the ability script gets initialized with the parameters for the ability.
|
||||||
.on_initialize(self.active_ability().parameters())
|
.on_initialize(self.library, self.active_ability().parameters())
|
||||||
} else {
|
} else {
|
||||||
self.ability_script.clear();
|
self.ability_script.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,7 @@ mod tests {
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
|
|
||||||
use crate::dynamic_data::script_handling::script::ScriptContainer;
|
use crate::dynamic_data::script_handling::script::ScriptContainer;
|
||||||
|
use crate::dynamic_data::DynamicLibrary;
|
||||||
use crate::static_data::EffectParameter;
|
use crate::static_data::EffectParameter;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
@ -273,7 +274,7 @@ mod tests {
|
||||||
|
|
||||||
fn remove_suppression(&self) {}
|
fn remove_suppression(&self) {}
|
||||||
|
|
||||||
fn on_initialize(&self, _pars: &[EffectParameter]) {
|
fn stack(&self) {
|
||||||
self.test_count.fetch_add(1, Ordering::SeqCst);
|
self.test_count.fetch_add(1, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +293,7 @@ mod tests {
|
||||||
let scripts = vec![ScriptWrapper::from(&script)];
|
let scripts = vec![ScriptWrapper::from(&script)];
|
||||||
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||||
}
|
}
|
||||||
let a = script.get_as::<TestScript>();
|
let a = script.get_as::<TestScript>();
|
||||||
assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
|
assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
|
||||||
|
@ -306,7 +307,7 @@ mod tests {
|
||||||
for i in 1..11 {
|
for i in 1..11 {
|
||||||
aggregator.reset();
|
aggregator.reset();
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||||
}
|
}
|
||||||
let a = script.get_as::<TestScript>();
|
let a = script.get_as::<TestScript>();
|
||||||
assert_eq!(a.test_count.load(Ordering::Relaxed), i);
|
assert_eq!(a.test_count.load(Ordering::Relaxed), i);
|
||||||
|
@ -325,7 +326,7 @@ mod tests {
|
||||||
];
|
];
|
||||||
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||||
}
|
}
|
||||||
let a = script1.get_as::<TestScript>();
|
let a = script1.get_as::<TestScript>();
|
||||||
assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
|
assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
|
||||||
|
@ -349,7 +350,7 @@ mod tests {
|
||||||
for i in 1..11 {
|
for i in 1..11 {
|
||||||
aggregator.reset();
|
aggregator.reset();
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||||
}
|
}
|
||||||
let a = script1.get_as::<TestScript>();
|
let a = script1.get_as::<TestScript>();
|
||||||
assert_eq!(a.test_count.load(Ordering::Relaxed), i);
|
assert_eq!(a.test_count.load(Ordering::Relaxed), i);
|
||||||
|
@ -372,7 +373,7 @@ mod tests {
|
||||||
for i in 1..11 {
|
for i in 1..11 {
|
||||||
aggregator.reset();
|
aggregator.reset();
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
v.get().unwrap().read().as_ref().unwrap().stack();
|
||||||
}
|
}
|
||||||
let s = set.at(0);
|
let s = set.at(0);
|
||||||
let s = s.get_as::<TestScript>();
|
let s = s.get_as::<TestScript>();
|
||||||
|
|
|
@ -8,10 +8,10 @@ use std::thread::JoinHandle;
|
||||||
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
|
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
|
||||||
|
|
||||||
use crate::dynamic_data::choices::{MoveChoice, TurnChoice};
|
use crate::dynamic_data::choices::{MoveChoice, TurnChoice};
|
||||||
use crate::dynamic_data::Battle;
|
|
||||||
use crate::dynamic_data::DamageSource;
|
use crate::dynamic_data::DamageSource;
|
||||||
use crate::dynamic_data::ExecutingMove;
|
use crate::dynamic_data::ExecutingMove;
|
||||||
use crate::dynamic_data::Pokemon;
|
use crate::dynamic_data::Pokemon;
|
||||||
|
use crate::dynamic_data::{Battle, DynamicLibrary};
|
||||||
use crate::static_data::{EffectParameter, TypeIdentifier};
|
use crate::static_data::{EffectParameter, TypeIdentifier};
|
||||||
use crate::static_data::{Item, Statistic};
|
use crate::static_data::{Item, Statistic};
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
@ -64,7 +64,7 @@ pub trait Script: Send + Sync {
|
||||||
/// This function is ran when this script stops being in effect, and is removed from its owner.
|
/// This function is ran when this script stops being in effect, and is removed from its owner.
|
||||||
fn on_remove(&self) {}
|
fn on_remove(&self) {}
|
||||||
/// This function is ran when this script starts being in effect.
|
/// This function is ran when this script starts being in effect.
|
||||||
fn on_initialize(&self, _pars: &[EffectParameter]) {}
|
fn on_initialize(&self, _library: &DynamicLibrary, _pars: &[EffectParameter]) {}
|
||||||
/// This function is ran just before the start of the turn. Everyone has made its choices here,
|
/// This function is ran just before the start of the turn. Everyone has made its choices here,
|
||||||
/// and the turn is about to start. This is a great place to initialize data if you need to know
|
/// and the turn is about to start. This is a great place to initialize data if you need to know
|
||||||
/// something has happened during a turn.
|
/// something has happened during a turn.
|
||||||
|
@ -423,7 +423,7 @@ mod tests {
|
||||||
&self.suppressed_count
|
&self.suppressed_count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_initialize(&self, _pars: &[EffectParameter]) {
|
fn stack(&self) {
|
||||||
unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() }
|
unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,7 +451,7 @@ mod tests {
|
||||||
drop(w);
|
drop(w);
|
||||||
// Initialize with the script being taken as read lock. This prevents the script from actually
|
// Initialize with the script being taken as read lock. This prevents the script from actually
|
||||||
// removing itself, as it's still doing things.
|
// removing itself, as it's still doing things.
|
||||||
container.script.read().as_ref().unwrap().on_initialize(&[]);
|
container.script.read().as_ref().unwrap().stack();
|
||||||
// If we now try and get the script, it will be none the first time. This has the side effect
|
// If we now try and get the script, it will be none the first time. This has the side effect
|
||||||
// of actually disposing of the script.
|
// of actually disposing of the script.
|
||||||
assert!(container.get().is_none());
|
assert!(container.get().is_none());
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use core::ffi::c_char;
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem::align_of;
|
use std::mem::{align_of, forget};
|
||||||
|
|
||||||
use wasmer::{Exports, Function, Store};
|
use wasmer::{Exports, Function, Store};
|
||||||
|
|
||||||
|
@ -10,6 +9,7 @@ use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||||
use crate::static_data::{DataLibrary, MoveData, MoveLibrary, StaticData};
|
use crate::static_data::{DataLibrary, MoveData, MoveLibrary, StaticData};
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
macro_rules! register_func {
|
macro_rules! register_func {
|
||||||
($exports: ident, $store: ident, $func: ident) => {
|
($exports: ident, $store: ident, $func: ident) => {
|
||||||
$exports.insert(stringify!($func), Function::new_native($store, $func));
|
$exports.insert(stringify!($func), Function::new_native($store, $func));
|
||||||
|
@ -39,19 +39,22 @@ pub(crate) fn register_webassembly_funcs(exports: &mut Exports, store: &Store, e
|
||||||
|
|
||||||
fn _print(env: &WebAssemblyEnv, p: u32, len: u32) {
|
fn _print(env: &WebAssemblyEnv, p: u32, len: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mem: *mut u8 = env.resolver().memory().data_ptr().offset(p as isize);
|
let mem: *mut u8 = env.data().memory().data_ptr().offset(p as isize);
|
||||||
let s = String::from_raw_parts(mem, len as usize, len as usize);
|
let s = String::from_raw_parts(mem, len as usize, len as usize);
|
||||||
println!("{}", s);
|
println!("{}", s);
|
||||||
|
forget(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _error(env: &WebAssemblyEnv, message: u32, message_len: u32, file: u32, file_len: u32, line: u32, position: u32) {
|
fn _error(env: &WebAssemblyEnv, message: u32, message_len: u32, file: u32, file_len: u32, line: u32, position: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mem: *mut u8 = env.resolver().memory().data_ptr().offset(message as isize);
|
let mem: *mut u8 = env.data().memory().data_ptr().offset(message as isize);
|
||||||
let message = String::from_raw_parts(mem, message_len as usize, message_len as usize);
|
let message = String::from_raw_parts(mem, message_len as usize, message_len as usize);
|
||||||
let mem: *mut u8 = env.resolver().memory().data_ptr().offset(file as isize);
|
let mem: *mut u8 = env.data().memory().data_ptr().offset(file as isize);
|
||||||
let file = String::from_raw_parts(mem, file_len as usize, file_len as usize);
|
let file = String::from_raw_parts(mem, file_len as usize, file_len as usize);
|
||||||
println!("Error: {} in file {}, line: {}:{}", message, file, line, position);
|
println!("Error: {} in file {}, line: {}:{}", message, file, line, position);
|
||||||
|
forget(message);
|
||||||
|
forget(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +62,7 @@ fn move_library_get_move_by_hash(env: &WebAssemblyEnv, lib: ExternRef<MoveLibrar
|
||||||
let lib = lib.value(env).unwrap();
|
let lib = lib.value(env).unwrap();
|
||||||
let m = lib.get_by_hash(hash);
|
let m = lib.get_by_hash(hash);
|
||||||
if let Some(v) = m {
|
if let Some(v) = m {
|
||||||
ExternRef::new(env, v)
|
ExternRef::new(env.data().as_ref(), v)
|
||||||
} else {
|
} else {
|
||||||
ExternRef::null()
|
ExternRef::null()
|
||||||
}
|
}
|
||||||
|
@ -67,7 +70,7 @@ fn move_library_get_move_by_hash(env: &WebAssemblyEnv, lib: ExternRef<MoveLibrar
|
||||||
|
|
||||||
fn move_data_get_name(env: &WebAssemblyEnv, move_data: ExternRef<MoveData>) -> ExternRef<StringKey> {
|
fn move_data_get_name(env: &WebAssemblyEnv, move_data: ExternRef<MoveData>) -> ExternRef<StringKey> {
|
||||||
let move_data = move_data.value(env).unwrap();
|
let move_data = move_data.value(env).unwrap();
|
||||||
ExternRef::new(env, move_data.name())
|
ExternRef::new(env.data().as_ref(), move_data.name())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_data_get_base_power(env: &WebAssemblyEnv, move_data: ExternRef<MoveData>) -> u8 {
|
fn move_data_get_base_power(env: &WebAssemblyEnv, move_data: ExternRef<MoveData>) -> u8 {
|
||||||
|
@ -80,12 +83,15 @@ fn const_string_get_hash(env: &WebAssemblyEnv, string_key: ExternRef<StringKey>)
|
||||||
|
|
||||||
fn const_string_get_str(env: &WebAssemblyEnv, string_key: ExternRef<StringKey>) -> u32 {
|
fn const_string_get_str(env: &WebAssemblyEnv, string_key: ExternRef<StringKey>) -> u32 {
|
||||||
let string_key = string_key.value(env).unwrap().str();
|
let string_key = string_key.value(env).unwrap().str();
|
||||||
let s: CString = CString::new(string_key.as_bytes()).unwrap();
|
|
||||||
let wasm_string_ptr = env
|
let wasm_string_ptr = env
|
||||||
.resolver()
|
.data()
|
||||||
.allocate_mem(string_key.len() as u32, align_of::<CString>() as u32);
|
.allocate_mem((string_key.len() + 1) as u32, align_of::<CString>() as u32);
|
||||||
let mut wasm_string = unsafe { CString::from_raw(wasm_string_ptr.0 as *mut c_char) };
|
let mut wasm_string: Vec<u8> =
|
||||||
s.clone_into(&mut wasm_string);
|
unsafe { Vec::from_raw_parts(wasm_string_ptr.0, string_key.len() + 1, string_key.len() + 1) };
|
||||||
|
wasm_string.resize(string_key.len() + 1, 0);
|
||||||
|
string_key.as_bytes().clone_into(&mut wasm_string);
|
||||||
|
wasm_string.insert(string_key.len(), 0 as u8);
|
||||||
|
forget(wasm_string);
|
||||||
wasm_string_ptr.1
|
wasm_string_ptr.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,9 +99,9 @@ fn battle_library_get_data_library(
|
||||||
env: &WebAssemblyEnv,
|
env: &WebAssemblyEnv,
|
||||||
dynamic_lib: ExternRef<DynamicLibrary>,
|
dynamic_lib: ExternRef<DynamicLibrary>,
|
||||||
) -> ExternRef<StaticData> {
|
) -> ExternRef<StaticData> {
|
||||||
ExternRef::new(env, dynamic_lib.value(env).unwrap().static_data())
|
ExternRef::new(env.data().as_ref(), dynamic_lib.value(env).unwrap().static_data())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data_library_get_move_library(env: &WebAssemblyEnv, data_library: ExternRef<StaticData>) -> ExternRef<MoveLibrary> {
|
fn data_library_get_move_library(env: &WebAssemblyEnv, data_library: ExternRef<StaticData>) -> ExternRef<MoveLibrary> {
|
||||||
ExternRef::new(env, data_library.value(env).unwrap().moves())
|
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().moves())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,19 @@ use std::marker::PhantomData;
|
||||||
use unique_type_id::UniqueTypeId;
|
use unique_type_id::UniqueTypeId;
|
||||||
use wasmer::FromToNativeWasmType;
|
use wasmer::FromToNativeWasmType;
|
||||||
|
|
||||||
use crate::script_implementations::wasm::script_resolver::{WebAssemblyEnv, WebAssemblyScriptResolver};
|
use crate::script_implementations::wasm::script_resolver::{
|
||||||
|
WebAssemblyEnv, WebAssemblyEnvironmentData, WebAssemblyScriptResolver,
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) struct ExternRef<T: UniqueTypeId<u64>> {
|
pub(crate) struct ExternRef<T: UniqueTypeId<u64> + ?Sized> {
|
||||||
index: u32,
|
index: u32,
|
||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: UniqueTypeId<u64>> ExternRef<T> {
|
impl<T: UniqueTypeId<u64>> ExternRef<T> {
|
||||||
pub fn new(env: &WebAssemblyEnv, value: &T) -> Self {
|
pub fn new(env: &WebAssemblyEnvironmentData, value: &T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
index: env.resolver().get_extern_ref_index(value),
|
index: env.get_extern_ref_index(value),
|
||||||
_phantom: Default::default(),
|
_phantom: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +39,7 @@ impl<T: UniqueTypeId<u64>> ExternRef<T> {
|
||||||
/// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the
|
/// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the
|
||||||
/// value when it was passed before. If these types do not match, this will panic.
|
/// value when it was passed before. If these types do not match, this will panic.
|
||||||
pub fn value<'a, 'b>(&'a self, env: &'b WebAssemblyEnv) -> Option<&'b T> {
|
pub fn value<'a, 'b>(&'a self, env: &'b WebAssemblyEnv) -> Option<&'b T> {
|
||||||
let ptr = env.resolver().get_extern_ref_value(self.index) as *const T;
|
let ptr = env.data().get_extern_ref_value(self.index) as *const T;
|
||||||
unsafe { ptr.as_ref() }
|
unsafe { ptr.as_ref() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize};
|
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize};
|
||||||
|
use std::sync::Weak;
|
||||||
|
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
use wasmer::NativeFunc;
|
||||||
|
|
||||||
use crate::dynamic_data::Script;
|
use crate::dynamic_data::{DynamicLibrary, Script};
|
||||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver;
|
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||||
|
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData;
|
||||||
use crate::script_implementations::wasm::WebAssemblyScriptCapabilities;
|
use crate::script_implementations::wasm::WebAssemblyScriptCapabilities;
|
||||||
|
use crate::static_data::EffectParameter;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
/// A WebAssemblyScript is there to implement the Script trait within WebAssemblyScript.
|
/// A WebAssemblyScript is there to implement the Script trait within WebAssemblyScript.
|
||||||
|
@ -25,8 +29,8 @@ pub struct WebAssemblyScript {
|
||||||
self_ptr: u32,
|
self_ptr: u32,
|
||||||
/// Capabilities define which functions we actually implement.
|
/// Capabilities define which functions we actually implement.
|
||||||
capabilities: AtomicPtr<HashSet<WebAssemblyScriptCapabilities>>,
|
capabilities: AtomicPtr<HashSet<WebAssemblyScriptCapabilities>>,
|
||||||
/// A reference back to our resolver.
|
/// The global runtime environment data.
|
||||||
resolver: AtomicPtr<WebAssemblyScriptResolver>,
|
environment: Weak<WebAssemblyEnvironmentData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebAssemblyScript {
|
impl WebAssemblyScript {
|
||||||
|
@ -35,7 +39,7 @@ impl WebAssemblyScript {
|
||||||
owner_ptr: *mut u8,
|
owner_ptr: *mut u8,
|
||||||
self_ptr: u32,
|
self_ptr: u32,
|
||||||
capabilities: *mut HashSet<WebAssemblyScriptCapabilities>,
|
capabilities: *mut HashSet<WebAssemblyScriptCapabilities>,
|
||||||
resolver: *mut WebAssemblyScriptResolver,
|
environment: Weak<WebAssemblyEnvironmentData>,
|
||||||
name: StringKey,
|
name: StringKey,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -45,7 +49,7 @@ impl WebAssemblyScript {
|
||||||
owner_ptr: AtomicPtr::new(owner_ptr),
|
owner_ptr: AtomicPtr::new(owner_ptr),
|
||||||
self_ptr,
|
self_ptr,
|
||||||
capabilities: AtomicPtr::new(capabilities),
|
capabilities: AtomicPtr::new(capabilities),
|
||||||
resolver: AtomicPtr::new(resolver),
|
environment,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +67,16 @@ impl Script for WebAssemblyScript {
|
||||||
&self.suppressed_count
|
&self.suppressed_count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_initialize(&self, library: &DynamicLibrary, _pars: &[EffectParameter]) {
|
||||||
|
let env = self.environment.upgrade().unwrap();
|
||||||
|
let exported = env.exported_functions();
|
||||||
|
if let Some(f) = exported.get(&"script_on_initialize".into()) {
|
||||||
|
let func: NativeFunc<(u32, ExternRef<DynamicLibrary>, u32), ()> = f.native().unwrap();
|
||||||
|
func.call(self.self_ptr, ExternRef::new(env.as_ref(), library), 0)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::ops::DerefMut;
|
use std::sync::{Arc, Weak};
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use parking_lot::lock_api::{MappedRwLockReadGuard, RwLockReadGuard};
|
use parking_lot::lock_api::{MappedRwLockReadGuard, RwLockReadGuard};
|
||||||
use parking_lot::{RawRwLock, RwLock};
|
use parking_lot::{RawRwLock, RwLock};
|
||||||
use unique_type_id::{TypeId, UniqueTypeId};
|
use unique_type_id::UniqueTypeId;
|
||||||
use wasmer::{
|
use wasmer::{
|
||||||
Cranelift, Exports, Extern, Features, Function, ImportObject, Instance, Memory, Module, NativeFunc, Store,
|
Cranelift, Exports, Extern, Features, Function, ImportObject, Instance, Memory, Module, NativeFunc, Store,
|
||||||
Universal, Value, WasmerEnv,
|
Universal, Value, WasmerEnv,
|
||||||
|
@ -28,8 +27,6 @@ pub struct WebAssemblyScriptResolver {
|
||||||
/// Our currently loaded WASM instances. Empty until finalize() is called, after which the loaded modules get turned
|
/// Our currently loaded WASM instances. Empty until finalize() is called, after which the loaded modules get turned
|
||||||
/// into actual instances.
|
/// into actual instances.
|
||||||
instances: Vec<Instance>,
|
instances: Vec<Instance>,
|
||||||
/// This is a map of all the functions that WASM gives us.
|
|
||||||
exported_functions: HashMap<StringKey, Function>,
|
|
||||||
|
|
||||||
/// This is the WASM function to load a script.
|
/// This is the WASM function to load a script.
|
||||||
load_script_fn: Option<NativeFunc<(u8, ExternRef<StringKey>), u32>>,
|
load_script_fn: Option<NativeFunc<(u8, ExternRef<StringKey>), u32>>,
|
||||||
|
@ -64,7 +61,6 @@ impl WebAssemblyScriptResolver {
|
||||||
store,
|
store,
|
||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
instances: Default::default(),
|
instances: Default::default(),
|
||||||
exported_functions: Default::default(),
|
|
||||||
load_script_fn: None,
|
load_script_fn: None,
|
||||||
script_capabilities: Default::default(),
|
script_capabilities: Default::default(),
|
||||||
environment_data: Arc::new(Default::default()),
|
environment_data: Arc::new(Default::default()),
|
||||||
|
@ -84,22 +80,21 @@ impl WebAssemblyScriptResolver {
|
||||||
let mut imports = ImportObject::new();
|
let mut imports = ImportObject::new();
|
||||||
let mut exports = Exports::new();
|
let mut exports = Exports::new();
|
||||||
|
|
||||||
let env = WebAssemblyEnv {
|
let env = WebAssemblyEnv::new(Arc::downgrade(&self.environment_data));
|
||||||
resolver: self.environment_data.clone(),
|
|
||||||
};
|
|
||||||
register_webassembly_funcs(&mut exports, &self.store, env);
|
register_webassembly_funcs(&mut exports, &self.store, env);
|
||||||
imports.register("env", exports);
|
imports.register("env", exports);
|
||||||
|
|
||||||
for module in &self.modules {
|
for module in &self.modules {
|
||||||
let instance = Instance::new(module, &imports).unwrap();
|
let instance = Instance::new(module, &imports).unwrap();
|
||||||
let exports = &instance.exports;
|
let exports = &instance.exports;
|
||||||
|
let mut exported_functions = self.environment_data.exported_functions.write();
|
||||||
for export in exports.iter() {
|
for export in exports.iter() {
|
||||||
match export.1 {
|
match export.1 {
|
||||||
Extern::Function(f) => {
|
Extern::Function(f) => {
|
||||||
self.exported_functions.insert(export.0.as_str().into(), f.clone());
|
exported_functions.insert(export.0.as_str().into(), f.clone());
|
||||||
}
|
}
|
||||||
Extern::Memory(m) => {
|
Extern::Memory(m) => {
|
||||||
self.environment_data.memory.write().insert(m.clone());
|
let _ = self.environment_data.memory.write().insert(m.clone());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -107,11 +102,12 @@ impl WebAssemblyScriptResolver {
|
||||||
if let Some(m) = &self.environment_data.memory.read().as_ref() {
|
if let Some(m) = &self.environment_data.memory.read().as_ref() {
|
||||||
m.grow(32).unwrap();
|
m.grow(32).unwrap();
|
||||||
}
|
}
|
||||||
if let Some(f) = self.exported_functions.get(&"load_script".into()) {
|
if let Some(f) = exported_functions.get(&"load_script".into()) {
|
||||||
self.load_script_fn = Some(f.native().unwrap())
|
self.load_script_fn = Some(f.native().unwrap())
|
||||||
}
|
}
|
||||||
if let Some(f) = self.exported_functions.get(&"allocate_mem".into()) {
|
if let Some(f) = exported_functions.get(&"allocate_mem".into()) {
|
||||||
self.environment_data
|
let _ = self
|
||||||
|
.environment_data
|
||||||
.allocate_mem_fn
|
.allocate_mem_fn
|
||||||
.write()
|
.write()
|
||||||
.insert(f.native().unwrap());
|
.insert(f.native().unwrap());
|
||||||
|
@ -151,7 +147,12 @@ impl ScriptResolver for WebAssemblyScriptResolver {
|
||||||
if !self.script_capabilities.read().contains_key(&key) {
|
if !self.script_capabilities.read().contains_key(&key) {
|
||||||
let mut capabilities = HashSet::new();
|
let mut capabilities = HashSet::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(get_cap) = self.exported_functions.get(&"get_script_capabilities".into()) {
|
if let Some(get_cap) = self
|
||||||
|
.environment_data
|
||||||
|
.exported_functions
|
||||||
|
.read()
|
||||||
|
.get(&"get_script_capabilities".into())
|
||||||
|
{
|
||||||
let res = get_cap.call(&[Value::I32(script as i32)]).unwrap();
|
let res = get_cap.call(&[Value::I32(script as i32)]).unwrap();
|
||||||
let ptr = (self.environment_data.memory.read().as_ref().unwrap().data_ptr()
|
let ptr = (self.environment_data.memory.read().as_ref().unwrap().data_ptr()
|
||||||
as *const WebAssemblyScriptCapabilities)
|
as *const WebAssemblyScriptCapabilities)
|
||||||
|
@ -173,7 +174,7 @@ impl ScriptResolver for WebAssemblyScriptResolver {
|
||||||
script,
|
script,
|
||||||
capabilities as *const HashSet<WebAssemblyScriptCapabilities>
|
capabilities as *const HashSet<WebAssemblyScriptCapabilities>
|
||||||
as *mut HashSet<WebAssemblyScriptCapabilities>,
|
as *mut HashSet<WebAssemblyScriptCapabilities>,
|
||||||
self as *const WebAssemblyScriptResolver as *mut WebAssemblyScriptResolver,
|
Arc::downgrade(&self.environment_data),
|
||||||
script_key.clone(),
|
script_key.clone(),
|
||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
|
@ -200,30 +201,44 @@ pub struct WebAssemblyEnvironmentData {
|
||||||
extern_ref_pointers: RwLock<Vec<*const u8>>,
|
extern_ref_pointers: RwLock<Vec<*const u8>>,
|
||||||
/// To make sure we send the same identifier to WASM when we send the same piece of data multiple times, we have a
|
/// To make sure we send the same identifier to WASM when we send the same piece of data multiple times, we have a
|
||||||
/// backwards lookup on extern_ref_pointers. This allows us to get the index for a given piece of data.
|
/// backwards lookup on extern_ref_pointers. This allows us to get the index for a given piece of data.
|
||||||
extern_ref_pointers_lookup: RwLock<HashMap<*const u8, u32>>,
|
extern_ref_pointers_lookup: RwLock<HashMap<ExternRefLookupKey, u32>>,
|
||||||
/// As an added security measure on our extern refs, we keep track of the types of the extern ref data we've sent.
|
/// As an added security measure on our extern refs, we keep track of the types of the extern ref data we've sent.
|
||||||
/// This prevents illegal arbitrary memory operations, where we expect type X, but the actual type is Y, which would
|
/// This prevents illegal arbitrary memory operations, where we expect type X, but the actual type is Y, which would
|
||||||
/// allow for modifying memory we might not want to. If we get a type mismatch, we will panic, preventing this.
|
/// allow for modifying memory we might not want to. If we get a type mismatch, we will panic, preventing this.
|
||||||
extern_ref_type_lookup: RwLock<HashMap<*const u8, TypeId<u64>>>,
|
extern_ref_type_lookup: RwLock<HashSet<ExternRefLookupKey>>,
|
||||||
|
|
||||||
/// The memory inside of the WASM container.
|
/// The memory inside of the WASM container.
|
||||||
memory: RwLock<Option<Memory>>,
|
memory: RwLock<Option<Memory>>,
|
||||||
|
|
||||||
|
/// This is a map of all the functions that WASM gives us.
|
||||||
|
exported_functions: RwLock<HashMap<StringKey, Function>>,
|
||||||
|
|
||||||
/// This is the WASM function to allocate memory inside the WASM container.
|
/// This is the WASM function to allocate memory inside the WASM container.
|
||||||
allocate_mem_fn: RwLock<Option<NativeFunc<(u32, u32), u32>>>,
|
allocate_mem_fn: RwLock<Option<NativeFunc<(u32, u32), u32>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
|
struct ExternRefLookupKey {
|
||||||
|
pub ptr: *const u8,
|
||||||
|
pub t: u64,
|
||||||
|
}
|
||||||
|
|
||||||
impl WebAssemblyEnvironmentData {
|
impl WebAssemblyEnvironmentData {
|
||||||
/// This returns the memory of the WASM container.
|
/// This returns the memory of the WASM container.
|
||||||
pub fn memory(&self) -> MappedRwLockReadGuard<'_, RawRwLock, Memory> {
|
pub fn memory(&self) -> MappedRwLockReadGuard<'_, RawRwLock, Memory> {
|
||||||
RwLockReadGuard::map(self.memory.read(), |a| a.as_ref().unwrap())
|
RwLockReadGuard::map(self.memory.read(), |a| a.as_ref().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This returns the functions exported from WASM.
|
||||||
|
pub fn exported_functions(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Function>> {
|
||||||
|
self.exported_functions.read()
|
||||||
|
}
|
||||||
|
|
||||||
/// Allocates memory inside the WASM container with a given size and alignment. This memory is
|
/// Allocates memory inside the WASM container with a given size and alignment. This memory is
|
||||||
/// owned by WASM, and is how we can pass memory references that the host allocated to WASM.
|
/// owned by WASM, and is how we can pass memory references that the host allocated to WASM.
|
||||||
/// The return is a tuple containing both the actual pointer to the memory (usable by the host),
|
/// The return is a tuple containing both the actual pointer to the memory (usable by the host),
|
||||||
/// and the WASM offset to the memory (usable by the client).
|
/// and the WASM offset to the memory (usable by the client).
|
||||||
pub fn allocate_mem(&self, size: u32, align: u32) -> (*const u8, u32) {
|
pub fn allocate_mem(&self, size: u32, align: u32) -> (*mut u8, u32) {
|
||||||
let wasm_ptr = self.allocate_mem_fn.read().as_ref().unwrap().call(size, align).unwrap();
|
let wasm_ptr = self.allocate_mem_fn.read().as_ref().unwrap().call(size, align).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
(
|
(
|
||||||
|
@ -246,7 +261,11 @@ impl WebAssemblyEnvironmentData {
|
||||||
/// of this code.
|
/// of this code.
|
||||||
pub fn get_extern_ref_index<T: UniqueTypeId<u64>>(&self, value: &T) -> u32 {
|
pub fn get_extern_ref_index<T: UniqueTypeId<u64>>(&self, value: &T) -> u32 {
|
||||||
let ptr = value as *const T as *const u8;
|
let ptr = value as *const T as *const u8;
|
||||||
if let Some(v) = self.extern_ref_pointers_lookup.read().get(&ptr) {
|
if let Some(v) = self
|
||||||
|
.extern_ref_pointers_lookup
|
||||||
|
.read()
|
||||||
|
.get(&ExternRefLookupKey { ptr, t: T::id().0 })
|
||||||
|
{
|
||||||
return *v as u32;
|
return *v as u32;
|
||||||
}
|
}
|
||||||
let index = {
|
let index = {
|
||||||
|
@ -254,8 +273,12 @@ impl WebAssemblyEnvironmentData {
|
||||||
extern_ref_guard.push(ptr);
|
extern_ref_guard.push(ptr);
|
||||||
extern_ref_guard.len() as u32
|
extern_ref_guard.len() as u32
|
||||||
};
|
};
|
||||||
self.extern_ref_pointers_lookup.write().insert(ptr, index);
|
self.extern_ref_pointers_lookup
|
||||||
self.extern_ref_type_lookup.write().insert(ptr, T::id());
|
.write()
|
||||||
|
.insert(ExternRefLookupKey { ptr, t: T::id().0 }, index);
|
||||||
|
self.extern_ref_type_lookup
|
||||||
|
.write()
|
||||||
|
.insert(ExternRefLookupKey { ptr, t: T::id().0 });
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,8 +287,15 @@ impl WebAssemblyEnvironmentData {
|
||||||
pub fn get_extern_ref_value<T: UniqueTypeId<u64>>(&self, index: u32) -> &T {
|
pub fn get_extern_ref_value<T: UniqueTypeId<u64>>(&self, index: u32) -> &T {
|
||||||
let read_guard = self.extern_ref_pointers.read();
|
let read_guard = self.extern_ref_pointers.read();
|
||||||
let ptr = read_guard.get((index - 1) as usize).unwrap();
|
let ptr = read_guard.get((index - 1) as usize).unwrap();
|
||||||
let expected_type_id = &self.extern_ref_type_lookup.read()[ptr];
|
if self
|
||||||
if expected_type_id.0 != T::id().0 {
|
.extern_ref_type_lookup
|
||||||
|
.read()
|
||||||
|
.get(&ExternRefLookupKey {
|
||||||
|
ptr: *ptr,
|
||||||
|
t: T::id().0,
|
||||||
|
})
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
panic!(
|
panic!(
|
||||||
"Extern ref was accessed with wrong type. Requested type {}, but this was not the type the extern ref was stored with.",
|
"Extern ref was accessed with wrong type. Requested type {}, but this was not the type the extern ref was stored with.",
|
||||||
std::any::type_name::<T>()
|
std::any::type_name::<T>()
|
||||||
|
@ -280,13 +310,18 @@ impl WebAssemblyEnvironmentData {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct WebAssemblyEnv {
|
pub(crate) struct WebAssemblyEnv {
|
||||||
/// A pointer to the WebAssemblyScriptResolver belonging to the current script environment.
|
/// A pointer to the WebAssemblyScriptResolver belonging to the current script environment.
|
||||||
pub resolver: Arc<WebAssemblyEnvironmentData>,
|
data: Weak<WebAssemblyEnvironmentData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebAssemblyEnv {
|
impl WebAssemblyEnv {
|
||||||
/// Get the WebAssemblyScriptResolver belonging to the current context.
|
/// Instantiates a new Environment with the requested data.
|
||||||
pub fn resolver(&self) -> &Arc<WebAssemblyEnvironmentData> {
|
pub fn new(data: Weak<WebAssemblyEnvironmentData>) -> Self {
|
||||||
&self.resolver
|
Self { data }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the actual data belonging to the current context.
|
||||||
|
pub fn data(&self) -> Arc<WebAssemblyEnvironmentData> {
|
||||||
|
self.data.upgrade().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,4 +329,8 @@ unsafe impl Sync for WebAssemblyEnv {}
|
||||||
|
|
||||||
unsafe impl Send for WebAssemblyEnv {}
|
unsafe impl Send for WebAssemblyEnv {}
|
||||||
|
|
||||||
|
unsafe impl Sync for WebAssemblyEnvironmentData {}
|
||||||
|
|
||||||
|
unsafe impl Send for WebAssemblyEnvironmentData {}
|
||||||
|
|
||||||
impl WasmerEnv for WebAssemblyEnv {}
|
impl WasmerEnv for WebAssemblyEnv {}
|
||||||
|
|
Binary file not shown.
|
@ -56,5 +56,5 @@ fn validate_script() {
|
||||||
.load_script(0 as *const u8, ScriptCategory::Move, &"test".into())
|
.load_script(0 as *const u8, ScriptCategory::Move, &"test".into())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
script.on_initialize(&[]);
|
script.on_initialize(&lib, &[]);
|
||||||
}
|
}
|
||||||
|
|
15
types.toml
15
types.toml
|
@ -1,15 +0,0 @@
|
||||||
MoveLibrary = 0
|
|
||||||
MoveData = 1
|
|
||||||
StringKey = 2
|
|
||||||
DynamicLibrary = 3
|
|
||||||
StaticData = 4
|
|
||||||
DynamicLibrary = 0
|
|
||||||
MoveLibrary = 1
|
|
||||||
StaticData = 2
|
|
||||||
MoveData = 3
|
|
||||||
StringKey = 4
|
|
||||||
DynamicLibrary = 0
|
|
||||||
MoveLibrary = 1
|
|
||||||
StaticData = 2
|
|
||||||
MoveData = 3
|
|
||||||
StringKey = 4
|
|
Loading…
Reference in New Issue