Skip to content

Commit

Permalink
Merge #3153
Browse files Browse the repository at this point in the history
3153: SharedMemory & Atomics r=ptitSeb a=ptitSeb

# Description
Enabled SharedMemory and the Atomics extension proposal

- [x] Enable Atomic extension by default
- [x] Fix "imports" tests #3154
- [x] Add function for memory.atomic.wait32, memory.atomic.wait64 and memory.atomic.notify opcodes #3155
- [x] Add support for the new wait/notify opcodes in Cranelift compiler #3156 
- [x] Add support for the new wait/notify opcodes in LLVM compiler #3157
- [x] Add support for atomic access opcodes in AArch64/Singlepass compiler #3159
- [x] Add support for the new wait/notify opcodes in Singlepass compiler #3158
- [x] Fix Atomic issues on x86_64 Singlepass compiler not related to Wait/Notify opcodes #3161
- [x] Fix Atomic issues on Cranelift compiler not related to Wait/Notify opcodes #3162
- [x] Fix Atomic issues on LLVM compiler not related to Wait/Notify opcodes #3163
- [x] Fix the ticket #3167 on Cranelift

For #3304 

Co-authored-by: John Sharratt's Shared Account <[email protected]>
Co-authored-by: ptitSeb <[email protected]>
Co-authored-by: Syrus Akbary <[email protected]>
  • Loading branch information
