mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-13 05:48:45 +00:00
Merge branch 'wasix-core-changes' into wasix
This commit is contained in:
2
.github/workflows/benchmark.yaml
vendored
2
.github/workflows/benchmark.yaml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: 1.63
|
||||
toolchain: 1.64
|
||||
- name: Configure cargo data directory
|
||||
# After this point, all cargo registry and crate data is stored in
|
||||
# $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files
|
||||
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -100,7 +100,7 @@ jobs:
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: 1.63
|
||||
toolchain: 1.64
|
||||
target: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
if: matrix.use_sccache != true
|
||||
|
||||
2
.github/workflows/cloudcompiler.yaml
vendored
2
.github/workflows/cloudcompiler.yaml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: 1.63
|
||||
toolchain: 1.64
|
||||
target: ${{ matrix.target }}
|
||||
- name: Install wasm32-wasi target
|
||||
shell: bash
|
||||
|
||||
2
.github/workflows/documentation.yaml
vendored
2
.github/workflows/documentation.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: 1.63
|
||||
toolchain: 1.64
|
||||
- name: Install LLVM
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
2
.github/workflows/test-js.yaml
vendored
2
.github/workflows/test-js.yaml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: 1.63
|
||||
toolchain: 1.64
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v2
|
||||
|
||||
2
.github/workflows/test-sys.yaml
vendored
2
.github/workflows/test-sys.yaml
vendored
@@ -113,7 +113,7 @@ jobs:
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: 1.63
|
||||
toolchain: 1.64
|
||||
target: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
if: matrix.use_sccache != true
|
||||
|
||||
13
bors.toml
13
bors.toml
@@ -1,13 +0,0 @@
|
||||
status = [
|
||||
#"Audit",
|
||||
"Code lint",
|
||||
#"Test on linux-x64",
|
||||
# "Test on linux-musl-x64",
|
||||
# "Test on linux-aarch64",
|
||||
#"Test on macos-arm64",
|
||||
#"Test on macos-x64",
|
||||
#"Test on windows-x64",
|
||||
]
|
||||
required_approvals = 0
|
||||
timeout_sec = 7200
|
||||
delete_merged_branches = true
|
||||
@@ -54,7 +54,7 @@ impl VMMemory {
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
pub fn fork(&self) -> Result<VMMemory, wasmer_types::MemoryError> {
|
||||
pub fn duplicate(&self) -> Result<VMMemory, wasmer_types::MemoryError> {
|
||||
let new_memory = crate::Memory::new_internal(self.ty.clone())?;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
|
||||
4
lib/api/src/js/externals/memory.rs
vendored
4
lib/api/src/js/externals/memory.rs
vendored
@@ -265,9 +265,9 @@ impl Memory {
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
pub fn fork(&mut self, store: &impl AsStoreRef) -> Result<VMMemory, MemoryError> {
|
||||
pub fn duplicate(&mut self, store: &impl AsStoreRef) -> Result<VMMemory, MemoryError> {
|
||||
let mem = self.handle.get(store.as_store_ref().objects());
|
||||
mem.fork()
|
||||
mem.duplicate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,10 +117,12 @@ mod tests {
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn try_clone(&self) -> Option<Box<dyn LinearMemory + 'static>> {
|
||||
None
|
||||
}
|
||||
fn fork(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
|
||||
fn duplicate(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
let mem = self.mem.clone();
|
||||
Ok(Box::new(Self {
|
||||
memory_definition: Some(UnsafeCell::new(VMMemoryDefinition {
|
||||
|
||||
@@ -110,8 +110,6 @@ pub fn sbrk(mut ctx: FunctionEnvMut<EmEnv>, increment: i32) -> i32 {
|
||||
increment,
|
||||
total_memory
|
||||
);
|
||||
let _ = dynamictop_ptr;
|
||||
|
||||
if increment > 0 && new_dynamic_top < old_dynamic_top || new_dynamic_top < 0 {
|
||||
abort_on_cannot_grow_memory_old(ctx);
|
||||
return -1;
|
||||
|
||||
@@ -119,11 +119,11 @@ impl WasmMmap {
|
||||
|
||||
/// Copies the memory
|
||||
/// (in this case it performs a copy-on-write to save memory)
|
||||
pub fn fork(&mut self) -> Result<Self, MemoryError> {
|
||||
pub fn duplicate(&mut self) -> Result<Self, MemoryError> {
|
||||
let mem_length = self.size.bytes().0;
|
||||
let mut alloc = self
|
||||
.alloc
|
||||
.fork(Some(mem_length))
|
||||
.duplicate(Some(mem_length))
|
||||
.map_err(MemoryError::Generic)?;
|
||||
let base_ptr = alloc.as_mut_ptr();
|
||||
Ok(Self {
|
||||
@@ -289,9 +289,9 @@ impl VMOwnedMemory {
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
pub fn fork(&mut self) -> Result<Self, MemoryError> {
|
||||
pub fn duplicate(&mut self) -> Result<Self, MemoryError> {
|
||||
Ok(Self {
|
||||
mmap: self.mmap.fork()?,
|
||||
mmap: self.mmap.duplicate()?,
|
||||
config: self.config.clone(),
|
||||
})
|
||||
}
|
||||
@@ -333,8 +333,8 @@ impl LinearMemory for VMOwnedMemory {
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
fn fork(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
let forked = Self::fork(self)?;
|
||||
fn duplicate(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
let forked = Self::duplicate(self)?;
|
||||
Ok(Box::new(forked))
|
||||
}
|
||||
}
|
||||
@@ -376,10 +376,10 @@ impl VMSharedMemory {
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
pub fn fork(&mut self) -> Result<Self, MemoryError> {
|
||||
pub fn duplicate(&mut self) -> Result<Self, MemoryError> {
|
||||
let mut guard = self.mmap.write().unwrap();
|
||||
Ok(Self {
|
||||
mmap: Arc::new(RwLock::new(guard.fork()?)),
|
||||
mmap: Arc::new(RwLock::new(guard.duplicate()?)),
|
||||
config: self.config.clone(),
|
||||
})
|
||||
}
|
||||
@@ -427,8 +427,8 @@ impl LinearMemory for VMSharedMemory {
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
fn fork(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
let forked = Self::fork(self)?;
|
||||
fn duplicate(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
let forked = Self::duplicate(self)?;
|
||||
Ok(Box::new(forked))
|
||||
}
|
||||
}
|
||||
@@ -495,8 +495,8 @@ impl LinearMemory for VMMemory {
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
fn fork(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
self.0.fork()
|
||||
fn duplicate(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
self.0.duplicate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,8 +558,8 @@ impl VMMemory {
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
pub fn fork(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
LinearMemory::fork(self)
|
||||
pub fn duplicate(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
|
||||
LinearMemory::duplicate(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,5 +615,5 @@ where
|
||||
}
|
||||
|
||||
/// Copies this memory to a new memory
|
||||
fn fork(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError>;
|
||||
fn duplicate(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError>;
|
||||
}
|
||||
|
||||
@@ -317,8 +317,10 @@ impl Mmap {
|
||||
|
||||
/// Copies the memory to a new swap file (using copy-on-write if available)
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn fork(&mut self, hint_used: Option<usize>) -> Result<Self, String> {
|
||||
pub fn duplicate(&mut self, hint_used: Option<usize>) -> Result<Self, String> {
|
||||
// Empty memory is an edge case
|
||||
|
||||
use std::os::unix::prelude::FromRawFd;
|
||||
if self.len == 0 {
|
||||
return Ok(Self::new());
|
||||
}
|
||||
@@ -355,28 +357,11 @@ impl Mmap {
|
||||
};
|
||||
|
||||
// The shallow copy failed so we have to do it the hard way
|
||||
let mut off_in: libc::off_t = 0;
|
||||
let mut off_out: libc::off_t = 0;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(any(target_env = "musl", target_vendor = "apple")))]
|
||||
{
|
||||
let ret = libc::copy_file_range(self.fd.0, &mut off_in, fd.0, &mut off_out, len, 0);
|
||||
} else {
|
||||
// TODO: don't use as casts...
|
||||
let ret = match copy_file_range_impl(self.fd.0, off_in as u64, fd.0, off_out as u64, len) {
|
||||
Ok(_) => 0,
|
||||
Err(_err) => -1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if ret < 0 {
|
||||
return Err(format!(
|
||||
"failed to copy temporary file data - {}",
|
||||
io::Error::last_os_error()
|
||||
));
|
||||
}
|
||||
let mut source = std::fs::File::from_raw_fd(self.fd.0);
|
||||
let mut out = std::fs::File::from_raw_fd(fd.0);
|
||||
copy_file_range(&mut source, 0, &mut out, 0, len)
|
||||
.map_err(|err| format!("Could not copy memory: {err}"))?;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
trace!("memory copy finished (size={})", len);
|
||||
@@ -410,7 +395,7 @@ impl Mmap {
|
||||
|
||||
/// Copies the memory to a new swap file (using copy-on-write if available)
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn fork(&mut self, hint_used: Option<usize>) -> Result<Self, String> {
|
||||
pub fn duplicate(&mut self, hint_used: Option<usize>) -> Result<Self, String> {
|
||||
// Create a new memory which we will copy to
|
||||
let new_mmap = Self::with_at_least(self.len)?;
|
||||
|
||||
@@ -436,66 +421,6 @@ impl Mmap {
|
||||
}
|
||||
}
|
||||
|
||||
/// Rust implementation of libc::copy_file_range.
|
||||
///
|
||||
/// Needed because that function is not available on all platforms.
|
||||
// TODO: better implementation! (this is very quick, low effort)
|
||||
// TODO: this function needs tests!
|
||||
#[cfg(target_family = "unix")]
|
||||
#[allow(dead_code)]
|
||||
fn copy_file_range_impl(
|
||||
source_fd: i32,
|
||||
source_offset: u64,
|
||||
out_fd: i32,
|
||||
out_offset: u64,
|
||||
len: usize,
|
||||
) -> Result<(), std::io::Error> {
|
||||
use std::{
|
||||
io::{Seek, SeekFrom},
|
||||
os::unix::io::FromRawFd,
|
||||
};
|
||||
|
||||
let mut f1 = unsafe { std::fs::File::from_raw_fd(source_fd) };
|
||||
let f1_original_pos = f1.stream_position()?;
|
||||
|
||||
// TODO: don't cast with as
|
||||
f1.seek(SeekFrom::Start(source_offset))?;
|
||||
|
||||
let mut f2 = unsafe { std::fs::File::from_raw_fd(out_fd) };
|
||||
let f2_original_pos = f2.stream_position()?;
|
||||
f2.seek(SeekFrom::Start(out_offset))?;
|
||||
|
||||
let mut reader = std::io::BufReader::new(f1);
|
||||
let mut writer = std::io::BufWriter::new(f2);
|
||||
|
||||
let mut buffer = vec![0u8; 4096];
|
||||
|
||||
let mut offset = 0;
|
||||
let end = len.saturating_sub(buffer.len());
|
||||
while offset < end {
|
||||
let read = reader.read(&mut buffer)?;
|
||||
writer.write_all(&buffer)?;
|
||||
offset += read;
|
||||
}
|
||||
// Need to read the last chunk.
|
||||
let remaining = len - offset;
|
||||
if remaining > 0 {
|
||||
reader.read_exact(&mut buffer[0..remaining])?;
|
||||
writer.write_all(&buffer[0..remaining])?;
|
||||
}
|
||||
|
||||
writer.flush()?;
|
||||
|
||||
// Restore files to original position.
|
||||
let mut f1 = reader.into_inner();
|
||||
f1.seek(SeekFrom::Start(f1_original_pos))?;
|
||||
|
||||
let mut f2 = writer.into_inner()?;
|
||||
f2.seek(SeekFrom::Start(f2_original_pos))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Drop for Mmap {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn drop(&mut self) {
|
||||
@@ -522,6 +447,54 @@ fn _assert() {
|
||||
_assert_send_sync::<Mmap>();
|
||||
}
|
||||
|
||||
/// Copy a range of a file to another file.
|
||||
// We could also use libc::copy_file_range on some systems, but it's
|
||||
// hard to do this because it is not available on many libc implementations.
|
||||
// (not on Mac OS, musl, ...)
|
||||
#[cfg(target_family = "unix")]
|
||||
fn copy_file_range(
|
||||
source: &mut std::fs::File,
|
||||
source_offset: u64,
|
||||
out: &mut std::fs::File,
|
||||
out_offset: u64,
|
||||
len: usize,
|
||||
) -> Result<(), std::io::Error> {
|
||||
use std::io::{Seek, SeekFrom};
|
||||
|
||||
let source_original_pos = source.stream_position()?;
|
||||
source.seek(SeekFrom::Start(source_offset))?;
|
||||
|
||||
// TODO: don't cast with as
|
||||
|
||||
let out_original_pos = out.stream_position()?;
|
||||
out.seek(SeekFrom::Start(out_offset))?;
|
||||
|
||||
// TODO: don't do this horrible "triple buffering" below".
|
||||
// let mut reader = std::io::BufReader::new(source);
|
||||
|
||||
// TODO: larger buffer?
|
||||
let mut buffer = vec![0u8; 4096];
|
||||
|
||||
let mut to_read = len;
|
||||
while to_read > 0 {
|
||||
let chunk_size = std::cmp::min(to_read, buffer.len());
|
||||
let read = source.read(&mut buffer[0..chunk_size])?;
|
||||
out.write_all(&buffer[0..read])?;
|
||||
to_read -= read;
|
||||
}
|
||||
|
||||
// Need to read the last chunk.
|
||||
out.flush()?;
|
||||
|
||||
// Restore files to original position.
|
||||
source.seek(SeekFrom::Start(source_original_pos))?;
|
||||
out.flush()?;
|
||||
out.sync_data()?;
|
||||
out.seek(SeekFrom::Start(out_original_pos))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -533,4 +506,59 @@ mod tests {
|
||||
assert_eq!(round_up_to_page_size(4096, 4096), 4096);
|
||||
assert_eq!(round_up_to_page_size(4097, 4096), 8192);
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[test]
|
||||
fn test_copy_file_range() -> Result<(), std::io::Error> {
|
||||
// I know tempfile:: exists, but this doesn't bring in an extra
|
||||
// dependency.
|
||||
|
||||
use std::{fs::OpenOptions, io::Seek};
|
||||
|
||||
let dir = std::env::temp_dir().join("wasmer/copy_file_range");
|
||||
if dir.is_dir() {
|
||||
std::fs::remove_dir_all(&dir).unwrap()
|
||||
}
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
|
||||
let pa = dir.join("a");
|
||||
let pb = dir.join("b");
|
||||
|
||||
let data: Vec<u8> = (0..100).collect();
|
||||
let mut a = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&pa)
|
||||
.unwrap();
|
||||
a.write_all(&data).unwrap();
|
||||
|
||||
let datb: Vec<u8> = (100..200).collect();
|
||||
let mut b = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&pb)
|
||||
.unwrap();
|
||||
b.write_all(&datb).unwrap();
|
||||
|
||||
a.seek(io::SeekFrom::Start(30)).unwrap();
|
||||
b.seek(io::SeekFrom::Start(99)).unwrap();
|
||||
copy_file_range(&mut a, 10, &mut b, 40, 15).unwrap();
|
||||
|
||||
assert_eq!(a.stream_position().unwrap(), 30);
|
||||
assert_eq!(b.stream_position().unwrap(), 99);
|
||||
|
||||
b.seek(io::SeekFrom::Start(0)).unwrap();
|
||||
let mut out = Vec::new();
|
||||
let len = b.read_to_end(&mut out).unwrap();
|
||||
assert_eq!(len, 100);
|
||||
assert_eq!(out[0..40], datb[0..40]);
|
||||
assert_eq!(out[40..55], data[10..25]);
|
||||
assert_eq!(out[55..100], datb[55..100]);
|
||||
|
||||
// TODO: needs more variant tests, but this is enough for now.
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use core::slice::Iter;
|
||||
use std::{
|
||||
cell::UnsafeCell,
|
||||
fmt,
|
||||
@@ -9,9 +10,9 @@ use std::{
|
||||
|
||||
use wasmer_types::StoreSnapshot;
|
||||
|
||||
use crate::VMExternObj;
|
||||
|
||||
use crate::{InstanceHandle, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable};
|
||||
use crate::{
|
||||
InstanceHandle, VMExternObj, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable,
|
||||
};
|
||||
|
||||
/// Unique ID to identify a context.
|
||||
///
|
||||
@@ -104,6 +105,21 @@ impl StoreObjects {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an immutable iterator over all globals
|
||||
pub fn iter_globals(&self) -> Iter<VMGlobal> {
|
||||
self.globals.iter()
|
||||
}
|
||||
|
||||
/// Set a global, at index idx. Will panic if idx is out of range
|
||||
/// Safety: the caller should check taht the raw value is compatible
|
||||
/// with destination VMGlobal type
|
||||
pub fn set_global_unchecked(&self, idx: usize, val: u128) {
|
||||
assert!(idx < self.globals.len());
|
||||
unsafe {
|
||||
self.globals[idx].vmglobal().as_mut().val.u128 = val;
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes the mutable things into a snapshot
|
||||
pub fn save_snapshot(&self) -> StoreSnapshot {
|
||||
let mut ret = StoreSnapshot::default();
|
||||
|
||||
Reference in New Issue
Block a user