2022-07-18 08:16:47 +00:00
|
|
|
use std::fmt::{Debug, Formatter};
|
2022-08-20 10:22:12 +00:00
|
|
|
use std::mem::{align_of, size_of};
|
2022-07-18 13:36:03 +00:00
|
|
|
use std::sync::{Arc, Weak};
|
2022-07-18 08:16:47 +00:00
|
|
|
|
|
|
|
use hashbrown::{HashMap, HashSet};
|
2022-07-18 11:18:11 +00:00
|
|
|
use parking_lot::lock_api::{MappedRwLockReadGuard, RwLockReadGuard};
|
|
|
|
use parking_lot::{RawRwLock, RwLock};
|
2022-07-18 13:36:03 +00:00
|
|
|
use unique_type_id::UniqueTypeId;
|
2022-07-18 08:16:47 +00:00
|
|
|
use wasmer::{
|
|
|
|
Cranelift, Exports, Extern, Features, Function, ImportObject, Instance, Memory, Module, NativeFunc, Store,
|
2022-07-18 11:18:11 +00:00
|
|
|
Universal, Value, WasmerEnv,
|
2022-07-18 08:16:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
use crate::dynamic_data::{ItemScript, Script, ScriptResolver};
|
|
|
|
use crate::script_implementations::wasm::export_registry::register_webassembly_funcs;
|
|
|
|
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
|
|
|
use crate::script_implementations::wasm::script::WebAssemblyScript;
|
2022-08-20 10:22:12 +00:00
|
|
|
use crate::script_implementations::wasm::script_function_cache::ScriptFunctionCache;
|
|
|
|
use crate::script_implementations::wasm::temp_wasm_allocator::{AllocatedObject, TempWasmAllocator};
|
2022-07-18 08:16:47 +00:00
|
|
|
use crate::script_implementations::wasm::WebAssemblyScriptCapabilities;
|
|
|
|
use crate::static_data::Item;
|
|
|
|
use crate::{PkmnResult, ScriptCategory, StringKey};
|
|
|
|
|
|
|
|
/// A WebAssembly script resolver implements the dynamic scripts functionality with WebAssembly.
|
|
|
|
pub struct WebAssemblyScriptResolver {
|
2022-07-18 11:18:11 +00:00
|
|
|
/// The global state storage of WASM.
|
2022-07-18 08:16:47 +00:00
|
|
|
store: Store,
|
2022-07-18 11:18:11 +00:00
|
|
|
/// The WASM modules we have loaded.
|
|
|
|
modules: Vec<Module>,
|
|
|
|
/// Our currently loaded WASM instances. Empty until finalize() is called, after which the loaded modules get turned
|
|
|
|
/// into actual instances.
|
|
|
|
instances: Vec<Instance>,
|
|
|
|
|
|
|
|
/// This is the WASM function to load a script.
|
2022-07-18 08:16:47 +00:00
|
|
|
load_script_fn: Option<NativeFunc<(u8, ExternRef<StringKey>), u32>>,
|
2022-07-18 11:18:11 +00:00
|
|
|
|
|
|
|
/// Script capabilities tell us which functions are implemented on a given script. This allows us to skip unneeded
|
|
|
|
/// WASM calls.
|
2022-08-20 10:22:12 +00:00
|
|
|
script_capabilities: RwLock<HashMap<ScriptCapabilitiesKey, Arc<HashSet<WebAssemblyScriptCapabilities>>>>,
|
2022-07-18 08:16:47 +00:00
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
environment_data: Arc<WebAssemblyEnvironmentData>,
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
/// This struct allows us to index a hashmap with both a category and name of a script.
|
2022-07-18 08:16:47 +00:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
|
|
|
struct ScriptCapabilitiesKey {
|
2022-07-18 11:18:11 +00:00
|
|
|
/// The category for the script we're looking for capabilities for.
|
2022-07-18 08:16:47 +00:00
|
|
|
category: ScriptCategory,
|
2022-07-18 11:18:11 +00:00
|
|
|
/// The name of the script we're looking for capabilities for.
|
2022-07-18 08:16:47 +00:00
|
|
|
script_key: StringKey,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WebAssemblyScriptResolver {
|
|
|
|
/// Instantiates a new WebAssemblyScriptResolver.
|
2022-07-18 08:49:58 +00:00
|
|
|
pub fn new() -> Box<WebAssemblyScriptResolver> {
|
2022-07-18 08:16:47 +00:00
|
|
|
let config = Cranelift::default();
|
|
|
|
let mut features = Features::new();
|
|
|
|
features.multi_value = true;
|
|
|
|
features.reference_types = true;
|
|
|
|
let universal = Universal::new(config).features(features);
|
|
|
|
let engine = universal.engine();
|
|
|
|
let store = Store::new(&engine);
|
2022-07-18 08:49:58 +00:00
|
|
|
let s = Self {
|
2022-07-18 08:16:47 +00:00
|
|
|
store,
|
2022-07-18 11:18:11 +00:00
|
|
|
modules: Default::default(),
|
|
|
|
instances: Default::default(),
|
2022-07-18 08:16:47 +00:00
|
|
|
load_script_fn: None,
|
|
|
|
script_capabilities: Default::default(),
|
2022-07-18 11:18:11 +00:00
|
|
|
environment_data: Arc::new(Default::default()),
|
2022-07-18 08:49:58 +00:00
|
|
|
};
|
|
|
|
Box::new(s)
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Load a compiled WASM module.
|
|
|
|
pub fn load_wasm_from_bytes(&mut self, bytes: &[u8]) {
|
|
|
|
// FIXME: Error handling
|
|
|
|
let module = Module::new(&self.store, bytes).unwrap();
|
2022-07-18 11:18:11 +00:00
|
|
|
self.modules.push(module);
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Initialise all the data we need.
|
2022-07-18 11:18:11 +00:00
|
|
|
pub fn finalize(&mut self) {
|
2022-07-18 08:16:47 +00:00
|
|
|
let mut imports = ImportObject::new();
|
|
|
|
let mut exports = Exports::new();
|
|
|
|
|
2022-07-18 13:36:03 +00:00
|
|
|
let env = WebAssemblyEnv::new(Arc::downgrade(&self.environment_data));
|
2022-07-18 08:16:47 +00:00
|
|
|
register_webassembly_funcs(&mut exports, &self.store, env);
|
|
|
|
imports.register("env", exports);
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
for module in &self.modules {
|
2022-08-20 10:22:12 +00:00
|
|
|
for import in module.imports() {
|
|
|
|
if imports.get_export("env", import.name()).is_none() {
|
|
|
|
println!(
|
|
|
|
"\x1b[91mMissing import: \"{}\" with type: {:?} \x1b[0m",
|
|
|
|
import.name(),
|
|
|
|
import.ty()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
let instance = Instance::new(module, &imports).unwrap();
|
|
|
|
let exports = &instance.exports;
|
2022-08-20 10:22:12 +00:00
|
|
|
|
|
|
|
let init_fn = exports.get_extern("_init");
|
|
|
|
if let Some(init_fn) = init_fn {
|
|
|
|
if let Extern::Function(init_fn) = init_fn {
|
|
|
|
init_fn.call(&[]).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:36:03 +00:00
|
|
|
let mut exported_functions = self.environment_data.exported_functions.write();
|
2022-07-18 11:18:11 +00:00
|
|
|
for export in exports.iter() {
|
|
|
|
match export.1 {
|
|
|
|
Extern::Function(f) => {
|
2022-07-18 13:36:03 +00:00
|
|
|
exported_functions.insert(export.0.as_str().into(), f.clone());
|
2022-07-18 11:18:11 +00:00
|
|
|
}
|
|
|
|
Extern::Memory(m) => {
|
2022-07-18 13:36:03 +00:00
|
|
|
let _ = self.environment_data.memory.write().insert(m.clone());
|
2022-07-18 11:18:11 +00:00
|
|
|
}
|
|
|
|
_ => {}
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-18 11:18:11 +00:00
|
|
|
if let Some(m) = &self.environment_data.memory.read().as_ref() {
|
|
|
|
m.grow(32).unwrap();
|
|
|
|
}
|
2022-08-20 10:22:12 +00:00
|
|
|
if let Some(f) = exported_functions.get::<StringKey>(&"load_script".into()) {
|
2022-07-18 11:18:11 +00:00
|
|
|
self.load_script_fn = Some(f.native().unwrap())
|
|
|
|
}
|
2022-08-20 10:22:12 +00:00
|
|
|
if let Some(f) = exported_functions.get::<StringKey>(&"allocate_mem".into()) {
|
2022-07-18 13:36:03 +00:00
|
|
|
let _ = self
|
|
|
|
.environment_data
|
2022-07-18 11:18:11 +00:00
|
|
|
.allocate_mem_fn
|
|
|
|
.write()
|
|
|
|
.insert(f.native().unwrap());
|
2022-08-20 10:22:12 +00:00
|
|
|
|
|
|
|
let temp_memory_slab = self.environment_data.allocate_mem(128, 1);
|
|
|
|
let _ = self
|
|
|
|
.environment_data
|
|
|
|
.temp_allocator
|
|
|
|
.write()
|
|
|
|
.insert(TempWasmAllocator::new(temp_memory_slab.0, temp_memory_slab.1));
|
2022-07-18 11:18:11 +00:00
|
|
|
}
|
|
|
|
self.instances.push(instance);
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
/// Gets the data passed to every function as environment data.
|
|
|
|
pub fn environment_data(&self) -> &Arc<WebAssemblyEnvironmentData> {
|
|
|
|
&self.environment_data
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ScriptResolver for WebAssemblyScriptResolver {
|
|
|
|
fn load_script(
|
|
|
|
&self,
|
|
|
|
owner: *const u8,
|
|
|
|
category: ScriptCategory,
|
|
|
|
script_key: &StringKey,
|
|
|
|
) -> PkmnResult<Option<Arc<dyn Script>>> {
|
|
|
|
let script = self
|
|
|
|
.load_script_fn
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
2022-07-18 11:18:11 +00:00
|
|
|
.call(category as u8, ExternRef::new_with_resolver(self, script_key))
|
2022-07-18 08:16:47 +00:00
|
|
|
.unwrap();
|
|
|
|
if script == 0 {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
let key = ScriptCapabilitiesKey {
|
|
|
|
category,
|
|
|
|
script_key: script_key.clone(),
|
|
|
|
};
|
|
|
|
|
|
|
|
if !self.script_capabilities.read().contains_key(&key) {
|
|
|
|
let mut capabilities = HashSet::new();
|
|
|
|
unsafe {
|
2022-07-18 13:36:03 +00:00
|
|
|
if let Some(get_cap) = self
|
|
|
|
.environment_data
|
|
|
|
.exported_functions
|
|
|
|
.read()
|
2022-08-20 10:22:12 +00:00
|
|
|
.get::<StringKey>(&"get_script_capabilities".into())
|
2022-07-18 13:36:03 +00:00
|
|
|
{
|
2022-07-18 08:16:47 +00:00
|
|
|
let res = get_cap.call(&[Value::I32(script as i32)]).unwrap();
|
2022-07-18 11:18:11 +00:00
|
|
|
let ptr = (self.environment_data.memory.read().as_ref().unwrap().data_ptr()
|
|
|
|
as *const WebAssemblyScriptCapabilities)
|
2022-07-18 08:16:47 +00:00
|
|
|
.offset(res[0].i32().unwrap() as isize);
|
|
|
|
let length = res[1].i32().unwrap() as usize;
|
|
|
|
for i in 0..length {
|
2022-07-18 11:18:11 +00:00
|
|
|
capabilities.insert(*ptr.add(i));
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-20 10:22:12 +00:00
|
|
|
self.script_capabilities
|
|
|
|
.write()
|
|
|
|
.insert(key.clone(), Arc::new(capabilities));
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let read_guard = self.script_capabilities.read();
|
|
|
|
let capabilities = read_guard.get(&key).unwrap();
|
|
|
|
|
|
|
|
Ok(Some(Arc::new(WebAssemblyScript::new(
|
|
|
|
owner as *mut u8,
|
|
|
|
script,
|
2022-08-20 10:22:12 +00:00
|
|
|
capabilities.clone(),
|
2022-07-18 13:36:03 +00:00
|
|
|
Arc::downgrade(&self.environment_data),
|
2022-07-18 08:16:47 +00:00
|
|
|
script_key.clone(),
|
|
|
|
))))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn load_item_script(&self, _key: &Item) -> PkmnResult<Option<Arc<dyn ItemScript>>> {
|
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for WebAssemblyScriptResolver {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
f.write_str("WebAssemblyScriptResolver")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
/// This data is what is passed to every function that requires access to the global runtime context.
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct WebAssemblyEnvironmentData {
|
|
|
|
/// We currently have a hacky implementation of extern refs while we're waiting for ExternRef support to hit the
|
|
|
|
/// wasm32-unknown-unknown target of Rust. As we don't want to pass raw memory pointers to WASM for security reasons,
|
|
|
|
/// we instead keep track of all the data we've sent to WASM, and pass the ID of that data to WASM. This allows us
|
|
|
|
/// to only operate on data we know WASM owns. We currently store this data in this continuous Vec, and give the index
|
|
|
|
/// of the data as the ID.
|
|
|
|
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
|
|
|
|
/// backwards lookup on extern_ref_pointers. This allows us to get the index for a given piece of data.
|
2022-07-18 13:36:03 +00:00
|
|
|
extern_ref_pointers_lookup: RwLock<HashMap<ExternRefLookupKey, u32>>,
|
2022-07-18 11:18:11 +00:00
|
|
|
/// 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
|
|
|
|
/// allow for modifying memory we might not want to. If we get a type mismatch, we will panic, preventing this.
|
2022-07-18 13:36:03 +00:00
|
|
|
extern_ref_type_lookup: RwLock<HashSet<ExternRefLookupKey>>,
|
2022-07-18 11:18:11 +00:00
|
|
|
|
2022-08-20 10:22:12 +00:00
|
|
|
/// Additional security for data slices passed to WASM.
|
|
|
|
extern_vec_ref_lookup: RwLock<HashMap<u32, Vec<u32>>>,
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
/// The memory inside of the WASM container.
|
|
|
|
memory: RwLock<Option<Memory>>,
|
|
|
|
|
2022-07-18 13:36:03 +00:00
|
|
|
/// This is a map of all the functions that WASM gives us.
|
|
|
|
exported_functions: RwLock<HashMap<StringKey, Function>>,
|
|
|
|
|
2022-08-20 10:22:12 +00:00
|
|
|
script_function_cache: ScriptFunctionCache,
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
/// This is the WASM function to allocate memory inside the WASM container.
|
|
|
|
allocate_mem_fn: RwLock<Option<NativeFunc<(u32, u32), u32>>>,
|
2022-08-20 10:22:12 +00:00
|
|
|
|
|
|
|
/// An allocator for quick short lifetime allocations within WASM.
|
|
|
|
temp_allocator: RwLock<Option<TempWasmAllocator>>,
|
2022-07-18 11:18:11 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 13:36:03 +00:00
|
|
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
|
|
|
struct ExternRefLookupKey {
|
|
|
|
pub ptr: *const u8,
|
2022-08-20 10:22:12 +00:00
|
|
|
pub is_vec: bool,
|
2022-07-18 13:36:03 +00:00
|
|
|
pub t: u64,
|
|
|
|
}
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
impl WebAssemblyEnvironmentData {
|
|
|
|
/// This returns the memory of the WASM container.
|
|
|
|
pub fn memory(&self) -> MappedRwLockReadGuard<'_, RawRwLock, Memory> {
|
|
|
|
RwLockReadGuard::map(self.memory.read(), |a| a.as_ref().unwrap())
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:36:03 +00:00
|
|
|
/// This returns the functions exported from WASM.
|
|
|
|
pub fn exported_functions(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Function>> {
|
|
|
|
self.exported_functions.read()
|
|
|
|
}
|
|
|
|
|
2022-08-20 10:22:12 +00:00
|
|
|
///
|
|
|
|
pub fn script_function_cache(&self) -> &ScriptFunctionCache {
|
|
|
|
&self.script_function_cache
|
|
|
|
}
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
/// 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.
|
|
|
|
/// 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).
|
2022-07-18 13:36:03 +00:00
|
|
|
pub fn allocate_mem(&self, size: u32, align: u32) -> (*mut u8, u32) {
|
2022-07-18 11:18:11 +00:00
|
|
|
let wasm_ptr = self.allocate_mem_fn.read().as_ref().unwrap().call(size, align).unwrap();
|
|
|
|
unsafe {
|
|
|
|
(
|
|
|
|
self.memory
|
|
|
|
.read()
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.data_ptr()
|
|
|
|
.offset(wasm_ptr as isize),
|
|
|
|
wasm_ptr,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-20 10:22:12 +00:00
|
|
|
/// 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.
|
|
|
|
/// 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).
|
|
|
|
pub fn allocate_mem_typed<T>(&self) -> (*mut u8, u32) {
|
|
|
|
let wasm_ptr = self
|
|
|
|
.allocate_mem_fn
|
|
|
|
.read()
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.call(size_of::<T>() as u32, align_of::<T>() as u32)
|
|
|
|
.unwrap();
|
|
|
|
unsafe {
|
|
|
|
(
|
|
|
|
self.memory
|
|
|
|
.read()
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.data_ptr()
|
|
|
|
.offset(wasm_ptr as isize),
|
|
|
|
wasm_ptr,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Allocate a piece of memory inside WASM with a very short lifespan. This is mainly used for
|
|
|
|
/// rapid allocation of script function parameters, where WASM needs to write to a specific
|
|
|
|
/// pointer.
|
|
|
|
pub fn temp_allocate_mem_typed<T>(&self) -> AllocatedObject<T> {
|
|
|
|
self.temp_allocator.read().as_ref().unwrap().alloc::<T>()
|
|
|
|
}
|
|
|
|
|
2022-07-18 11:18:11 +00:00
|
|
|
/// Get a numeric value from any given value. This is not a true Extern Ref from WASM, as this
|
|
|
|
/// is not supported by our current WASM platform (Rust). Instead, this is simply a way to not
|
|
|
|
/// have to send arbitrary pointer values back and forth with WASM. Only values WASM can actually
|
|
|
|
/// access can be touched through this, and we ensure the value is the correct type. In the future,
|
|
|
|
/// when extern refs get actually properly implemented at compile time we might want to get rid
|
|
|
|
/// of this code.
|
2022-08-20 10:22:12 +00:00
|
|
|
pub fn get_extern_ref_index<T: UniqueTypeId<u64> + ?Sized>(&self, value: &T) -> u32 {
|
|
|
|
self.get_extern_ref_from_ptr(value as *const T as *const u8, T::id().0, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a numeric value from any given value. This is not a true Extern Ref from WASM, as this
|
|
|
|
/// is not supported by our current WASM platform (Rust). Instead, this is simply a way to not
|
|
|
|
/// have to send arbitrary pointer values back and forth with WASM. Only values WASM can actually
|
|
|
|
/// access can be touched through this, and we ensure the value is the correct type. In the future,
|
|
|
|
/// when extern refs get actually properly implemented at compile time we might want to get rid
|
|
|
|
/// of this code.
|
|
|
|
pub fn get_extern_vec_ref_index<T: UniqueTypeId<u64>>(&self, value: &[T]) -> u32 {
|
|
|
|
let mut vec = Vec::with_capacity(value.len());
|
|
|
|
for v in value {
|
|
|
|
vec.push(self.get_extern_ref_index(v));
|
|
|
|
}
|
|
|
|
let p = self.get_extern_ref_from_ptr(value as *const [T] as *const u8, T::id().0, true);
|
|
|
|
self.extern_vec_ref_lookup.write().insert(p, vec);
|
|
|
|
p
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get an extern ref belonging to a vector we have passed to WASM.
|
|
|
|
pub fn get_extern_vec_ref_extern_ref(&self, extern_vec_ref: u32, index: u32) -> u32 {
|
|
|
|
let r = self.extern_vec_ref_lookup.read();
|
|
|
|
let v = r.get(&extern_vec_ref).unwrap();
|
|
|
|
v[index as usize]
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the extern ref index belonging to a specific pointer. If none exists, this will create
|
|
|
|
/// a new one.
|
|
|
|
fn get_extern_ref_from_ptr(&self, ptr: *const u8, type_id: u64, is_vec: bool) -> u32 {
|
|
|
|
if let Some(v) = self.extern_ref_pointers_lookup.read().get(&ExternRefLookupKey {
|
|
|
|
ptr,
|
|
|
|
is_vec,
|
|
|
|
t: type_id,
|
|
|
|
}) {
|
2022-07-18 11:18:11 +00:00
|
|
|
return *v as u32;
|
|
|
|
}
|
|
|
|
let index = {
|
|
|
|
let mut extern_ref_guard = self.extern_ref_pointers.write();
|
|
|
|
extern_ref_guard.push(ptr);
|
|
|
|
extern_ref_guard.len() as u32
|
|
|
|
};
|
2022-08-20 10:22:12 +00:00
|
|
|
self.extern_ref_pointers_lookup.write().insert(
|
|
|
|
ExternRefLookupKey {
|
|
|
|
ptr,
|
|
|
|
is_vec,
|
|
|
|
t: type_id,
|
|
|
|
},
|
|
|
|
index,
|
|
|
|
);
|
|
|
|
self.extern_ref_type_lookup.write().insert(ExternRefLookupKey {
|
|
|
|
ptr,
|
|
|
|
is_vec,
|
|
|
|
t: type_id,
|
|
|
|
});
|
2022-07-18 11:18:11 +00:00
|
|
|
index
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets a value from the extern ref lookup. This turns an earlier registered index back into
|
|
|
|
/// its proper value, validates its type, and returns the value.
|
|
|
|
pub fn get_extern_ref_value<T: UniqueTypeId<u64>>(&self, index: u32) -> &T {
|
|
|
|
let read_guard = self.extern_ref_pointers.read();
|
|
|
|
let ptr = read_guard.get((index - 1) as usize).unwrap();
|
2022-07-18 13:36:03 +00:00
|
|
|
if self
|
|
|
|
.extern_ref_type_lookup
|
|
|
|
.read()
|
|
|
|
.get(&ExternRefLookupKey {
|
|
|
|
ptr: *ptr,
|
2022-08-20 10:22:12 +00:00
|
|
|
is_vec: false,
|
2022-07-18 13:36:03 +00:00
|
|
|
t: T::id().0,
|
|
|
|
})
|
|
|
|
.is_none()
|
|
|
|
{
|
2022-07-18 11:18:11 +00:00
|
|
|
panic!(
|
|
|
|
"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>()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe { (*ptr as *const T).as_ref().unwrap() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The runtime environment for script execution. This is passed to most of the host functions being called.
|
2022-07-18 08:16:47 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub(crate) struct WebAssemblyEnv {
|
2022-07-18 11:18:11 +00:00
|
|
|
/// A pointer to the WebAssemblyScriptResolver belonging to the current script environment.
|
2022-07-18 13:36:03 +00:00
|
|
|
data: Weak<WebAssemblyEnvironmentData>,
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl WebAssemblyEnv {
|
2022-07-18 13:36:03 +00:00
|
|
|
/// Instantiates a new Environment with the requested data.
|
|
|
|
pub fn new(data: Weak<WebAssemblyEnvironmentData>) -> Self {
|
|
|
|
Self { data }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the actual data belonging to the current context.
|
|
|
|
pub fn data(&self) -> Arc<WebAssemblyEnvironmentData> {
|
|
|
|
self.data.upgrade().unwrap()
|
2022-07-18 08:16:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Sync for WebAssemblyEnv {}
|
|
|
|
|
|
|
|
unsafe impl Send for WebAssemblyEnv {}
|
|
|
|
|
2022-07-18 13:36:03 +00:00
|
|
|
unsafe impl Sync for WebAssemblyEnvironmentData {}
|
|
|
|
|
|
|
|
unsafe impl Send for WebAssemblyEnvironmentData {}
|
|
|
|
|
2022-07-18 08:16:47 +00:00
|
|
|
impl WasmerEnv for WebAssemblyEnv {}
|