4 people authored Nov 29, 2022
2 parents 5287c4f + 30a7d61 commit 256755b
Show file tree
Hide file tree
Showing 35 changed files with 5,965 additions and 1,149 deletions.
5 changes: 5 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ fn main() -> anyhow::Result<()> {
wast_processor,
)?;
test_directory_module(spectests, "tests/wast/spec/proposals/simd", wast_processor)?;
test_directory_module(
spectests,
"tests/wast/spec/proposals/threads",
wast_processor,
)?;
// test_directory_module(spectests, "tests/wast/spec/proposals/bulk-memory-operations", wast_processor)?;
Ok(())
})?;
Expand Down
6 changes: 5 additions & 1 deletion lib/api/src/js/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ impl Imports {
/// Resolve and return a vector of imports in the order they are defined in the `module`'s source code.
///
/// This means the returned `Vec<Extern>` might be a subset of the imports contained in `self`.
pub fn imports_for_module(&self, module: &Module) -> Result<Vec<Extern>, LinkError> {
pub fn imports_for_module(
&self,
module: &Module,
_store: &mut impl AsStoreMut,
) -> Result<Vec<Extern>, LinkError> {
let mut ret = vec![];
for import in module.imports() {
if let Some(imp) = self
Expand Down
1 change: 0 additions & 1 deletion lib/api/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ pub use crate::js::value::Value as Val;

pub mod vm {
//! The `vm` module re-exports wasmer-vm types.
pub use crate::js::export::VMMemory;
}

Expand Down
18 changes: 14 additions & 4 deletions lib/api/src/sys/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,26 @@ impl Imports {
/// import_object.get_export("module", "name");
/// ```
pub fn get_export(&self, module: &str, name: &str) -> Option<Extern> {
if self
.map
.contains_key(&(module.to_string(), name.to_string()))
{
if self.exists(module, name) {
let ext = &self.map[&(module.to_string(), name.to_string())];
return Some(ext.clone());
}
None
}

/// Returns if an export exist for a given module and name.
///
/// # Usage
/// ```no_run
/// # use wasmer::Imports;
/// let mut import_object = Imports::new();
/// import_object.exists("module", "name");
/// ```
pub fn exists(&self, module: &str, name: &str) -> bool {
self.map
.contains_key(&(module.to_string(), name.to_string()))
}

/// Returns true if the Imports contains namespace with the provided name.
pub fn contains_namespace(&self, name: &str) -> bool {
self.map.keys().any(|(k, _)| (k == name))
Expand Down
4 changes: 2 additions & 2 deletions lib/api/src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ pub mod vm {
//! The `vm` module re-exports wasmer-vm types.
pub use wasmer_vm::{
MemoryError, MemoryStyle, TableStyle, VMExtern, VMMemory, VMMemoryDefinition, VMTable,
VMTableDefinition,
MemoryError, MemoryStyle, TableStyle, VMExtern, VMMemory, VMMemoryDefinition,
VMOwnedMemory, VMSharedMemory, VMTable, VMTableDefinition,
};
}

Expand Down
7 changes: 4 additions & 3 deletions lib/cli/src/commands/run/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::collections::BTreeSet;
use std::path::PathBuf;
use wasmer::{AsStoreMut, FunctionEnv, Instance, Module, RuntimeError, Value};
use wasmer_wasi::{
get_wasi_versions, import_object_for_all_wasi_versions, is_wasix_module, WasiEnv, WasiError,
WasiState, WasiVersion,
get_wasi_versions, import_object_for_all_wasi_versions, is_wasix_module,
wasi_import_shared_memory, WasiEnv, WasiError, WasiState, WasiVersion,
};

use clap::Parser;
Expand Down Expand Up @@ -104,7 +104,8 @@ impl Wasi {
is_wasix_module(module),
std::sync::atomic::Ordering::Release,
);
let import_object = import_object_for_all_wasi_versions(store, &wasi_env.env);
let mut import_object = import_object_for_all_wasi_versions(store, &wasi_env.env);
wasi_import_shared_memory(&mut import_object, module, store);
let instance = Instance::new(store, module, &import_object)?;
let memory = instance.exports.get_memory("memory")?;
wasi_env.data_mut(store).set_memory(memory.clone());
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-cranelift/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode {
match trap {
ir::TrapCode::StackOverflow => TrapCode::StackOverflow,
ir::TrapCode::HeapOutOfBounds => TrapCode::HeapAccessOutOfBounds,
ir::TrapCode::HeapMisaligned => TrapCode::HeapMisaligned,
ir::TrapCode::HeapMisaligned => TrapCode::UnalignedAtomic,
ir::TrapCode::TableOutOfBounds => TrapCode::TableAccessOutOfBounds,
ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull,
ir::TrapCode::BadSignature => TrapCode::BadSignature,
Expand Down
189 changes: 174 additions & 15 deletions lib/compiler-cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ pub struct FuncEnvironment<'module_environment> {
/// The external function signature for implementing wasm's `table.fill`.
table_fill_sig: Option<ir::SigRef>,

/// The external function signature for implementing wasm's `memory32.atomic.wait32`.
memory32_atomic_wait32_sig: Option<ir::SigRef>,

/// The external function signature for implementing wasm's `memory32.atomic.wait64`.
memory32_atomic_wait64_sig: Option<ir::SigRef>,

/// The external function signature for implementing wasm's `memory32.atomic.notify`.
memory32_atomic_notify_sig: Option<ir::SigRef>,

/// Offsets to struct fields accessed by JIT code.
offsets: VMOffsets,

Expand Down Expand Up @@ -143,6 +152,9 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
data_drop_sig: None,
func_ref_sig: None,
table_fill_sig: None,
memory32_atomic_wait32_sig: None,
memory32_atomic_wait64_sig: None,
memory32_atomic_notify_sig: None,
offsets: VMOffsets::new(target_config.pointer_bytes(), module),
memory_styles,
table_styles,
Expand Down Expand Up @@ -684,6 +696,139 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
(sig, VMBuiltinFunctionIndex::get_data_drop_index())
}

fn get_memory32_atomic_wait32_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.memory32_atomic_wait32_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
// Memory Index
AbiParam::new(I32),
// Dst
AbiParam::new(I32),
// Val
AbiParam::new(I32),
// Timeout
AbiParam::new(I64),
],
returns: vec![AbiParam::new(I32)],
call_conv: self.target_config.default_call_conv,
})
});
self.memory32_atomic_wait32_sig = Some(sig);
sig
}

/// Return the memory.atomic.wait32 function signature to call for the given index,
/// along with the translated index value to pass to it
/// and its index in `VMBuiltinFunctionsArray`.
fn get_memory_atomic_wait32_func(
&mut self,
func: &mut Function,
index: MemoryIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
if self.module.is_imported_memory(index) {
(
self.get_memory32_atomic_wait32_sig(func),
index.index(),
VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index(),
)
} else {
(
self.get_memory32_atomic_wait32_sig(func),
self.module.local_memory_index(index).unwrap().index(),
VMBuiltinFunctionIndex::get_memory_atomic_wait32_index(),
)
}
}

fn get_memory32_atomic_wait64_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.memory32_atomic_wait64_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
// Memory Index
AbiParam::new(I32),
// Dst
AbiParam::new(I32),
// Val
AbiParam::new(I64),
// Timeout
AbiParam::new(I64),
],
returns: vec![AbiParam::new(I32)],
call_conv: self.target_config.default_call_conv,
})
});
self.memory32_atomic_wait64_sig = Some(sig);
sig
}

/// Return the memory.atomic.wait64 function signature to call for the given index,
/// along with the translated index value to pass to it
/// and its index in `VMBuiltinFunctionsArray`.
fn get_memory_atomic_wait64_func(
&mut self,
func: &mut Function,
index: MemoryIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
if self.module.is_imported_memory(index) {
(
self.get_memory32_atomic_wait64_sig(func),
index.index(),
VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index(),
)
} else {
(
self.get_memory32_atomic_wait64_sig(func),
self.module.local_memory_index(index).unwrap().index(),
VMBuiltinFunctionIndex::get_memory_atomic_wait64_index(),
)
}
}

fn get_memory32_atomic_notify_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.memory32_atomic_notify_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
// Memory Index
AbiParam::new(I32),
// Dst
AbiParam::new(I32),
// Count
AbiParam::new(I32),
],
returns: vec![AbiParam::new(I32)],
call_conv: self.target_config.default_call_conv,
})
});
self.memory32_atomic_notify_sig = Some(sig);
sig
}

/// Return the memory.atomic.notify function signature to call for the given index,
/// along with the translated index value to pass to it
/// and its index in `VMBuiltinFunctionsArray`.
fn get_memory_atomic_notify_func(
&mut self,
func: &mut Function,
index: MemoryIndex,
) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
if self.module.is_imported_memory(index) {
(
self.get_memory32_atomic_notify_sig(func),
index.index(),
VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index(),
)
} else {
(
self.get_memory32_atomic_notify_sig(func),
self.module.local_memory_index(index).unwrap().index(),
VMBuiltinFunctionIndex::get_memory_atomic_notify_index(),
)
}
}

/// Translates load of builtin function and returns a pair of values `vmctx`
/// and address of the loaded function.
fn translate_load_builtin_function_address(
Expand Down Expand Up @@ -1389,29 +1534,43 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro

fn translate_atomic_wait(
&mut self,
_pos: FuncCursor,
_index: MemoryIndex,
mut pos: FuncCursor,
index: MemoryIndex,
_heap: ir::Heap,
_addr: ir::Value,
_expected: ir::Value,
_timeout: ir::Value,
addr: ir::Value,
expected: ir::Value,
timeout: ir::Value,
) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported(
"wasm atomics (fn translate_atomic_wait)".to_string(),
))
let (func_sig, index_arg, func_idx) = if pos.func.dfg.value_type(expected) == I64 {
self.get_memory_atomic_wait64_func(pos.func, index)
} else {
self.get_memory_atomic_wait32_func(pos.func, index)
};
let memory_index = pos.ins().iconst(I32, index_arg as i64);
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
let call_inst = pos.ins().call_indirect(
func_sig,
func_addr,
&[vmctx, memory_index, addr, expected, timeout],
);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
}

fn translate_atomic_notify(
&mut self,
_pos: FuncCursor,
_index: MemoryIndex,
mut pos: FuncCursor,
index: MemoryIndex,
_heap: ir::Heap,
_addr: ir::Value,
_count: ir::Value,
addr: ir::Value,
count: ir::Value,
) -> WasmResult<ir::Value> {
Err(WasmError::Unsupported(
"wasm atomics (fn translate_atomic_notify)".to_string(),
))
let (func_sig, index_arg, func_idx) = self.get_memory_atomic_notify_func(pos.func, index);
let memory_index = pos.ins().iconst(I32, index_arg as i64);
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
let call_inst =
pos.ins()
.call_indirect(func_sig, func_addr, &[vmctx, memory_index, addr, count]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
}

fn get_global_type(&self, global_index: GlobalIndex) -> Option<WasmerType> {
Expand Down
Loading

0 comments on commit 256755b

Please sign in to comment.