From c7ed879270499c927dd2cac6731c2c0913331697 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 15 Oct 2025 10:39:26 -0700 Subject: [PATCH 1/8] fix: resolve linking issue --- fix/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fix/build.rs b/fix/build.rs index 80cb7f4..f0eb17b 100644 --- a/fix/build.rs +++ b/fix/build.rs @@ -118,7 +118,7 @@ fn c2elf(c: &[u8], h: &[u8]) -> Result> { "-ffreestanding", // "-nostdlib", "-nostartfiles", - "-mcmodel=large", + // "-mcmodel=large", "--verbose", "-Wl,-no-pie", ]) @@ -149,8 +149,8 @@ fn main() -> Result<()> { } let prefix = autotools::Config::new("../modules/arca-musl") - .cflag("-mcmodel=large") - .cxxflag("-mcmodel=large") + // .cflag("-mcmodel=large") + // .cxxflag("-mcmodel=large") .out_dir(prefix) .build(); From dfdf98be6b4b6833cb683986836c5b2638dc4314 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 15 Oct 2025 10:40:08 -0700 Subject: [PATCH 2/8] feat: fix-shell with flattened out type information --- Cargo.lock | 8 ++ fix/Cargo.toml | 2 + fix/build.rs | 22 ++++- fix/fix-shell/fix.c | 61 +++++++++++++ fix/fix-shell/fix.h | 25 ++++++ fix/fix-shell/handle.h | 7 ++ fix/fix-shell/main.c | 147 ++---------------------------- fix/fix-shell/runtime.c | 165 ++++++++++++++++++++++++++++++++++ fix/fix-shell/runtime.h | 15 ++++ fix/fix-shell/wasm-rt-impl.c | 19 ++-- fix/fix-shell/wasm-rt.h | 7 +- fix/src/handle.rs | 170 +++++++++++++++++++++++++++++++++++ fix/src/main.rs | 35 +++++--- fix/src/runtime.rs | 28 ++++++ 14 files changed, 543 insertions(+), 168 deletions(-) create mode 100644 fix/fix-shell/fix.h create mode 100644 fix/fix-shell/handle.h create mode 100644 fix/fix-shell/runtime.c create mode 100644 fix/fix-shell/runtime.h create mode 100644 fix/src/handle.rs create mode 100644 fix/src/runtime.rs diff --git a/Cargo.lock b/Cargo.lock index 6ff0779..27369db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,6 +313,12 @@ dependencies = [ "piper", ] +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" + [[package]] name = "byteorder" version = "1.5.0" @@ -684,6 +690,8 @@ dependencies = [ "arcane", "async-lock", "autotools", + "bindgen", + "bytemuck", "cc", "chrono", "cmake", diff --git a/fix/Cargo.toml b/fix/Cargo.toml index 4198dea..aac8da4 100644 --- a/fix/Cargo.toml +++ b/fix/Cargo.toml @@ -30,9 +30,11 @@ trait-variant = "0.1.2" futures = { version = "0.3.31", default-features = false, features = ["alloc", "async-await"] } user = { path = "../user", artifact = "bin", target = "x86_64-unknown-none" } async-lock = { version = "3.4.1", default-features = false } +bytemuck = "1.24.0" [build-dependencies] anyhow = "1.0.98" +bindgen = "0.72.1" cc = "1.2.30" autotools = "0.2.7" cmake = "0.1.54" diff --git a/fix/build.rs b/fix/build.rs index f0eb17b..966a1ff 100644 --- a/fix/build.rs +++ b/fix/build.rs @@ -190,9 +190,25 @@ fn main() -> Result<()> { std::fs::write(dst, elf)?; } - let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - println!("cargo::rerun-if-changed={dir}/etc/memmap.ld"); - println!("cargo::rustc-link-arg=-T{dir}/etc/memmap.ld"); + let cwd = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + + let headers = vec![cwd.clone() + "/fix-shell/handle.h"]; + + let bindings = bindgen::Builder::default() + .headers(headers) + .clang_args(["-nostdinc"]) + .use_core() + .default_enum_style(bindgen::EnumVariation::ModuleConsts) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .generate() + .expect("Unable to generate bindings"); + + bindings + .write_to_file(Path::new(&out_dir).join("handle-bindings.rs")) + .expect("Couldn't write bindings!"); + + println!("cargo::rerun-if-changed={cwd}/etc/memmap.ld"); + println!("cargo::rustc-link-arg=-T{cwd}/etc/memmap.ld"); println!("cargo::rustc-link-arg=-no-pie"); Ok(()) diff --git a/fix/fix-shell/fix.c b/fix/fix-shell/fix.c index e69de29..c956b97 100644 --- a/fix/fix-shell/fix.c +++ b/fix/fix-shell/fix.c @@ -0,0 +1,61 @@ +#include "fix.h" +#include "arca/arca.h" +#include "arca/asm.h" +#include "arca/sys.h" + +arcad type_to_arcad(fix_type type) { + return arca_word_create((int64_t)(type)); +} + +static fix_type arcad_to_type(arcad type) { + uint64_t word; + arca_word_read(type, &word); + if (word == BlobObject) { + return BlobObject; + } + + if (word == TreeObject) { + return TreeObject; + } + + return Null; +} + +long check(char *msg, long ret) { + if (ret >= 0) { + return ret; + } + arca_panic(msg); +} + +fix_handle arcad_to_handle(arcad type, arcad data) { + fix_handle res = {.type = arcad_to_type(type), .d = data}; + return res; +} + +fix_handle arca_tuple_to_handle(arcad tuple) { + if (arca_type(tuple) != __TYPE_tuple) { + arca_panic("arca_tuple_to_handle: input is not a tuple"); + } + + size_t len; + check("arca_length", arca_length(tuple, &len)); + if (len != 2) { + arca_panic("arca_tuple_to_handle: input is not a 2-entry tuple"); + } + + return arcad_to_handle(arca_tuple_get(tuple, 0), arca_tuple_get(tuple, 1)); +} + +arcad_pair handle_to_arcad(fix_handle handle) { + arcad_pair res = {type_to_arcad(handle.type), handle.d}; + return res; +} + +arcad handle_to_arca_tuple(fix_handle handle) { + arcad tuple = arca_tuple_create(2); + arcad_pair p = handle_to_arcad(handle); + arca_tuple_set(tuple, 0, p.first); + arca_tuple_set(tuple, 1, p.second); + return tuple; +} diff --git a/fix/fix-shell/fix.h b/fix/fix-shell/fix.h new file mode 100644 index 0000000..47d0bde --- /dev/null +++ b/fix/fix-shell/fix.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "handle.h" + +typedef struct fix_handle { + fix_type type; + arcad d; +} fix_handle; + +typedef struct arcad_pair { + arcad first; + arcad second; +} arcad_pair; + +typedef struct w2c_fixpoint w2c_fixpoint; + +arcad type_to_arcad(fix_type type); +fix_handle arcad_to_handle(arcad type, arcad data); +fix_handle arca_tuple_to_handle(arcad tuple); +arcad_pair handle_to_arcad(fix_handle handle); +arcad handle_to_arca_tuple(fix_handle handle); + +long check(char *msg, long ret); diff --git a/fix/fix-shell/handle.h b/fix/fix-shell/handle.h new file mode 100644 index 0000000..dbea17d --- /dev/null +++ b/fix/fix-shell/handle.h @@ -0,0 +1,7 @@ +#pragma once + +typedef enum fix_type { + BlobObject = 0, + TreeObject = 1, + Null = 2 +} fix_type; diff --git a/fix/fix-shell/main.c b/fix/fix-shell/main.c index fe3f912..8ae567c 100644 --- a/fix/fix-shell/main.c +++ b/fix/fix-shell/main.c @@ -1,157 +1,22 @@ +#include "fix.h" #include "module.h" #include "wasm-rt.h" - +#include #include #include #include #define SELF_PAGE_TABLE 0 -extern wasm_rt_memory_t *WASM_MEMORIES[128]; -extern size_t WASM_MEMORIES_N; - -static int len(const char *s) { - int i = 0; - while (s[i]) - i++; - return i; -} - -static void error_append(const char *msg) { - arca_debug_log((const uint8_t *)msg, len(msg)); -} - -static void error_append_int(const char *msg, int value) { - arca_debug_log_int((const uint8_t* )msg, len(msg), value); -} - -[[noreturn]] void trap(const char *msg) { - error_append(msg); - arca_exit(0); -} - -[[noreturn]] void abort(void) { - error_append("abort"); - arca_exit(0); -} - -uint64_t check(int64_t ret) { - assert(ret >= 0); - return ret; -} - -wasm_rt_externref_t w2c_fixpoint_create_blob_i64(struct w2c_fixpoint *instance, - uint64_t val) { - return check(arca_word_create(val)); -} +[[noreturn]] void trap(const char *msg) { arca_panic(msg); } -wasm_rt_externref_t w2c_fixpoint_get_tree_entry(struct w2c_fixpoint *instance, - wasm_rt_externref_t handle, - uint32_t index) { - arcad entry = check(arca_tuple_get(handle, index)); - return entry; -} - -static size_t bytes_to_wasm_pages(size_t bytes) { - return (bytes + PAGE_SIZE - 1) / PAGE_SIZE; -} - -static arcad create_wasm_pages(size_t wasm_pages) { - size_t bytes = wasm_pages * PAGE_SIZE; - size_t pages = (bytes + 4095) / 4096; - arcad table = arca_table_create(bytes); - for (size_t i = 0; i < pages; i++) { - struct arca_entry entry; - entry.mode = __MODE_read_write; - entry.data = check(arca_page_create(4096)); - arca_table_map(table, (void *)(i * 4096), &entry); - } - return table; -} - -static struct arca_entry map_table(void *addr, arcad table, bool write) { - struct arca_entry entry; - entry.mode = write ? __MODE_read_write: __MODE_read_only; - entry.data = table; - check(arca_mmap(addr, &entry)); - return entry; -} - -void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t n, - wasm_rt_externref_t handle) { - assert(n < WASM_MEMORIES_N); - wasm_rt_memory_t *memory = WASM_MEMORIES[n]; - void *addr = (void *)((size_t)n << 32); - - size_t nbytes; - check(arca_length(handle, &nbytes)); - size_t npages = bytes_to_wasm_pages(nbytes); - memory->size = nbytes; - memory->pages = npages; - - // TODO: map these blobs as read-only - arcad pages; - struct arca_entry entry; - switch (arca_type(handle)) { - case __TYPE_word: { - assert(npages == 1); - pages = create_wasm_pages(npages); - entry = map_table(addr, pages, true); - assert(entry.mode == __MODE_none); - arca_word_read(handle, addr); - arca_mmap(addr, &entry); - assert(entry.mode == __MODE_read_write); - entry.mode = __MODE_read_only; - arca_mmap(addr, &entry); - if (entry.mode != __MODE_none) { - arca_drop(entry.data); - } - return; - } - - case __TYPE_blob: { - pages = check(create_wasm_pages(npages)); - entry = map_table(addr, pages, true); - arca_blob_read(handle, 0, addr, nbytes); - arca_mmap(addr, &entry); - entry.mode = __MODE_read_only; - arca_mmap(addr, &entry); - if (entry.mode != __MODE_none) { - arca_drop(entry.data); - } - return; - } - - case __TYPE_page: { - pages = check(create_wasm_pages(npages)); - entry = map_table(addr, pages, true); - arca_page_read(handle, 0, addr, nbytes); - arca_mmap(addr, &entry); - entry.mode = __MODE_read_only; - arca_mmap(addr, &entry); - if (entry.mode != __MODE_none) { - arca_drop(entry.data); - } - return; - } - - case __TYPE_table: { - map_table(addr, handle, false); - return; - } - - default: - assert(false); - } - - return; -} +[[noreturn]] void abort(void) { arca_panic("abort"); } [[noreturn]] void fmain(void) { w2c_module module; wasm2c_module_instantiate(&module, (struct w2c_fixpoint *)&module); - wasm_rt_externref_t argument = arca_argument(); + wasm_rt_externref_t argument = arca_tuple_to_handle(arca_argument()); wasm_rt_externref_t result = w2c_module_0x5Ffixpoint_apply(&module, argument); - arca_exit(result); + arca_exit(handle_to_arca_tuple(result)); } diff --git a/fix/fix-shell/runtime.c b/fix/fix-shell/runtime.c new file mode 100644 index 0000000..b599353 --- /dev/null +++ b/fix/fix-shell/runtime.c @@ -0,0 +1,165 @@ +#include "runtime.h" +#include "fix.h" + +#include +#include +#include + +extern wasm_rt_memory_t *WASM_MEMORIES[128]; +extern size_t WASM_MEMORIES_N; + +static size_t bytes_to_wasm_pages(size_t bytes) { + return (bytes + PAGE_SIZE - 1) / PAGE_SIZE; +} + +// Create an Arca page table of length `wasm_pages` of Wasm pages +static arcad create_wasm_pages(size_t wasm_pages, size_t page_size) { + size_t bytes = wasm_pages * PAGE_SIZE; + size_t pages = (bytes + page_size) / page_size; + // Creates a page table that covers the length of bytes + arcad table = arca_table_create(bytes); + // For every page in the table, create a rw 4k page + for (size_t i = 0; i < pages; i++) { + struct arca_entry entry; + entry.mode = __MODE_read_write; + // Create a rw 4k page + entry.data = check("arca_page_create", arca_page_create(page_size)); + // Map the page as rw in the table + arca_table_map(table, (void *)(i * page_size), &entry); + } + return table; +} + +static struct arca_entry map_table(void *addr, arcad table, bool write) { + struct arca_entry entry; + entry.mode = write ? __MODE_read_write : __MODE_read_only; + entry.data = table; + check("arca_mmap", arca_mmap(addr, &entry)); + return entry; +} + +static void check_cond(bool predicate) { + if (!predicate) { + arca_panic("Assertion failed"); + } +} + +wasm_rt_externref_t w2c_fixpoint_get_tree_entry(struct w2c_fixpoint *instance, + wasm_rt_externref_t handle, + uint32_t index) { + // Check whether `handle` refers to a TreeObject + if (handle.type != TreeObject) { + arca_log("get_tree_entry: handle does not refer to a TreeObject"); + arca_panic("get_tree_entry: handle does not refer to a TreeObject"); + } + + arcad type = check("arca_tuple_get", arca_tuple_get(handle.d, index * 2)); + arcad data = check("arca_tuple_get", arca_tuple_get(handle.d, index * 2 + 1)); + + return arcad_to_handle(type, data); +} + +wasm_rt_externref_t w2c_fixpoint_create_blob_i64(struct w2c_fixpoint *instance, + uint64_t val) { + arcad data = check("arca_word_create", arca_word_create(val)); + arcad type = type_to_arcad(BlobObject); + return arcad_to_handle(type, data); +} + +void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t n, + wasm_rt_externref_t handle) { + if (handle.type != BlobObject) { + arca_log("attach_blob: handle does not refer to a BlobObject"); + arca_panic("attach_blob: handle does not refer to a BlobObject"); + } + + arcad d = handle.d; + + // check_cond(n < WASM_MEMORIES_N); + wasm_rt_memory_t *memory = WASM_MEMORIES[n]; + // `addr` is the beginning address of this wasm memory in the address space + void *addr = (void *)((size_t)n << 32); + + // Setup size fields of the wasm memory + size_t nbytes; + check("arca_length", arca_length(d, &nbytes)); + size_t npages = bytes_to_wasm_pages(nbytes); + memory->size = nbytes; + memory->pages = npages; + + arcad pages; + struct arca_entry entry; + switch (arca_type(handle.d)) { + case __TYPE_word: { + check_cond(npages == 1); + // Create rw page table and map at `addr` + pages = create_wasm_pages(npages, 4096); + entry = map_table(addr, pages, true); + check_cond(entry.mode == __MODE_none); + // Read the blob content to `addr` + arca_word_read(handle.d, addr); + + // arca_mmap returns the old entry in the page table at `addr` + arca_mmap(addr, &entry); + check_cond(entry.mode == __MODE_read_write); + // set the entry mode to read only + entry.mode = __MODE_read_only; + // map the entry back at the same location; now `addr` is read only and + // contains the word + arca_mmap(addr, &entry); + if (entry.mode != __MODE_none) { + arca_drop(entry.data); + } + return; + } + + case __TYPE_blob: { + pages = create_wasm_pages(npages, 4096); + entry = map_table(addr, pages, true); + arca_blob_read(handle.d, 0, addr, nbytes); + arca_mmap(addr, &entry); + entry.mode = __MODE_read_only; + arca_mmap(addr, &entry); + if (entry.mode != __MODE_none) { + arca_drop(entry.data); + } + return; + } + + case __TYPE_page: { + // Check the size of the page + size_t page_size; + check("arca_length", arca_length(d, &page_size)); + pages = create_wasm_pages(npages, page_size); + + // Map the page for Blob to the created table + entry.mode = __MODE_read_only; + entry.data = d; + arca_table_set(pages, 0, &entry); + + // Map the table at `addr` + entry = map_table(addr, pages, false); + + // Drop the old entry at `addr` if any + if (entry.mode != __MODE_none) { + arca_drop(entry.data); + } + return; + } + + case __TYPE_table: { + entry = map_table(addr, handle.d, false); + + // Drop the old entry at `addr` if any + if (entry.mode != __MODE_none) { + arca_drop(entry.data); + } + return; + } + + default: + check_cond(false); + } + + return; +} diff --git a/fix/fix-shell/runtime.h b/fix/fix-shell/runtime.h new file mode 100644 index 0000000..c491b4c --- /dev/null +++ b/fix/fix-shell/runtime.h @@ -0,0 +1,15 @@ +#pragma once + +#include "wasm-rt.h" +#include + +// Get `index`th entry from a Tree +wasm_rt_externref_t w2c_fixpoint_get_tree_entry(struct w2c_fixpoint *instance, + wasm_rt_externref_t handle, + uint32_t index); +// Attach the Blob referred by `handle` to `index`th wasm memory +void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t index, + wasm_rt_externref_t handle); +// Create a Blob with content `val` +wasm_rt_externref_t w2c_fixpoint_create_blob_i64(struct w2c_fixpoint *instance, + uint64_t val); diff --git a/fix/fix-shell/wasm-rt-impl.c b/fix/fix-shell/wasm-rt-impl.c index e3ce5b2..cc5cb93 100644 --- a/fix/fix-shell/wasm-rt-impl.c +++ b/fix/fix-shell/wasm-rt-impl.c @@ -26,7 +26,7 @@ wasm_rt_memory_t *WASM_MEMORIES[128]; size_t WASM_MEMORIES_N = 0; -uint64_t check(int64_t ret); +long check(char *msg, long ret); [[noreturn]] void trap(const char *msg); void wasm_rt_trap(wasm_rt_trap_t code) { @@ -84,8 +84,9 @@ void wasm_rt_allocate_memory(wasm_rt_memory_t *memory, uint64_t initial_pages, memory->is64 = is64; for (uint64_t i = 0; i < byte_length >> 12; i++) { - arcad page = check(arca_page_create(1 << 12)); - check(arca_mmap(memory->data + i * 4096, &(struct arca_entry){ + arcad page = check("arca_page_create", arca_page_create(1 << 12)); + check("arca_mmap", + arca_mmap(memory->data + i * 4096, &(struct arca_entry){ .mode = __MODE_read_write, .data = page, })); @@ -107,12 +108,12 @@ uint64_t wasm_rt_grow_memory(wasm_rt_memory_t *memory, uint64_t delta) { uint64_t delta_size = delta * PAGE_SIZE; for (uint64_t i = 0; i < delta_size >> 12; i++) { - arcad page = check(arca_page_create(1 << 12)); - check(arca_mmap(memory->data + +memory->size + i * 4096, - &(struct arca_entry){ - .mode = __MODE_read_write, - .data = page, - })); + arcad page = check("arca_page_create", arca_page_create(1 << 12)); + check("arca_mmap", arca_mmap(memory->data + +memory->size + i * 4096, + &(struct arca_entry){ + .mode = __MODE_read_write, + .data = page, + })); } memory->pages = new_pages; diff --git a/fix/fix-shell/wasm-rt.h b/fix/fix-shell/wasm-rt.h index 9557513..6513f0a 100644 --- a/fix/fix-shell/wasm-rt.h +++ b/fix/fix-shell/wasm-rt.h @@ -22,6 +22,8 @@ #include #include +#include "fix.h" + #define PAGE_SIZE 65536 [[noreturn]] void abort(void); @@ -129,10 +131,11 @@ typedef struct { static const wasm_rt_funcref_t wasm_rt_funcref_null_value; /** The type of an external reference (opaque to WebAssembly). */ -typedef int64_t wasm_rt_externref_t; +typedef struct fix_handle wasm_rt_externref_t; /** Default (null) value of an externref */ -static const wasm_rt_externref_t wasm_rt_externref_null_value = 0; +static const wasm_rt_externref_t wasm_rt_externref_null_value = {.d = -1, + .type = Null}; /** A Memory object. */ typedef struct { diff --git a/fix/src/handle.rs b/fix/src/handle.rs new file mode 100644 index 0000000..ec23da9 --- /dev/null +++ b/fix/src/handle.rs @@ -0,0 +1,170 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] + +use crate::runtime::{DeterministicEquivRuntime, ExecutionRuntime}; +use arca::Runtime; +use bytemuck::bytes_of; +use kernel::types::{Tuple, Value, Word}; + +#[derive(Debug)] +pub enum Error { + OOB, + TypeMismatch, +} + +include!(concat!(env!("OUT_DIR"), "/handle-bindings.rs")); + +type BlobData = Value; +type TreeData = Tuple; + +#[derive(Clone, Debug)] +pub enum Handle { + BlobObject(BlobData), + TreeObject(TreeData), +} + +impl Handle { + fn to_fix_type(&self) -> Word { + match self { + Handle::BlobObject(_) => Runtime::create_word(fix_type::BlobObject.into()), + Handle::TreeObject(_) => Runtime::create_word(fix_type::TreeObject.into()), + } + } + + fn to_raw_value(&self) -> Value { + match self { + Handle::BlobObject(blob) => blob.clone(), + Handle::TreeObject(tree) => Value::Tuple(tree.clone()), + } + } + + fn to_arca_tuple(&self) -> Value { + let mut t = Runtime::create_tuple(2); + t.set(0, self.to_fix_type()); + t.set(1, self.to_raw_value()); + Value::Tuple(t) + } + + fn from_raw_type(fix_type: &Value) -> Result { + match fix_type { + Value::Word(w) => Ok(w.read()), + _ => Err(Error::TypeMismatch), + } + } + + fn from_raw_parts(fix_type: &Value, data: Value) -> Result { + match Self::from_raw_type(fix_type)? as u32 { + fix_type::BlobObject => Ok(Handle::BlobObject(data)), + fix_type::TreeObject => match data { + Value::Tuple(t) => Ok(Handle::TreeObject(t)), + _ => Err(Error::TypeMismatch), + }, + _ => Err(Error::TypeMismatch), + } + } + + fn from_raw_tuple(tuple: &Tuple) -> Result { + Self::from_raw_parts(&tuple.get(0), tuple.get(1)) + } +} + +pub struct FixRuntime {} + +impl FixRuntime { + fn new() -> Self { + Self {} + } + + pub fn create_scrach_tree(length: usize) -> TreeData { + Runtime::create_tuple(length * 2) + } + + fn get_tree(handle: &Handle) -> Result<&TreeData, Error> { + match handle { + Handle::TreeObject(treedata) => Ok(treedata), + _ => Err(Error::TypeMismatch), + } + } +} + +impl DeterministicEquivRuntime for FixRuntime { + type BlobData = BlobData; + type TreeData = TreeData; + type Handle = Handle; + type Error = Error; + + fn create_blob_i64(data: u64) -> Self::Handle { + Handle::BlobObject(Value::Word(Runtime::create_word(data))) + } + + fn create_blob(data: Self::BlobData) -> Self::Handle { + Handle::BlobObject(data) + } + + fn create_tree(data: Self::TreeData) -> Self::Handle { + Handle::TreeObject(data) + } + + fn length(handle: &Self::Handle) -> Result { + match handle { + Handle::BlobObject(data) => match data { + Value::Word(word) => Ok(word.len()), + Value::Blob(blob) => Ok(blob.len()), + Value::Page(page) => Ok(page.len()), + _ => Err(Error::TypeMismatch), + }, + Handle::TreeObject(tuple) => Ok(tuple.len() / 2), + } + } + + fn get_blob(handle: &Self::Handle) -> Result<&[u8], Self::Error> { + match handle { + Handle::BlobObject(v) => match v { + Value::Word(w) => Ok(bytes_of(w.inner().as_ref())), + Value::Blob(b) => Ok(b.inner().as_ref()), + Value::Page(p) => Ok(p.inner().as_ref()), + _ => Err(Error::TypeMismatch), + }, + Handle::TreeObject(_) => Err(Error::TypeMismatch), + } + } + + fn set_tree_entry( + data: &mut Self::TreeData, + index: usize, + handle: &Self::Handle, + ) -> Result { + let prev_type = data.set(index * 2, handle.to_fix_type()); + let prev_data = data.set(index * 2 + 1, handle.to_raw_value()); + Self::Handle::from_raw_parts(&prev_type, prev_data) + } + + fn get_tree_entry(data: &Self::TreeData, index: usize) -> Result { + let fix_type = data.get(index * 2); + let data = data.get(index * 2 + 1); + Self::Handle::from_raw_parts(&fix_type, data) + } + + fn is_blob(handle: &mut Self::Handle) -> bool { + matches!(handle, Handle::BlobObject(_)) + } + + fn is_tree(handle: &mut Self::Handle) -> bool { + matches!(handle, Handle::TreeObject(_)) + } +} + +impl ExecutionRuntime for FixRuntime { + fn execute(combination: &Self::Handle) -> Result { + let tree = Self::get_tree(combination)?; + let function_handle = Self::get_tree_entry(tree, 1)?; + let elf = Self::get_blob(&function_handle)?; + + let f = common::elfloader::load_elf(elf).expect("Failed to load elf"); + let f = Runtime::apply_function(f, combination.to_arca_tuple()); + + let result = f.force().try_into().unwrap(); + + Handle::from_raw_tuple(&result) + } +} diff --git a/fix/src/main.rs b/fix/src/main.rs index eaf3406..f3a03a6 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -10,23 +10,32 @@ use arca::Runtime; use kernel::prelude::*; +use crate::{handle::FixRuntime, runtime::DeterministicEquivRuntime, runtime::ExecutionRuntime}; + extern crate alloc; +pub mod handle; +pub mod runtime; + const MODULE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/addblob")); #[kmain] async fn main(_: &[usize]) { - let f = common::elfloader::load_elf(MODULE).expect("Failed to load elf"); - let mut tree = Runtime::create_tuple(4); - let dummy = Runtime::create_word(0xcafeb0ba); - - tree.set(0, dummy); - tree.set(1, dummy); - tree.set(2, Runtime::create_word(7)); - tree.set(3, Runtime::create_word(1024)); - - let f = Runtime::apply_function(f, arca::Value::Tuple(tree)); - let word: Word = f.force().try_into().unwrap(); - log::info!("{:?}", word.read()); - assert_eq!(word.read(), 1031); + let dummy = FixRuntime::create_blob_i64(0xcafeb0ba); + let function = FixRuntime::create_blob(Value::Blob(Runtime::create_blob(MODULE))); + + let mut tree = FixRuntime::create_scrach_tree(4); + let _ = FixRuntime::set_tree_entry(&mut tree, 0, &dummy); + let _ = FixRuntime::set_tree_entry(&mut tree, 1, &function); + let _ = FixRuntime::set_tree_entry(&mut tree, 2, &FixRuntime::create_blob_i64(7)); + let _ = FixRuntime::set_tree_entry(&mut tree, 3, &FixRuntime::create_blob_i64(1024)); + let combination = FixRuntime::create_tree(tree); + let result = FixRuntime::execute(&combination).expect("Failed to execute"); + + let mut arr = [0u8; 8]; + let result_blob = FixRuntime::get_blob(&result).expect("Add did not return a Blob"); + arr[..result_blob.len()].copy_from_slice(result_blob); + let num = u64::from_le_bytes(arr); + log::info!("{:?}", num); + assert_eq!(num, 1031); } diff --git a/fix/src/runtime.rs b/fix/src/runtime.rs new file mode 100644 index 0000000..aab4b14 --- /dev/null +++ b/fix/src/runtime.rs @@ -0,0 +1,28 @@ +pub trait DeterministicEquivRuntime { + type BlobData: Clone + core::fmt::Debug; + type TreeData: Clone + core::fmt::Debug; + type Handle: Clone + core::fmt::Debug; + type Error; + + fn create_blob_i64(data: u64) -> Self::Handle; + fn create_blob(data: Self::BlobData) -> Self::Handle; + fn create_tree(data: Self::TreeData) -> Self::Handle; + + fn length(handle: &Self::Handle) -> Result; + + fn get_blob(handle: &Self::Handle) -> Result<&[u8], Self::Error>; + fn get_tree_entry(data: &Self::TreeData, index: usize) -> Result; + + fn set_tree_entry( + data: &mut Self::TreeData, + index: usize, + handle: &Self::Handle, + ) -> Result; + + fn is_blob(handle: &mut Self::Handle) -> bool; + fn is_tree(handle: &mut Self::Handle) -> bool; +} + +pub trait ExecutionRuntime: DeterministicEquivRuntime { + fn execute(combination: &Self::Handle) -> Result; +} From a065878a211ce40d4b754666ccbf06046d9abe3d Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 15 Oct 2025 17:20:57 -0700 Subject: [PATCH 3/8] feat: implement macros for translating between rust handles and __m256i --- Cargo.lock | 25 ++- fix/Cargo.toml | 6 + fix/handle/Cargo.toml | 13 ++ fix/handle/src/lib.rs | 6 + fix/handle/src/rawhandle.rs | 305 ++++++++++++++++++++++++++++++++++++ fix/src/handle.rs | 170 -------------------- fix/src/main.rs | 5 +- macros/Cargo.toml | 2 +- macros/src/bitpack.rs | 140 +++++++++++++++++ macros/src/lib.rs | 6 + modules/arca-musl | 2 +- 11 files changed, 506 insertions(+), 174 deletions(-) create mode 100644 fix/handle/Cargo.toml create mode 100644 fix/handle/src/lib.rs create mode 100644 fix/handle/src/rawhandle.rs delete mode 100644 fix/src/handle.rs create mode 100644 macros/src/bitpack.rs diff --git a/Cargo.lock b/Cargo.lock index 27369db..a4918f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -279,6 +279,17 @@ dependencies = [ "syn", ] +[[package]] +name = "bitfield-struct" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3ca019570363e800b05ad4fd890734f28ac7b72f563ad8a35079efb793616f8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -691,16 +702,20 @@ dependencies = [ "async-lock", "autotools", "bindgen", + "bitfield-struct 0.11.0", "bytemuck", "cc", "chrono", "cmake", "common", "derive_more", + "fixhandle", "futures", "include_directory", "kernel", "log", + "macros", + "ninep", "postcard", "serde", "serde_bytes", @@ -708,6 +723,14 @@ dependencies = [ "user", ] +[[package]] +name = "fixhandle" +version = "0.1.0" +dependencies = [ + "derive_more", + "macros", +] + [[package]] name = "foldhash" version = "0.1.5" @@ -967,7 +990,7 @@ dependencies = [ "arca", "arcane", "async-lock", - "bitfield-struct", + "bitfield-struct 0.7.0", "cc", "cfg-if", "common", diff --git a/fix/Cargo.toml b/fix/Cargo.toml index aac8da4..4df65c9 100644 --- a/fix/Cargo.toml +++ b/fix/Cargo.toml @@ -14,11 +14,15 @@ klog-warn = ["kernel/klog-warn"] klog-error = ["kernel/klog-error"] klog-off = ["kernel/klog-off"] debugcon = ["kernel/debugcon"] +testing-mode = ["fixhandle/testing-mode"] [dependencies] arca = { path = "../arca", features = ["serde"] } kernel = { path = "../kernel" } +macros = { path = "../macros" } common = { path = "../common", default-features = false } +fixhandle = { path = "handle" } +fixruntime = { path = "runtime" } log = "0.4.27" serde = { version = "1.0.219", default-features = false, features = ["alloc", "derive"] } chrono = { version = "0.4.41", default-features = false, features = ["alloc", "serde"] } @@ -31,8 +35,10 @@ futures = { version = "0.3.31", default-features = false, features = ["alloc", " user = { path = "../user", artifact = "bin", target = "x86_64-unknown-none" } async-lock = { version = "3.4.1", default-features = false } bytemuck = "1.24.0" +bitfield-struct = "0.11.0" [build-dependencies] +fixshell = { path = "shell", artifact="staticlib", target = "x86_64-unknown-none" } anyhow = "1.0.98" bindgen = "0.72.1" cc = "1.2.30" diff --git a/fix/handle/Cargo.toml b/fix/handle/Cargo.toml new file mode 100644 index 0000000..928271d --- /dev/null +++ b/fix/handle/Cargo.toml @@ -0,0 +1,13 @@ +cargo-features = ["per-package-target"] + +[package] +name = "fixhandle" +version = "0.1.0" +edition = "2024" + +[dependencies] +derive_more = { version = "2.0.1", default-features = false, features = ["full"] } +macros = { path = "../../macros" } + +[features] +testing-mode = [] diff --git a/fix/handle/src/lib.rs b/fix/handle/src/lib.rs new file mode 100644 index 0000000..9fd3974 --- /dev/null +++ b/fix/handle/src/lib.rs @@ -0,0 +1,6 @@ +#![no_std] +#![feature(portable_simd)] +#![feature(test)] +#![allow(dead_code)] + +pub mod rawhandle; diff --git a/fix/handle/src/rawhandle.rs b/fix/handle/src/rawhandle.rs new file mode 100644 index 0000000..7e98ff7 --- /dev/null +++ b/fix/handle/src/rawhandle.rs @@ -0,0 +1,305 @@ +#![allow(clippy::double_parens)] +use core::simd::{u8x32, u16x16, u64x4}; +use derive_more::{From, TryInto, TryUnwrap, Unwrap}; +use macros::BitPack; + +pub trait BitPack { + const TAGBITS: u32; + fn pack(&self) -> u8x32; + fn unpack(content: u8x32) -> Self; +} + +const fn ceil_log2(n: u32) -> u32 { + if n <= 1 { + 0 + } else { + 32 - (n - 1).leading_zeros() + } +} + +const fn bitmask256() -> u8x32 { + assert!(I + WIDTH <= 256); + let mut out = [0u8; 32]; + let mut i = I; + loop { + if i >= I + WIDTH { + break; + } + + let byte = i / 8; + let off = i % 8; + out[byte as usize] |= 1u8 << off; + + i += 1; + } + u8x32::from_array(out) +} + +#[derive(Debug, Clone, Copy)] +struct RawHandle { + content: u8x32, +} + +impl RawHandle { + fn new(content: u8x32) -> Self { + Self { content } + } +} + +#[derive(Debug, Clone, Copy)] +struct MachineHandle { + inner: RawHandle, +} + +impl MachineHandle { + fn new(payload: u64, size: u64) -> Self { + assert!(size & 0xffff000000000000 == 0); + let field = unsafe { + core::mem::transmute::, core::simd::Simd>( + u64x4::from_array([payload, 0, 0, size]), + ) + }; + let inner = RawHandle::new(field); + Self { inner } + } + + fn get_payload(&self) -> u64 { + let field: &u64x4 = unsafe { core::mem::transmute(&self.inner.content) }; + field[0] + } + + fn get_size(&self) -> u64 { + let field: &u64x4 = unsafe { core::mem::transmute(&self.inner.content) }; + field[3] & 0xffffffffffff + } +} + +impl BitPack for MachineHandle { + const TAGBITS: u32 = 240; + + fn unpack(content: u8x32) -> Self { + let inner = RawHandle::new(content); + Self { inner } + } + + fn pack(&self) -> u8x32 { + self.inner.content + } +} + +#[derive(Debug, Clone, Copy)] +pub struct VirtualHandle { + inner: MachineHandle, +} + +impl BitPack for VirtualHandle { + const TAGBITS: u32 = MachineHandle::TAGBITS; + fn unpack(content: u8x32) -> Self { + let inner = MachineHandle::unpack(content); + Self { inner } + } + + fn pack(&self) -> u8x32 { + self.inner.pack() + } +} + +impl VirtualHandle { + pub fn new(addr: usize, size: usize) -> Self { + let inner = MachineHandle::new(addr as u64, size as u64); + Self { inner } + } + + pub fn addr(&self) -> usize { + self.inner.get_payload().try_into().unwrap() + } + + pub fn len(&self) -> usize { + self.inner.get_size().try_into().unwrap() + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +#[derive(Debug, Clone, Copy)] +pub struct PhysicalHandle { + inner: MachineHandle, +} + +impl BitPack for PhysicalHandle { + const TAGBITS: u32 = MachineHandle::TAGBITS; + fn unpack(content: u8x32) -> Self { + let inner = MachineHandle::unpack(content); + Self { inner } + } + + fn pack(&self) -> u8x32 { + self.inner.pack() + } +} + +impl PhysicalHandle { + pub fn new(local_id: usize, size: usize) -> Self { + let inner = MachineHandle::new(local_id as u64, size as u64); + Self { inner } + } + + pub fn local_id(&self) -> usize { + self.inner.get_payload().try_into().unwrap() + } + + pub fn len(&self) -> usize { + self.inner.get_size().try_into().unwrap() + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +#[derive(BitPack, Debug, Clone, Copy, From, TryUnwrap)] +pub enum Handle { + VirtualHandle(VirtualHandle), + PhysicalHandle(PhysicalHandle), +} + +#[derive(BitPack, Debug, TryUnwrap, Unwrap, From, Clone, Copy)] +#[unwrap(ref)] +#[try_unwrap(ref)] +pub enum BlobName { + Blob(Handle), +} + +#[derive(BitPack, Debug, Unwrap, Clone, Copy)] +pub enum TreeName { + NotTag(Handle), + Tag(Handle), +} + +impl From for Handle { + fn from(val: TreeName) -> Self { + match val { + TreeName::Tag(h) | TreeName::NotTag(h) => h, + } + } +} + +#[derive(BitPack, Debug, TryUnwrap, Unwrap, From, Clone, Copy)] +#[try_unwrap(ref)] +pub enum Ref { + BlobName(BlobName), + TreeName(TreeName), +} + +#[derive(BitPack, Debug, TryUnwrap, Unwrap, From, Clone, Copy)] +#[try_unwrap(ref)] +pub enum Object { + BlobName(BlobName), + TreeName(TreeName), +} + +#[derive(BitPack, Debug, Unwrap, Clone, Copy)] +pub enum Thunk { + Identification(Ref), + Application(TreeName), + Selection(TreeName), +} + +#[derive(BitPack, Debug, TryUnwrap, Unwrap, Clone, Copy)] +#[try_unwrap(ref)] +pub enum Encode { + Strict(Thunk), + Shallow(Thunk), +} + +#[derive(Debug, BitPack, TryUnwrap, Unwrap, From, Clone, Copy)] +#[try_unwrap(ref)] +pub enum FixHandle { + Ref(Ref), + Object(Object), + Thunk(Thunk), + Encode(Encode), +} + +#[derive(BitPack, Debug, TryInto, Unwrap, From, Clone, Copy)] +pub enum Value { + Ref(Ref), + Object(Object), + Thunk(Thunk), +} + +#[cfg(test)] +mod tests { + use core::simd::u16x16; + + use super::*; + + extern crate std; + extern crate test; + + #[test] + fn test_tag_gits() { + assert_eq!(Handle::TAGBITS, 241); + assert_eq!(BlobName::TAGBITS, 241); + assert_eq!(TreeName::TAGBITS, 242); + assert_eq!(Object::TAGBITS, 243); + assert_eq!(Thunk::TAGBITS, 245); + } + + #[test] + fn test_tag_masks() { + assert_eq!(Handle::TAGMASK.as_array()[30], 0b00000001); + assert_eq!(Handle::TAGMASK.as_array()[31], 0b00000000); + + let field: u16x16 = unsafe { core::mem::transmute(Handle::TAGMASK) }; + assert_eq!(field[15], 0b0000000000000001); + + assert_eq!(TreeName::TAGMASK.as_array()[30], 0b00000010); + assert_eq!(TreeName::TAGMASK.as_array()[31], 0b00000000); + + assert_eq!(Thunk::TAGMASK.as_array()[30], 0b00011000); + assert_eq!(Thunk::TAGMASK.as_array()[31], 0b00000000); + } + + #[test] + fn test_pack() { + let h: Handle = PhysicalHandle::new(42, 10086).into(); + let res = h.pack(); + let field: &u16x16 = unsafe { core::mem::transmute(&res) }; + assert_eq!(field[15], 0b0000000000000001); + + let h: TreeName = TreeName::Tag(PhysicalHandle::new(42, 10086).into()); + let res = h.pack(); + let field: &u16x16 = unsafe { core::mem::transmute(&res) }; + assert_eq!(field[15], 0b0000000000000011); + } + + #[test] + fn test_round_trip() { + let h: Handle = PhysicalHandle::new(42, 10086).into(); + let res = Handle::unpack(h.pack()) + .try_unwrap_physical_handle() + .expect("Failed to unwrap to PhysicalHandle"); + assert_eq!(res.local_id(), 42); + assert_eq!(res.len(), 10086); + + let h: FixHandle = FixHandle::Object(Object::BlobName(BlobName::Blob( + PhysicalHandle::new(42, 10086).into(), + ))); + let res = FixHandle::unpack(h.pack()) + .try_unwrap_object() + .expect("Failed to unwrap to Object") + .try_unwrap_blob_name() + .expect("Failed to unwrap to BlobName") + .unwrap_blob() + .try_unwrap_physical_handle() + .expect("Failed to unwrap to PhysicalHandle"); + + assert_eq!(res.local_id(), 42); + assert_eq!(res.len(), 10086); + } +} diff --git a/fix/src/handle.rs b/fix/src/handle.rs deleted file mode 100644 index ec23da9..0000000 --- a/fix/src/handle.rs +++ /dev/null @@ -1,170 +0,0 @@ -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] - -use crate::runtime::{DeterministicEquivRuntime, ExecutionRuntime}; -use arca::Runtime; -use bytemuck::bytes_of; -use kernel::types::{Tuple, Value, Word}; - -#[derive(Debug)] -pub enum Error { - OOB, - TypeMismatch, -} - -include!(concat!(env!("OUT_DIR"), "/handle-bindings.rs")); - -type BlobData = Value; -type TreeData = Tuple; - -#[derive(Clone, Debug)] -pub enum Handle { - BlobObject(BlobData), - TreeObject(TreeData), -} - -impl Handle { - fn to_fix_type(&self) -> Word { - match self { - Handle::BlobObject(_) => Runtime::create_word(fix_type::BlobObject.into()), - Handle::TreeObject(_) => Runtime::create_word(fix_type::TreeObject.into()), - } - } - - fn to_raw_value(&self) -> Value { - match self { - Handle::BlobObject(blob) => blob.clone(), - Handle::TreeObject(tree) => Value::Tuple(tree.clone()), - } - } - - fn to_arca_tuple(&self) -> Value { - let mut t = Runtime::create_tuple(2); - t.set(0, self.to_fix_type()); - t.set(1, self.to_raw_value()); - Value::Tuple(t) - } - - fn from_raw_type(fix_type: &Value) -> Result { - match fix_type { - Value::Word(w) => Ok(w.read()), - _ => Err(Error::TypeMismatch), - } - } - - fn from_raw_parts(fix_type: &Value, data: Value) -> Result { - match Self::from_raw_type(fix_type)? as u32 { - fix_type::BlobObject => Ok(Handle::BlobObject(data)), - fix_type::TreeObject => match data { - Value::Tuple(t) => Ok(Handle::TreeObject(t)), - _ => Err(Error::TypeMismatch), - }, - _ => Err(Error::TypeMismatch), - } - } - - fn from_raw_tuple(tuple: &Tuple) -> Result { - Self::from_raw_parts(&tuple.get(0), tuple.get(1)) - } -} - -pub struct FixRuntime {} - -impl FixRuntime { - fn new() -> Self { - Self {} - } - - pub fn create_scrach_tree(length: usize) -> TreeData { - Runtime::create_tuple(length * 2) - } - - fn get_tree(handle: &Handle) -> Result<&TreeData, Error> { - match handle { - Handle::TreeObject(treedata) => Ok(treedata), - _ => Err(Error::TypeMismatch), - } - } -} - -impl DeterministicEquivRuntime for FixRuntime { - type BlobData = BlobData; - type TreeData = TreeData; - type Handle = Handle; - type Error = Error; - - fn create_blob_i64(data: u64) -> Self::Handle { - Handle::BlobObject(Value::Word(Runtime::create_word(data))) - } - - fn create_blob(data: Self::BlobData) -> Self::Handle { - Handle::BlobObject(data) - } - - fn create_tree(data: Self::TreeData) -> Self::Handle { - Handle::TreeObject(data) - } - - fn length(handle: &Self::Handle) -> Result { - match handle { - Handle::BlobObject(data) => match data { - Value::Word(word) => Ok(word.len()), - Value::Blob(blob) => Ok(blob.len()), - Value::Page(page) => Ok(page.len()), - _ => Err(Error::TypeMismatch), - }, - Handle::TreeObject(tuple) => Ok(tuple.len() / 2), - } - } - - fn get_blob(handle: &Self::Handle) -> Result<&[u8], Self::Error> { - match handle { - Handle::BlobObject(v) => match v { - Value::Word(w) => Ok(bytes_of(w.inner().as_ref())), - Value::Blob(b) => Ok(b.inner().as_ref()), - Value::Page(p) => Ok(p.inner().as_ref()), - _ => Err(Error::TypeMismatch), - }, - Handle::TreeObject(_) => Err(Error::TypeMismatch), - } - } - - fn set_tree_entry( - data: &mut Self::TreeData, - index: usize, - handle: &Self::Handle, - ) -> Result { - let prev_type = data.set(index * 2, handle.to_fix_type()); - let prev_data = data.set(index * 2 + 1, handle.to_raw_value()); - Self::Handle::from_raw_parts(&prev_type, prev_data) - } - - fn get_tree_entry(data: &Self::TreeData, index: usize) -> Result { - let fix_type = data.get(index * 2); - let data = data.get(index * 2 + 1); - Self::Handle::from_raw_parts(&fix_type, data) - } - - fn is_blob(handle: &mut Self::Handle) -> bool { - matches!(handle, Handle::BlobObject(_)) - } - - fn is_tree(handle: &mut Self::Handle) -> bool { - matches!(handle, Handle::TreeObject(_)) - } -} - -impl ExecutionRuntime for FixRuntime { - fn execute(combination: &Self::Handle) -> Result { - let tree = Self::get_tree(combination)?; - let function_handle = Self::get_tree_entry(tree, 1)?; - let elf = Self::get_blob(&function_handle)?; - - let f = common::elfloader::load_elf(elf).expect("Failed to load elf"); - let f = Runtime::apply_function(f, combination.to_arca_tuple()); - - let result = f.force().try_into().unwrap(); - - Handle::from_raw_tuple(&result) - } -} diff --git a/fix/src/main.rs b/fix/src/main.rs index f3a03a6..145b36e 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -5,12 +5,15 @@ #![feature(iterator_try_collect)] #![feature(box_patterns)] #![feature(never_type)] +#![feature(portable_simd)] #![allow(dead_code)] use arca::Runtime; use kernel::prelude::*; -use crate::{handle::FixRuntime, runtime::DeterministicEquivRuntime, runtime::ExecutionRuntime}; +use crate::{ + handle::handle::FixRuntime, runtime::DeterministicEquivRuntime, runtime::ExecutionRuntime, +}; extern crate alloc; diff --git a/macros/Cargo.toml b/macros/Cargo.toml index e7c43a0..266a891 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" proc-macro-crate = "3.1.0" proc-macro2 = "1.0.86" quote = "1.0.36" -syn = "2.0.67" +syn = { version = "2.0.67", features = ["full"] } [lib] proc-macro = true diff --git a/macros/src/bitpack.rs b/macros/src/bitpack.rs new file mode 100644 index 0000000..aeebdaa --- /dev/null +++ b/macros/src/bitpack.rs @@ -0,0 +1,140 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Ident}; + +pub fn bitpack(input: TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + + match input.data { + Data::Enum(de) => bitpack_enum(&name, de), + Data::Struct(_) => compile_error("Unable to create bitpack for struct"), + Data::Union(_) => compile_error("Unable to create bitpack for union"), + } +} + +fn compile_error(msg: &str) -> TokenStream { + syn::Error::new(proc_macro2::Span::call_site(), msg) + .to_compile_error() + .into() +} + +const fn ceil_log2(n: u32) -> u32 { + if n <= 1 { + 0 + } else { + 32 - (n - 1).leading_zeros() + } +} + +struct Variant { + index: u32, + pat: proc_macro2::TokenStream, + construct: proc_macro2::TokenStream, + width: proc_macro2::TokenStream, + unpack: proc_macro2::TokenStream, +} + +fn bitpack_enum(name: &Ident, de: DataEnum) -> TokenStream { + let mut variants = Vec::new(); + for (index, v) in de.variants.iter().enumerate() { + let ident = v.ident.clone(); + + let ty = match &v.fields { + syn::Fields::Named(fields_named) => { + if fields_named.named.len() != 1 { + return compile_error("Unable to create bitpack for variants not of 1 field"); + } + &fields_named.named.first().unwrap().ty + } + syn::Fields::Unnamed(fields_unnamed) => { + if fields_unnamed.unnamed.len() != 1 { + return compile_error("Unable to create bitpack for variants not of 1 field"); + } + &fields_unnamed.unnamed.first().unwrap().ty + } + syn::Fields::Unit => { + return compile_error("Unable to create bitpack for variants not of 1 field") + } + }; + + let pat = quote! { #name::#ident(inner) }; + let construct = quote! { Self::#ident }; + let width = quote! { #ty::TAGBITS }; + let unpack = quote! { #ty::unpack }; + + variants.push(Variant { + index: index as u32, + pat, + construct, + width, + unpack, + }) + } + + let child_widths = variants.iter().map(|v| &v.width); + let max_child_widths = quote! { + { + let mut m: u32 = 0; + #( { + let w = #child_widths; if w > m { m = w; } + })* + m + } + }; + let curr_width = ceil_log2(variants.len().try_into().unwrap()); + + let tag_bits = quote! { #max_child_widths + #curr_width }; + let tag_mask = quote! { bitmask256::<#max_child_widths, #curr_width>() }; + + let unpack_arms = variants.iter().map(|v| { + let index: u64 = v.index.into(); + let construct = &v.construct; + let unpack = &v.unpack; + quote! { + #index => { #construct( #unpack( content )) } + } + }); + + let pack_arms = variants.iter().map(|v| { + let index = v.index; + let pat = &v.pat; + quote! { + #pat => { + let mut result = inner.pack(); + result &= !Self::TAGMASK; + let field: &mut u16x16 = unsafe { core::mem::transmute( &mut result ) }; + field[15] |= (#index << (Self::TAGBITS - 240 - 1)) as u16; + result + } + } + }); + + let output = quote! { + impl #name { + const TAGMASK: u8x32 = #tag_mask; + } + + impl BitPack for #name { + const TAGBITS: u32 = #tag_bits; + + fn pack(&self) -> u8x32 { + match self { + #(#pack_arms)* + } + } + + fn unpack(content: u8x32) -> Self { + let tag = content & Self::TAGMASK; + let field: &u16x16 = unsafe { core::mem::transmute( &tag ) }; + let tag = field[15] >> (Self::TAGBITS - 240 - 1); + match tag as u64 { + #(#unpack_arms)* + _ => todo!() + } + } + + } + }; + output.into() +} diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 9a79cc4..8ce770b 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,5 +1,6 @@ use proc_macro::TokenStream; +mod bitpack; mod core_local; mod testing; mod util; @@ -33,3 +34,8 @@ pub fn arca_test(_attr: TokenStream, item: TokenStream) -> TokenStream { pub fn kmain(attr: TokenStream, item: TokenStream) -> TokenStream { util::kmain(attr, item) } + +#[proc_macro_derive(BitPack)] +pub fn bitpack(input: TokenStream) -> TokenStream { + bitpack::bitpack(input) +} diff --git a/modules/arca-musl b/modules/arca-musl index a88bc69..6ffcd36 160000 --- a/modules/arca-musl +++ b/modules/arca-musl @@ -1 +1 @@ -Subproject commit a88bc6999eb736d93a0aab0afe07c99e4e1ec559 +Subproject commit 6ffcd3681de8fcfbba252b85a72ae294bd39fe93 From 6934dacf641683d6ca461e23efb1ef3e33277af0 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Tue, 4 Nov 2025 15:05:13 -0800 Subject: [PATCH 4/8] wip: fix shell stuffs --- Cargo.lock | 49 +++++++ Cargo.toml | 4 +- fix/build.rs | 22 +-- fix/fix-shell/bindings.h | 14 ++ fix/fix-shell/fix.c | 61 --------- fix/fix-shell/fix.h | 25 ---- fix/fix-shell/handle.h | 7 - fix/fix-shell/main.c | 6 +- fix/fix-shell/runtime.c | 164 ++++------------------- fix/fix-shell/runtime.h | 9 +- fix/fix-shell/wasm-rt-impl.c | 64 ++++++++- fix/fix-shell/wasm-rt.h | 8 +- fix/handle/src/lib.rs | 7 +- fix/handle/src/rawhandle.rs | 15 +-- fix/handle/src/testing.rs | 5 + fix/runtime/Cargo.toml | 38 ++++++ fix/runtime/src/bottom.rs | 174 ++++++++++++++++++++++++ fix/runtime/src/data.rs | 157 ++++++++++++++++++++++ fix/runtime/src/fixruntime.rs | 98 ++++++++++++++ fix/runtime/src/lib.rs | 9 ++ fix/runtime/src/runtime.rs | 29 ++++ fix/runtime/src/storage.rs | 96 +++++++++++++ fix/shell/Cargo.toml | 20 +++ fix/shell/build.rs | 6 + fix/shell/src/lib.rs | 7 + fix/shell/src/runtime.rs | 22 +++ fix/shell/src/shell.rs | 244 ++++++++++++++++++++++++++++++++++ fix/src/main.rs | 50 +++---- fix/src/runtime.rs | 28 ---- fix/src/testing.rs | 5 + fix/wasm/addblob.wat | 21 ++- user/src/lib.rs | 6 +- 32 files changed, 1132 insertions(+), 338 deletions(-) create mode 100644 fix/fix-shell/bindings.h delete mode 100644 fix/fix-shell/fix.c delete mode 100644 fix/fix-shell/fix.h delete mode 100644 fix/fix-shell/handle.h create mode 100644 fix/handle/src/testing.rs create mode 100644 fix/runtime/Cargo.toml create mode 100644 fix/runtime/src/bottom.rs create mode 100644 fix/runtime/src/data.rs create mode 100644 fix/runtime/src/fixruntime.rs create mode 100644 fix/runtime/src/lib.rs create mode 100644 fix/runtime/src/runtime.rs create mode 100644 fix/runtime/src/storage.rs create mode 100644 fix/shell/Cargo.toml create mode 100644 fix/shell/build.rs create mode 100644 fix/shell/src/lib.rs create mode 100644 fix/shell/src/runtime.rs create mode 100644 fix/shell/src/shell.rs delete mode 100644 fix/src/runtime.rs create mode 100644 fix/src/testing.rs diff --git a/Cargo.lock b/Cargo.lock index a4918f3..c1e645f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -710,6 +710,8 @@ dependencies = [ "common", "derive_more", "fixhandle", + "fixruntime", + "fixshell", "futures", "include_directory", "kernel", @@ -731,6 +733,42 @@ dependencies = [ "macros", ] +[[package]] +name = "fixruntime" +version = "0.1.0" +dependencies = [ + "arca", + "arcane", + "async-lock", + "bitfield-struct 0.11.0", + "bytemuck", + "chrono", + "chumsky", + "common", + "derive_more", + "fixhandle", + "futures", + "kernel", + "log", + "macros", + "postcard", + "serde", + "serde_bytes", + "trait-variant", + "user", +] + +[[package]] +name = "fixshell" +version = "0.1.0" +dependencies = [ + "anyhow", + "arca", + "arcane", + "fixhandle", + "user", +] + [[package]] name = "foldhash" version = "0.1.5" @@ -943,6 +981,17 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "io-uring" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +dependencies = [ + "bitflags 2.9.2", + "cfg-if", + "libc", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" diff --git a/Cargo.toml b/Cargo.toml index f08277f..649f1cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = [ "common", "vmm", "kernel", "macros", "user", "arca" , "arcane", "fix"] -default-members = [ "common", "vmm", "macros", "arca"] +members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcade" , "ninep", "arcane", "vfs" , "memcached", "fix", "fix/runtime", "fix/handle", "fix/shell" ] +default-members = [ "vmm", "common" ] resolver = "2" diff --git a/fix/build.rs b/fix/build.rs index 966a1ff..13400a0 100644 --- a/fix/build.rs +++ b/fix/build.rs @@ -94,6 +94,9 @@ fn c2elf(c: &[u8], h: &[u8]) -> Result> { } } + let shell_top = env::var_os("CARGO_STATICLIB_FILE_FIXSHELL_fixshell").unwrap(); + src.push(PathBuf::from(shell_top)); + println!("{src:?}"); let mut o_file = INTERMEDIATEOUT.get().unwrap().clone(); @@ -116,11 +119,13 @@ fn c2elf(c: &[u8], h: &[u8]) -> Result> { "-frounding-math", // "-fsignaling-nans", "-ffreestanding", - // "-nostdlib", + "-nostdlib", "-nostartfiles", // "-mcmodel=large", "--verbose", "-Wl,-no-pie", + "-mavx2", + "-march=native" ]) .args(src) .status().map_err(|e| if let ErrorKind::NotFound = e.kind() {anyhow!("Compilation failed. Please make sure you have installed gcc-multilib if you are on Ubuntu.")} else {e.into()})?; @@ -192,21 +197,6 @@ fn main() -> Result<()> { let cwd = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let headers = vec![cwd.clone() + "/fix-shell/handle.h"]; - - let bindings = bindgen::Builder::default() - .headers(headers) - .clang_args(["-nostdinc"]) - .use_core() - .default_enum_style(bindgen::EnumVariation::ModuleConsts) - .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) - .generate() - .expect("Unable to generate bindings"); - - bindings - .write_to_file(Path::new(&out_dir).join("handle-bindings.rs")) - .expect("Couldn't write bindings!"); - println!("cargo::rerun-if-changed={cwd}/etc/memmap.ld"); println!("cargo::rustc-link-arg=-T{cwd}/etc/memmap.ld"); println!("cargo::rustc-link-arg=-no-pie"); diff --git a/fix/fix-shell/bindings.h b/fix/fix-shell/bindings.h new file mode 100644 index 0000000..d80c91c --- /dev/null +++ b/fix/fix-shell/bindings.h @@ -0,0 +1,14 @@ +/*Automatically generated by cbindgen*/ + +#include +#include + +__m256i fixpoint_create_blob_i64(uint64_t val); + +uint64_t fixpoint_attach_blob(void *addr, __m256i handle); + +uint64_t fixpoint_attach_tree(void *addr, __m256i handle); + +__m256i arca_blob_to_handle(int64_t h); + +int64_t handle_to_arca_blob(__m256i h); diff --git a/fix/fix-shell/fix.c b/fix/fix-shell/fix.c deleted file mode 100644 index c956b97..0000000 --- a/fix/fix-shell/fix.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "fix.h" -#include "arca/arca.h" -#include "arca/asm.h" -#include "arca/sys.h" - -arcad type_to_arcad(fix_type type) { - return arca_word_create((int64_t)(type)); -} - -static fix_type arcad_to_type(arcad type) { - uint64_t word; - arca_word_read(type, &word); - if (word == BlobObject) { - return BlobObject; - } - - if (word == TreeObject) { - return TreeObject; - } - - return Null; -} - -long check(char *msg, long ret) { - if (ret >= 0) { - return ret; - } - arca_panic(msg); -} - -fix_handle arcad_to_handle(arcad type, arcad data) { - fix_handle res = {.type = arcad_to_type(type), .d = data}; - return res; -} - -fix_handle arca_tuple_to_handle(arcad tuple) { - if (arca_type(tuple) != __TYPE_tuple) { - arca_panic("arca_tuple_to_handle: input is not a tuple"); - } - - size_t len; - check("arca_length", arca_length(tuple, &len)); - if (len != 2) { - arca_panic("arca_tuple_to_handle: input is not a 2-entry tuple"); - } - - return arcad_to_handle(arca_tuple_get(tuple, 0), arca_tuple_get(tuple, 1)); -} - -arcad_pair handle_to_arcad(fix_handle handle) { - arcad_pair res = {type_to_arcad(handle.type), handle.d}; - return res; -} - -arcad handle_to_arca_tuple(fix_handle handle) { - arcad tuple = arca_tuple_create(2); - arcad_pair p = handle_to_arcad(handle); - arca_tuple_set(tuple, 0, p.first); - arca_tuple_set(tuple, 1, p.second); - return tuple; -} diff --git a/fix/fix-shell/fix.h b/fix/fix-shell/fix.h deleted file mode 100644 index 47d0bde..0000000 --- a/fix/fix-shell/fix.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -#include "handle.h" - -typedef struct fix_handle { - fix_type type; - arcad d; -} fix_handle; - -typedef struct arcad_pair { - arcad first; - arcad second; -} arcad_pair; - -typedef struct w2c_fixpoint w2c_fixpoint; - -arcad type_to_arcad(fix_type type); -fix_handle arcad_to_handle(arcad type, arcad data); -fix_handle arca_tuple_to_handle(arcad tuple); -arcad_pair handle_to_arcad(fix_handle handle); -arcad handle_to_arca_tuple(fix_handle handle); - -long check(char *msg, long ret); diff --git a/fix/fix-shell/handle.h b/fix/fix-shell/handle.h deleted file mode 100644 index dbea17d..0000000 --- a/fix/fix-shell/handle.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -typedef enum fix_type { - BlobObject = 0, - TreeObject = 1, - Null = 2 -} fix_type; diff --git a/fix/fix-shell/main.c b/fix/fix-shell/main.c index 8ae567c..5b11e66 100644 --- a/fix/fix-shell/main.c +++ b/fix/fix-shell/main.c @@ -1,6 +1,6 @@ -#include "fix.h" #include "module.h" #include "wasm-rt.h" +#include "bindings.h" #include #include @@ -16,7 +16,7 @@ [[noreturn]] void fmain(void) { w2c_module module; wasm2c_module_instantiate(&module, (struct w2c_fixpoint *)&module); - wasm_rt_externref_t argument = arca_tuple_to_handle(arca_argument()); + wasm_rt_externref_t argument = (wasm_rt_externref_t)(arca_blob_to_handle(arca_argument())); wasm_rt_externref_t result = w2c_module_0x5Ffixpoint_apply(&module, argument); - arca_exit(handle_to_arca_tuple(result)); + arca_exit(handle_to_arca_blob((__m256i)(result))); } diff --git a/fix/fix-shell/runtime.c b/fix/fix-shell/runtime.c index b599353..3f5a948 100644 --- a/fix/fix-shell/runtime.c +++ b/fix/fix-shell/runtime.c @@ -1,5 +1,5 @@ +#include "bindings.h" #include "runtime.h" -#include "fix.h" #include #include @@ -7,159 +7,51 @@ extern wasm_rt_memory_t *WASM_MEMORIES[128]; extern size_t WASM_MEMORIES_N; +extern wasm_rt_externref_table_t *WASM_TABLES[128]; +extern size_t WASM_TABLES_N; static size_t bytes_to_wasm_pages(size_t bytes) { return (bytes + PAGE_SIZE - 1) / PAGE_SIZE; } -// Create an Arca page table of length `wasm_pages` of Wasm pages -static arcad create_wasm_pages(size_t wasm_pages, size_t page_size) { - size_t bytes = wasm_pages * PAGE_SIZE; - size_t pages = (bytes + page_size) / page_size; - // Creates a page table that covers the length of bytes - arcad table = arca_table_create(bytes); - // For every page in the table, create a rw 4k page - for (size_t i = 0; i < pages; i++) { - struct arca_entry entry; - entry.mode = __MODE_read_write; - // Create a rw 4k page - entry.data = check("arca_page_create", arca_page_create(page_size)); - // Map the page as rw in the table - arca_table_map(table, (void *)(i * page_size), &entry); - } - return table; -} - -static struct arca_entry map_table(void *addr, arcad table, bool write) { - struct arca_entry entry; - entry.mode = write ? __MODE_read_write : __MODE_read_only; - entry.data = table; - check("arca_mmap", arca_mmap(addr, &entry)); - return entry; -} - -static void check_cond(bool predicate) { - if (!predicate) { - arca_panic("Assertion failed"); - } -} - -wasm_rt_externref_t w2c_fixpoint_get_tree_entry(struct w2c_fixpoint *instance, - wasm_rt_externref_t handle, - uint32_t index) { - // Check whether `handle` refers to a TreeObject - if (handle.type != TreeObject) { - arca_log("get_tree_entry: handle does not refer to a TreeObject"); - arca_panic("get_tree_entry: handle does not refer to a TreeObject"); - } - - arcad type = check("arca_tuple_get", arca_tuple_get(handle.d, index * 2)); - arcad data = check("arca_tuple_get", arca_tuple_get(handle.d, index * 2 + 1)); - - return arcad_to_handle(type, data); -} - wasm_rt_externref_t w2c_fixpoint_create_blob_i64(struct w2c_fixpoint *instance, uint64_t val) { - arcad data = check("arca_word_create", arca_word_create(val)); - arcad type = type_to_arcad(BlobObject); - return arcad_to_handle(type, data); + return (wasm_rt_externref_t)fixpoint_create_blob_i64(val); } -void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t n, +void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t index, wasm_rt_externref_t handle) { - if (handle.type != BlobObject) { - arca_log("attach_blob: handle does not refer to a BlobObject"); - arca_panic("attach_blob: handle does not refer to a BlobObject"); + if (index >= WASM_MEMORIES_N) { + arca_panic("memory index oob"); } - - arcad d = handle.d; - - // check_cond(n < WASM_MEMORIES_N); - wasm_rt_memory_t *memory = WASM_MEMORIES[n]; + wasm_rt_memory_t *memory = WASM_MEMORIES[index]; // `addr` is the beginning address of this wasm memory in the address space - void *addr = (void *)((size_t)n << 32); + void *addr = (void *)(memory->data); + uint64_t nbytes = fixpoint_attach_blob(addr, (__m256i)handle); - // Setup size fields of the wasm memory - size_t nbytes; - check("arca_length", arca_length(d, &nbytes)); size_t npages = bytes_to_wasm_pages(nbytes); memory->size = nbytes; memory->pages = npages; + return; +} - arcad pages; - struct arca_entry entry; - switch (arca_type(handle.d)) { - case __TYPE_word: { - check_cond(npages == 1); - // Create rw page table and map at `addr` - pages = create_wasm_pages(npages, 4096); - entry = map_table(addr, pages, true); - check_cond(entry.mode == __MODE_none); - // Read the blob content to `addr` - arca_word_read(handle.d, addr); - - // arca_mmap returns the old entry in the page table at `addr` - arca_mmap(addr, &entry); - check_cond(entry.mode == __MODE_read_write); - // set the entry mode to read only - entry.mode = __MODE_read_only; - // map the entry back at the same location; now `addr` is read only and - // contains the word - arca_mmap(addr, &entry); - if (entry.mode != __MODE_none) { - arca_drop(entry.data); - } - return; - } - - case __TYPE_blob: { - pages = create_wasm_pages(npages, 4096); - entry = map_table(addr, pages, true); - arca_blob_read(handle.d, 0, addr, nbytes); - arca_mmap(addr, &entry); - entry.mode = __MODE_read_only; - arca_mmap(addr, &entry); - if (entry.mode != __MODE_none) { - arca_drop(entry.data); - } - return; - } - - case __TYPE_page: { - // Check the size of the page - size_t page_size; - check("arca_length", arca_length(d, &page_size)); - pages = create_wasm_pages(npages, page_size); - - // Map the page for Blob to the created table - entry.mode = __MODE_read_only; - entry.data = d; - arca_table_set(pages, 0, &entry); - - // Map the table at `addr` - entry = map_table(addr, pages, false); - - // Drop the old entry at `addr` if any - if (entry.mode != __MODE_none) { - arca_drop(entry.data); - } - return; - } - - case __TYPE_table: { - entry = map_table(addr, handle.d, false); - - // Drop the old entry at `addr` if any - if (entry.mode != __MODE_none) { - arca_drop(entry.data); - } - return; +void w2c_fixpoint_attach_tree(struct w2c_fixpoint *instance, uint32_t index, + wasm_rt_externref_t handle) +{ + if (index >= WASM_TABLES_N) { + arca_panic("table index oob"); } + wasm_rt_externref_table_t *table = WASM_TABLES[index]; + // `addr` is the beginning address of this wasm memory in the address space + void *addr = (void *)(table->data); + uint64_t nelems = fixpoint_attach_tree(addr, (__m256i)handle); + table->size = nelems; + return; +} - default: - check_cond(false); +long check(char *msg, long ret) { + if (ret >= 0) { + return ret; } - - return; + arca_panic(msg); } diff --git a/fix/fix-shell/runtime.h b/fix/fix-shell/runtime.h index c491b4c..4284fa9 100644 --- a/fix/fix-shell/runtime.h +++ b/fix/fix-shell/runtime.h @@ -3,13 +3,14 @@ #include "wasm-rt.h" #include -// Get `index`th entry from a Tree -wasm_rt_externref_t w2c_fixpoint_get_tree_entry(struct w2c_fixpoint *instance, - wasm_rt_externref_t handle, - uint32_t index); +typedef struct w2c_fixpoint w2c_fixpoint; + // Attach the Blob referred by `handle` to `index`th wasm memory void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t index, wasm_rt_externref_t handle); +// Attach the Tree referred by `handle` to `index`th wasm table +void w2c_fixpoint_attach_tree(struct w2c_fixpoint *instance, uint32_t index, + wasm_rt_externref_t handle); // Create a Blob with content `val` wasm_rt_externref_t w2c_fixpoint_create_blob_i64(struct w2c_fixpoint *instance, uint64_t val); diff --git a/fix/fix-shell/wasm-rt-impl.c b/fix/fix-shell/wasm-rt-impl.c index cc5cb93..6f1d232 100644 --- a/fix/fix-shell/wasm-rt-impl.c +++ b/fix/fix-shell/wasm-rt-impl.c @@ -25,6 +25,8 @@ wasm_rt_memory_t *WASM_MEMORIES[128]; size_t WASM_MEMORIES_N = 0; +wasm_rt_externref_table_t *WASM_TABLES[128]; +size_t WASM_TABLES_N = 0; long check(char *msg, long ret); [[noreturn]] void trap(const char *msg); @@ -139,7 +141,67 @@ void wasm_rt_free_memory(wasm_rt_memory_t *memory) { return; } } DEFINE_TABLE_OPS(funcref) -DEFINE_TABLE_OPS(externref) + +void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t *table, + uint32_t elements, + uint32_t max_elements) { + size_t n = WASM_TABLES_N++; + assert(n < 128); + WASM_TABLES[n] = table; + + assert(max_elements * sizeof(wasm_rt_externref_t) <= (1ull << 32)); + + // tables are after the memories in the address space + table->data = (void *)((128 + n) << 32); + table->max_size = max_elements; + table->size = elements; + + uint64_t byte_length = elements * sizeof(wasm_rt_externref_t); + uint64_t num_pages = (byte_length + (1ull << 12) - 1) / (1ull << 12); + + for (uint64_t i = 0; i < num_pages; i++) { + arcad page = check("arca_page_create", arca_page_create(1 << 12)); + check("arca_mmap", arca_mmap((uint8_t *)(table->data) + i * 4096, + &(struct arca_entry){ + .mode = __MODE_read_write, + .data = page, + })); + } + return; +} + +void wasm_rt_free_externref_table(wasm_rt_externref_table_t *table) { return; } + +uint32_t wasm_rt_grow_externref_table(wasm_rt_externref_table_t *table, + uint32_t delta, + wasm_rt_externref_t init) { + uint64_t old_elements = table->size; + uint64_t new_elements = old_elements + delta; + if (new_elements == 0) { + return 0; + } + if (new_elements < old_elements || new_elements > table->max_size) { + return (uint32_t)-1; + } + uint64_t old_size = old_elements * sizeof(wasm_rt_externref_t); + uint64_t new_size = new_elements * sizeof(wasm_rt_externref_t); + + uint64_t old_num_pages = (old_size + (1ull << 12) - 1) / (1ull << 12); + uint64_t new_num_pages = (new_size + (1ull << 12) - 1) / (1ull << 12); + + for (uint64_t i = 0; i < new_num_pages - old_num_pages; i++) { + arcad page = check("arca_page_create", arca_page_create(1 << 12)); + check("arca_mmap", + arca_mmap((uint8_t *)(table->data) + old_num_pages * 4096 + i * 4096, + &(struct arca_entry){ + .mode = __MODE_read_write, + .data = page, + })); + } + + table->size = new_elements; + return old_elements; +} const char *wasm_rt_strerror(wasm_rt_trap_t trap) { switch (trap) { diff --git a/fix/fix-shell/wasm-rt.h b/fix/fix-shell/wasm-rt.h index 6513f0a..267bd5d 100644 --- a/fix/fix-shell/wasm-rt.h +++ b/fix/fix-shell/wasm-rt.h @@ -22,8 +22,6 @@ #include #include -#include "fix.h" - #define PAGE_SIZE 65536 [[noreturn]] void abort(void); @@ -131,11 +129,11 @@ typedef struct { static const wasm_rt_funcref_t wasm_rt_funcref_null_value; /** The type of an external reference (opaque to WebAssembly). */ -typedef struct fix_handle wasm_rt_externref_t; +typedef unsigned char __attribute__((vector_size(32))) u8x32; +typedef u8x32 wasm_rt_externref_t; /** Default (null) value of an externref */ -static const wasm_rt_externref_t wasm_rt_externref_null_value = {.d = -1, - .type = Null}; +static const wasm_rt_externref_t wasm_rt_externref_null_value = {0}; /** A Memory object. */ typedef struct { diff --git a/fix/handle/src/lib.rs b/fix/handle/src/lib.rs index 9fd3974..fd8c22e 100644 --- a/fix/handle/src/lib.rs +++ b/fix/handle/src/lib.rs @@ -1,6 +1,11 @@ #![no_std] #![feature(portable_simd)] -#![feature(test)] +#![feature(custom_test_frameworks)] #![allow(dead_code)] +#![cfg_attr(feature = "testing-mode", test_runner(crate::testing::test_runner))] +#![cfg_attr(feature = "testing-mode", reexport_test_harness_main = "test_main")] + +#[cfg(feature = "testing-mode")] +mod testing; pub mod rawhandle; diff --git a/fix/handle/src/rawhandle.rs b/fix/handle/src/rawhandle.rs index 7e98ff7..6906730 100644 --- a/fix/handle/src/rawhandle.rs +++ b/fix/handle/src/rawhandle.rs @@ -232,16 +232,11 @@ pub enum Value { Thunk(Thunk), } -#[cfg(test)] +#[cfg(feature = "testing-mode")] mod tests { - use core::simd::u16x16; - use super::*; - extern crate std; - extern crate test; - - #[test] + #[test_case] fn test_tag_gits() { assert_eq!(Handle::TAGBITS, 241); assert_eq!(BlobName::TAGBITS, 241); @@ -250,7 +245,7 @@ mod tests { assert_eq!(Thunk::TAGBITS, 245); } - #[test] + #[test_case] fn test_tag_masks() { assert_eq!(Handle::TAGMASK.as_array()[30], 0b00000001); assert_eq!(Handle::TAGMASK.as_array()[31], 0b00000000); @@ -265,7 +260,7 @@ mod tests { assert_eq!(Thunk::TAGMASK.as_array()[31], 0b00000000); } - #[test] + #[test_case] fn test_pack() { let h: Handle = PhysicalHandle::new(42, 10086).into(); let res = h.pack(); @@ -278,7 +273,7 @@ mod tests { assert_eq!(field[15], 0b0000000000000011); } - #[test] + #[test_case] fn test_round_trip() { let h: Handle = PhysicalHandle::new(42, 10086).into(); let res = Handle::unpack(h.pack()) diff --git a/fix/handle/src/testing.rs b/fix/handle/src/testing.rs new file mode 100644 index 0000000..26aecae --- /dev/null +++ b/fix/handle/src/testing.rs @@ -0,0 +1,5 @@ +pub fn test_runner(tests: &[&dyn Fn()]) { + for test in tests { + test(); + } +} diff --git a/fix/runtime/Cargo.toml b/fix/runtime/Cargo.toml new file mode 100644 index 0000000..86cedb6 --- /dev/null +++ b/fix/runtime/Cargo.toml @@ -0,0 +1,38 @@ +cargo-features = ["per-package-target"] + +[package] +name = "fixruntime" +version = "0.1.0" +edition = "2024" +forced-target = "x86_64-unknown-none" + +[features] +klog-trace = ["kernel/klog-trace"] +klog-debug = ["kernel/klog-debug"] +klog-info = ["kernel/klog-info"] +klog-warn = ["kernel/klog-warn"] +klog-error = ["kernel/klog-error"] +klog-off = ["kernel/klog-off"] +debugcon = ["kernel/debugcon"] +testing-mode = [] + +[dependencies] +arca = { path = "../../arca", features = ["serde"] } +kernel = { path = "../../kernel" } +macros = { path = "../../macros" } +common = { path = "../../common", default-features = false } +fixhandle = { path = "../handle" } +log = "0.4.27" +serde = { version = "1.0.219", default-features = false, features = ["alloc", "derive"] } +chrono = { version = "0.4.41", default-features = false, features = ["alloc", "serde"] } +serde_bytes = { version = "0.11.17", default-features = false, features = ["alloc"] } +arcane = { version = "0.1.0", path = "../../arcane" } +postcard = { version = "1.1.3", features = ["alloc"] } +derive_more = { version = "2.0.1", default-features = false, features = ["full"] } +trait-variant = "0.1.2" +futures = { version = "0.3.31", default-features = false, features = ["alloc", "async-await"] } +chumsky = { version = "0.10.1", default-features = false } +user = { path = "../../user", artifact = "bin", target = "x86_64-unknown-none" } +async-lock = { version = "3.4.1", default-features = false } +bytemuck = "1.24.0" +bitfield-struct = "0.11.0" diff --git a/fix/runtime/src/bottom.rs b/fix/runtime/src/bottom.rs new file mode 100644 index 0000000..f9149d4 --- /dev/null +++ b/fix/runtime/src/bottom.rs @@ -0,0 +1,174 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] + +use crate::{ + data::{BlobData, RawData, TreeData}, + fixruntime::FixRuntime, + runtime::{DeterministicEquivRuntime, Executor}, +}; + +use core::simd::u8x32; + +use arca::Runtime; +use fixhandle::rawhandle::{BitPack, FixHandle}; +use kernel::prelude::vec; +use kernel::{ + prelude::vec::Vec, + types::{Blob as ArcaBlob, Function, Tuple, Value}, +}; + +#[derive(Debug)] +pub enum Error { + FixRuntimeError, +} + +fn pack_handle(handle: &FixHandle) -> ArcaBlob { + let raw = handle.pack(); + Runtime::create_blob(raw.as_array()) +} + +fn unpack_handle(blob: &ArcaBlob) -> FixHandle { + let mut buf = [0u8; 32]; + if Runtime::read_blob(blob, 0, &mut buf) != 32 { + panic!("Failed to parse Arca Blob to Fix Handle") + } + FixHandle::unpack(u8x32::from_array(buf)) +} + +pub struct FixShellBottom<'a> { + parent: &'a mut FixRuntime<'a>, +} + +impl<'a> DeterministicEquivRuntime for FixShellBottom<'a> { + type BlobData = BlobData; + type TreeData = TreeData; + type Handle = ArcaBlob; + type Error = Error; + + fn create_blob_i64(&mut self, data: u64) -> Self::Handle { + pack_handle(&self.parent.create_blob_i64(data)) + } + + fn create_blob(&mut self, data: Self::BlobData) -> Self::Handle { + pack_handle(&self.parent.create_blob(data)) + } + + fn create_tree(&mut self, data: Self::TreeData) -> Self::Handle { + pack_handle(&self.parent.create_tree(data)) + } + + fn get_blob(&self, handle: &Self::Handle) -> Result { + self.parent + .get_blob(&unpack_handle(handle)) + .map_err(|_| Error::FixRuntimeError) + } + + fn get_tree(&self, handle: &Self::Handle) -> Result { + self.parent + .get_tree(&unpack_handle(handle)) + .map_err(|_| Error::FixRuntimeError) + } + + fn is_blob(handle: &Self::Handle) -> bool { + FixRuntime::is_blob(&unpack_handle(handle)) + } + + fn is_tree(handle: &Self::Handle) -> bool { + FixRuntime::is_tree(&unpack_handle(handle)) + } +} + +impl<'a> FixShellBottom<'a> { + fn run(&mut self, mut f: Function) -> FixHandle { + loop { + let result = f.force(); + if let Value::Blob(b) = result { + return unpack_handle(&b); + } else { + let Value::Function(g) = result else { panic!() }; + let data = g.into_inner().read(); + let Value::Tuple(mut data) = data else { + unreachable!() + }; + let t: ArcaBlob = data.take(0).try_into().unwrap(); + assert_eq!(&*t, b"Symbolic"); + let effect: ArcaBlob = data.take(1).try_into().unwrap(); + let args: Tuple = data.take(2).try_into().unwrap(); + let mut args: Vec = args.into_iter().collect(); + let Some(Value::Function(k)) = args.pop() else { + panic!() + }; + + f = match &*effect { + b"create_blob_i64" => { + let Some(Value::Word(w)) = args.pop() else { + panic!() + }; + k.apply(self.create_blob_i64(w.read())) + } + b"create_blob" => { + let Some(Value::Table(t)) = args.pop() else { + panic!() + }; + let Some(Value::Word(w)) = args.pop() else { + panic!() + }; + k.apply(self.create_blob(BlobData::new(t, w.read() as usize))) + } + b"create_tree" => { + let Some(Value::Table(t)) = args.pop() else { + panic!() + }; + let Some(Value::Word(w)) = args.pop() else { + panic!() + }; + k.apply(self.create_tree(TreeData::new(t, w.read() as usize))) + } + b"get_blob" => { + let Some(Value::Blob(b)) = args.pop() else { + panic!() + }; + let t: RawData = self.get_blob(&b).expect("").into(); + k.apply(Value::Table(t.into())) + } + b"get_tree" => { + let Some(Value::Blob(b)) = args.pop() else { + panic!() + }; + let t: RawData = self.get_tree(&b).expect("").into(); + k.apply(Value::Table(t.into())) + } + b"is_blob" => { + let Some(Value::Blob(b)) = args.pop() else { + panic!() + }; + k.apply(Runtime::create_word(Self::is_blob(&b) as u64)) + } + b"is_tree" => { + let Some(Value::Blob(b)) = args.pop() else { + panic!() + }; + k.apply(Runtime::create_word(Self::is_tree(&b) as u64)) + } + _ => unreachable!(), + }; + } + } + } +} + +impl<'a> Executor for FixShellBottom<'a> { + fn execute(&mut self, combination: &FixHandle) -> FixHandle { + let tree = self.parent.get_tree(combination).unwrap(); + let function_handle = tree.get(1); + let elf = self.parent.get_blob(&function_handle).unwrap(); + + let mut buffer = vec![0u8; elf.len()]; + elf.get(&mut buffer); + + let f = common::elfloader::load_elf(&buffer).expect("Failed to load elf"); + let f = Runtime::apply_function(f, Value::from(pack_handle(combination))); + + self.run(f) + } +} diff --git a/fix/runtime/src/data.rs b/fix/runtime/src/data.rs new file mode 100644 index 0000000..122a093 --- /dev/null +++ b/fix/runtime/src/data.rs @@ -0,0 +1,157 @@ +use arca::Runtime as _; +use core::cmp; +use core::panic; +use core::simd::u8x32; +use fixhandle::rawhandle::BitPack; +use fixhandle::rawhandle::FixHandle; +use kernel::prelude::*; +use kernel::types::Runtime; +use kernel::types::Table; + +const MAXSIZE: usize = 1 << 32; + +#[derive(Debug, Clone)] +pub struct RawData { + data: Table, + length: usize, +} + +impl RawData { + fn new(length: usize) -> Self { + if length > MAXSIZE { + panic!("Data larger than maximum size") + } + Self { + data: Table::new(MAXSIZE), + length, + } + } + + fn create(data: &[u8]) -> Self { + let mut inner = RawData::new(data.len()); + let pagesize = inner.data.len() / 512; + for i in 0..(data.len() + 1) / pagesize { + let mut page = Runtime::create_page(pagesize); + Runtime::write_page(&mut page, 0, &data[i * pagesize..]); + Runtime::set_table(&mut inner.data, i, arca::Entry::ROPage(page)) + .expect("Unable to set entry"); + } + inner + } + + fn get(&self, start: usize, buf: &mut [u8]) { + let pagesize = self.data.len() / 512; + let mut curr_start = start; + let mut index = 0; + while curr_start - start < buf.len() { + // Advance to the end of current page + let mut curr_end = (curr_start / pagesize + 1) * pagesize; + curr_end = cmp::min(curr_end, start + buf.len()); + match Runtime::get_table(&self.data, index) + .expect("Page to get is out of the MAXSIZE range") + { + arca::Entry::Null(_) => (), + arca::Entry::ROPage(page) | arca::Entry::RWPage(page) => { + Runtime::read_page( + &page, + curr_start % pagesize, + &mut buf[curr_start..curr_end], + ); + } + arca::Entry::ROTable(_) => todo!(), + arca::Entry::RWTable(_) => todo!(), + } + + index += 1; + curr_start = curr_end; + } + } +} + +impl From for Table { + fn from(val: RawData) -> Self { + val.data + } +} + +#[derive(Debug, Clone)] +pub struct BlobData { + inner: RawData, +} + +impl BlobData { + pub fn new(data: Table, length: usize) -> Self { + let inner = RawData { data, length }; + Self { inner } + } + + pub fn create(data: &[u8]) -> Self { + let inner = RawData::create(data); + Self { inner } + } + + pub fn len(&self) -> usize { + self.inner.length + } + + pub fn get(&self, buf: &mut [u8]) { + self.inner.get(0, buf) + } +} + +impl From for RawData { + fn from(val: BlobData) -> Self { + val.inner + } +} + +impl From for BlobData { + fn from(value: RawData) -> Self { + Self { inner: value } + } +} + +#[derive(Debug, Clone)] +pub struct TreeData { + inner: RawData, +} + +impl TreeData { + pub fn new(data: Table, length: usize) -> Self { + let inner = RawData { data, length }; + Self { inner } + } + + pub fn create(data: &[FixHandle]) -> Self { + let mut buffer = vec![0u8; data.len() * 32]; + for (idx, i) in data.iter().enumerate() { + let raw = i.pack(); + buffer.as_mut_slice()[idx * 32..].copy_from_slice(raw.as_array()); + } + + let inner = RawData::create(&buffer); + Self { inner } + } + + pub fn len(&self) -> usize { + self.inner.length / 32 + } + + pub fn get(&self, idx: usize) -> FixHandle { + let mut buffer = [0u8; 32]; + self.inner.get(idx * 32, &mut buffer); + FixHandle::unpack(u8x32::from_array(buffer)) + } +} + +impl From for RawData { + fn from(val: TreeData) -> Self { + val.inner + } +} + +impl From for TreeData { + fn from(value: RawData) -> Self { + Self { inner: value } + } +} diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs new file mode 100644 index 0000000..b100d22 --- /dev/null +++ b/fix/runtime/src/fixruntime.rs @@ -0,0 +1,98 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] + +use crate::{ + data::{BlobData, TreeData}, + runtime::DeterministicEquivRuntime, + storage::{ObjectStore, Storage}, +}; +use bytemuck::bytes_of; +use derive_more::TryUnwrapError; +use fixhandle::rawhandle::{FixHandle, Object}; + +#[derive(Debug)] +pub enum Error { + OOB, + TypeMismatch, +} + +impl From> for Error { + fn from(_value: TryUnwrapError) -> Self { + Error::TypeMismatch + } +} + +#[derive(Debug)] +pub struct FixRuntime<'a> { + store: &'a mut ObjectStore, +} + +impl<'a> FixRuntime<'a> { + fn new(store: &'a mut ObjectStore) -> Self { + Self { store } + } +} + +impl<'a> DeterministicEquivRuntime for FixRuntime<'a> { + type BlobData = BlobData; + type TreeData = TreeData; + type Handle = FixHandle; + type Error = Error; + + fn create_blob_i64(&mut self, data: u64) -> Self::Handle { + let buf = bytes_of(&data); + Object::from(self.store.create_blob(BlobData::create(buf))).into() + } + + fn create_blob(&mut self, data: Self::BlobData) -> Self::Handle { + Object::from(self.store.create_blob(data)).into() + } + + fn create_tree(&mut self, data: Self::TreeData) -> Self::Handle { + Object::from(self.store.create_tree(data)).into() + } + + fn get_blob(&self, handle: &Self::Handle) -> Result { + let b = handle + .try_unwrap_object_ref() + .map_err(Error::from)? + .try_unwrap_blob_name_ref() + .map_err(|_| Error::TypeMismatch)?; + Ok(self.store.get_blob(b)) + } + + fn get_tree(&self, handle: &Self::Handle) -> Result { + let t = handle + .try_unwrap_object_ref() + .map_err(Error::from)? + .try_unwrap_tree_name_ref() + .map_err(Error::from)?; + Ok(self.store.get_tree(t)) + } + + fn is_blob(handle: &Self::Handle) -> bool { + handle + .try_unwrap_object_ref() + .map_err(Error::from) + .and_then(|h| h.try_unwrap_blob_name_ref().map_err(Error::from)) + .is_ok() + || handle + .try_unwrap_ref_ref() + .map_err(Error::from) + .and_then(|h| h.try_unwrap_blob_name_ref().map_err(Error::from)) + .is_ok() + } + + fn is_tree(handle: &Self::Handle) -> bool { + handle + .try_unwrap_object_ref() + .map_err(Error::from) + .and_then(|h| h.try_unwrap_tree_name_ref().map_err(Error::from)) + .is_ok() + || handle + .try_unwrap_ref_ref() + .map_err(Error::from) + .and_then(|h| h.try_unwrap_tree_name_ref().map_err(Error::from)) + .is_ok() + } +} diff --git a/fix/runtime/src/lib.rs b/fix/runtime/src/lib.rs new file mode 100644 index 0000000..46c768b --- /dev/null +++ b/fix/runtime/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] +#![feature(portable_simd)] +#![allow(dead_code)] + +mod bottom; +mod data; +pub mod fixruntime; +pub mod runtime; +mod storage; diff --git a/fix/runtime/src/runtime.rs b/fix/runtime/src/runtime.rs new file mode 100644 index 0000000..8313a1c --- /dev/null +++ b/fix/runtime/src/runtime.rs @@ -0,0 +1,29 @@ +use core::clone::Clone; +use core::result::Result; + +use fixhandle::rawhandle::FixHandle; + +pub trait DeterministicEquivRuntime { + type BlobData: Clone + core::fmt::Debug; + type TreeData: Clone + core::fmt::Debug; + type Handle: Clone + core::fmt::Debug; + type Error; + + fn create_blob_i64(&mut self, data: u64) -> Self::Handle; + fn create_blob(&mut self, data: Self::BlobData) -> Self::Handle; + fn create_tree(&mut self, data: Self::TreeData) -> Self::Handle; + + fn get_blob(&self, handle: &Self::Handle) -> Result; + fn get_tree(&self, handle: &Self::Handle) -> Result; + + fn is_blob(handle: &Self::Handle) -> bool; + fn is_tree(handle: &Self::Handle) -> bool; +} + +pub trait ExecutionRuntime: DeterministicEquivRuntime { + fn request_execution(&mut self, combination: &Self::Handle) -> Result<(), Self::Error>; +} + +pub trait Executor { + fn execute(&mut self, combination: &FixHandle) -> FixHandle; +} diff --git a/fix/runtime/src/storage.rs b/fix/runtime/src/storage.rs new file mode 100644 index 0000000..13e5d3f --- /dev/null +++ b/fix/runtime/src/storage.rs @@ -0,0 +1,96 @@ +use crate::data::{BlobData, RawData, TreeData}; +use fixhandle::rawhandle::{BlobName, Handle, PhysicalHandle, TreeName}; +use kernel::prelude::*; + +#[derive(Debug)] +struct RefCnt { + inner: T, + count: usize, +} + +impl RefCnt { + fn new(inner: T) -> Self { + Self { inner, count: 0 } + } +} + +#[derive(Debug)] +struct RawObjectStore { + table: Vec>, +} + +impl Default for RawObjectStore { + fn default() -> Self { + Self { table: vec![] } + } +} + +impl RawObjectStore { + fn new() -> Self { + Self::default() + } + + fn create(&mut self, data: Data) -> usize { + let idx = self.table.len(); + self.table.push(RefCnt::new(data)); + idx + } + + fn get(&self, idx: usize) -> Data { + self.table[idx].inner.clone() + } +} + +pub trait Storage { + fn create_blob(&mut self, data: BlobData) -> BlobName; + fn create_tree(&mut self, data: TreeData) -> TreeName; + fn get_blob(&self, handle: &BlobName) -> BlobData; + fn get_tree(&self, handle: &TreeName) -> TreeData; +} + +#[derive(Default, Debug)] +pub struct ObjectStore { + store: RawObjectStore, +} + +impl ObjectStore { + fn new() -> Self { + Self::default() + } +} + +impl Storage for ObjectStore { + fn create_blob(&mut self, data: BlobData) -> BlobName { + let len = data.len(); + let local_id = self.store.create(data.into()); + BlobName::Blob(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))) + } + + fn create_tree(&mut self, data: TreeData) -> TreeName { + let len = data.len(); + let local_id = self.store.create(data.into()); + TreeName::NotTag(Handle::PhysicalHandle(PhysicalHandle::new(local_id, len))) + } + + fn get_blob(&self, handle: &BlobName) -> BlobData { + match handle { + BlobName::Blob(h) => match h { + Handle::VirtualHandle(_) => todo!(), + Handle::PhysicalHandle(physical_handle) => { + self.store.get(physical_handle.local_id()).into() + } + }, + } + } + + fn get_tree(&self, handle: &TreeName) -> TreeData { + match handle { + TreeName::NotTag(t) | TreeName::Tag(t) => match t { + Handle::VirtualHandle(_) => todo!(), + Handle::PhysicalHandle(physical_handle) => { + self.store.get(physical_handle.local_id()).into() + } + }, + } + } +} diff --git a/fix/shell/Cargo.toml b/fix/shell/Cargo.toml new file mode 100644 index 0000000..ebdbfed --- /dev/null +++ b/fix/shell/Cargo.toml @@ -0,0 +1,20 @@ +cargo-features = ["per-package-target"] + +[package] +name = "fixshell" +version = "0.1.0" +edition = "2024" +forced-target = "x86_64-unknown-none" + +[lib] +name = "fixshell" +crate-type = ["staticlib"] + +[dependencies] +arca = { path = "../../arca" } +user = { path = "../../user" } +arcane = { path = "../../arcane/"} +fixhandle = { path = "../handle", default-features = false} + +[build-dependencies] +anyhow = "1.0.100" diff --git a/fix/shell/build.rs b/fix/shell/build.rs new file mode 100644 index 0000000..a2afb2a --- /dev/null +++ b/fix/shell/build.rs @@ -0,0 +1,6 @@ +use anyhow::Result; + +fn main() -> Result<()> { + println!("cargo::rustc-link-arg=-no-pie"); + Ok(()) +} diff --git a/fix/shell/src/lib.rs b/fix/shell/src/lib.rs new file mode 100644 index 0000000..42ec870 --- /dev/null +++ b/fix/shell/src/lib.rs @@ -0,0 +1,7 @@ +#![no_std] +#![allow(unused)] +#![feature(portable_simd)] +#![feature(simd_ffi)] + +mod runtime; +pub mod shell; diff --git a/fix/shell/src/runtime.rs b/fix/shell/src/runtime.rs new file mode 100644 index 0000000..7420c13 --- /dev/null +++ b/fix/shell/src/runtime.rs @@ -0,0 +1,22 @@ +use core::clone::Clone; +use core::result::Result; + +use fixhandle::rawhandle::FixHandle; + +pub trait DeterministicEquivRuntime { + type BlobData: Clone + core::fmt::Debug; + type TreeData: Clone + core::fmt::Debug; + type Handle: Clone + core::fmt::Debug; + type Error; + + fn create_blob_i64(data: u64) -> Self::Handle; + fn create_blob(data: Self::BlobData) -> Self::Handle; + fn create_tree(data: Self::TreeData) -> Self::Handle; + + fn get_blob(handle: Self::Handle) -> Result; + fn get_tree(handle: Self::Handle) -> Result; + + fn is_blob(handle: Self::Handle) -> bool; + fn is_tree(handle: Self::Handle) -> bool; + fn len(handle: Self::Handle) -> usize; +} diff --git a/fix/shell/src/shell.rs b/fix/shell/src/shell.rs new file mode 100644 index 0000000..fd0cb24 --- /dev/null +++ b/fix/shell/src/shell.rs @@ -0,0 +1,244 @@ +use crate::runtime::DeterministicEquivRuntime; +use arca::Runtime as _; +use arca::{Blob, Function, Table}; +use arcane::{ + __MODE_read_only, __NR_length, __TYPE_table, arca_argument, arca_blob_create, arca_blob_read, + arca_entry, arca_mmap, arcad, +}; +use core::arch::x86_64::__m256i; +use core::ffi::c_void; +use core::simd::u8x32; +use fixhandle::rawhandle::{BitPack, FixHandle, Handle}; +use user::ArcaError; +use user::Ref; +use user::Runtime; +use user::error::log as arca_log; + +// FixShell top-half that only handles physical handles +#[derive(Debug, Default)] +struct FixShellPhysical; +// FixShell top-half + +#[derive(Debug, Default)] +struct FixShell; + +impl DeterministicEquivRuntime for FixShellPhysical { + type BlobData = Table; + type TreeData = Table; + type Handle = __m256i; + type Error = ArcaError; + + fn create_blob_i64(data: u64) -> Self::Handle { + let result: Blob = Function::symbolic("create_blob_i64") + .apply(data) + .call_with_current_continuation() + .try_into() + .expect("create_blob_i64 failed"); + let mut buf = [0u8; 32]; + Runtime::read_blob(&result, 0, &mut buf); + __m256i::from(u8x32::from_array(buf)) + } + + fn create_blob(data: Self::BlobData) -> Self::Handle { + let result: Blob = Function::symbolic("create_blob") + .apply(data) + .call_with_current_continuation() + .try_into() + .expect("create_blob failed"); + let mut buf = [0u8; 32]; + Runtime::read_blob(&result, 0, &mut buf); + __m256i::from(u8x32::from_array(buf)) + } + + fn create_tree(data: Self::TreeData) -> Self::Handle { + let result: Blob = Function::symbolic("create_tree") + .apply(data) + .call_with_current_continuation() + .try_into() + .expect("create_tree failed"); + let mut buf = [0u8; 32]; + Runtime::read_blob(&result, 0, &mut buf); + __m256i::from(u8x32::from_array(buf)) + } + + fn get_blob(handle: Self::Handle) -> Result { + let handle: u8x32 = handle.into(); + let result: Table = Function::symbolic("get_blob") + .apply(Runtime::create_blob(handle.as_array())) + .call_with_current_continuation() + .try_into() + .map_err(|_| ArcaError::BadType)?; + Ok(result) + } + + fn get_tree(handle: Self::Handle) -> Result { + let handle: u8x32 = handle.into(); + let result: Table = Function::symbolic("get_tree") + .apply(Runtime::create_blob(handle.as_array())) + .call_with_current_continuation() + .try_into() + .map_err(|_| ArcaError::BadType)?; + Ok(result) + } + + fn is_blob(handle: Self::Handle) -> bool { + let handle = FixHandle::unpack(handle.into()); + handle + .try_unwrap_object_ref() + .map_err(|_| ArcaError::BadType) + .and_then(|h| h.try_unwrap_blob_name_ref().map_err(|_| ArcaError::BadType)) + .is_ok() + || handle + .try_unwrap_ref_ref() + .map_err(|_| ArcaError::BadType) + .and_then(|h| h.try_unwrap_blob_name_ref().map_err(|_| ArcaError::BadType)) + .is_ok() + } + + fn is_tree(handle: Self::Handle) -> bool { + let handle = FixHandle::unpack(handle.into()); + handle + .try_unwrap_object_ref() + .map_err(|_| ArcaError::BadType) + .and_then(|h| h.try_unwrap_tree_name_ref().map_err(|_| ArcaError::BadType)) + .is_ok() + || handle + .try_unwrap_ref_ref() + .map_err(|_| ArcaError::BadType) + .and_then(|h| h.try_unwrap_tree_name_ref().map_err(|_| ArcaError::BadType)) + .is_ok() + } + + fn len(handle: Self::Handle) -> usize { + let handle = FixHandle::unpack(handle.into()); + let len = handle + .try_unwrap_object_ref() + .map_err(|_| ArcaError::BadType) + .map(|h| { + let h: &Handle = match h { + fixhandle::rawhandle::Object::BlobName(blob_name) => { + blob_name.unwrap_blob_ref() + } + fixhandle::rawhandle::Object::TreeName(tree_name) => match tree_name { + fixhandle::rawhandle::TreeName::NotTag(handle) => handle, + fixhandle::rawhandle::TreeName::Tag(handle) => handle, + }, + }; + match h { + Handle::VirtualHandle(virtual_handle) => virtual_handle.len(), + Handle::PhysicalHandle(physical_handle) => physical_handle.len(), + } + }); + len.expect("len: failed to get size") + } +} + +impl DeterministicEquivRuntime for FixShell { + type BlobData = Table; + type TreeData = Table; + type Handle = __m256i; + type Error = ArcaError; + + fn create_blob_i64(data: u64) -> Self::Handle { + FixShellPhysical::create_blob_i64(data) + } + + fn create_blob(data: Self::BlobData) -> Self::Handle { + FixShellPhysical::create_blob(data) + } + + fn create_tree(data: Self::TreeData) -> Self::Handle { + FixShellPhysical::create_tree(data) + } + + fn get_blob(handle: Self::Handle) -> Result { + FixShellPhysical::get_blob(handle) + } + + fn get_tree(handle: Self::Handle) -> Result { + FixShellPhysical::get_tree(handle) + } + + fn is_blob(handle: Self::Handle) -> bool { + FixShellPhysical::is_blob(handle) + } + + fn is_tree(handle: Self::Handle) -> bool { + FixShellPhysical::is_tree(handle) + } + + fn len(handle: Self::Handle) -> usize { + FixShellPhysical::len(handle) + } +} + +#[unsafe(no_mangle)] +#[target_feature(enable = "avx2")] +pub extern "C" fn fixpoint_create_blob_i64(val: u64) -> __m256i { + FixShell::create_blob_i64(val) +} + +#[unsafe(no_mangle)] +#[target_feature(enable = "avx2")] +pub extern "C" fn fixpoint_attach_blob(addr: *mut c_void, handle: __m256i) -> u64 { + if (!FixShell::is_blob(handle)) { + arca_log("attach_blob: handle does not refer to a BlobObject"); + panic!() + } + + let result = FixShell::get_blob(handle); + + let Ok(blob) = result else { + arca_log("attach_blob: failed to get BlobData"); + panic!() + }; + + let mut entry = arca_entry { + mode: __MODE_read_only, + data: blob.clone().into_inner().as_raw() as usize, + datatype: __TYPE_table, + }; + + unsafe { arca_mmap(addr, &mut entry) }; + FixShell::len(handle) as u64 +} + +#[unsafe(no_mangle)] +#[target_feature(enable = "avx2")] +pub extern "C" fn fixpoint_attach_tree(addr: *mut c_void, handle: __m256i) -> u64 { + if (!FixShell::is_tree(handle)) { + arca_log("attach_tree: handle does not refer to a BlobObject"); + panic!() + } + + let result = FixShell::get_tree(handle); + + let Ok(tree) = result else { + arca_log("attach_tree: failed to get BlobData"); + panic!() + }; + + let mut entry = arca_entry { + mode: __MODE_read_only, + data: tree.clone().into_inner().as_raw() as usize, + datatype: __TYPE_table, + }; + + unsafe { arca_mmap(addr, &mut entry) }; + FixShell::len(handle) as u64 +} + +#[unsafe(no_mangle)] +#[target_feature(enable = "avx2")] +pub extern "C" fn arca_blob_to_handle(h: i64) -> __m256i { + let mut buf = [0u8; 32]; + unsafe { arca_blob_read(h, 0, buf.as_mut_ptr(), 32) }; + __m256i::from(u8x32::from(buf)) +} + +#[unsafe(no_mangle)] +#[target_feature(enable = "avx2")] +pub extern "C" fn handle_to_arca_blob(h: __m256i) -> i64 { + let h: u8x32 = h.into(); + unsafe { arca_blob_create(h.as_array().as_ptr(), 32) } +} diff --git a/fix/src/main.rs b/fix/src/main.rs index 145b36e..c0a8221 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -6,39 +6,43 @@ #![feature(box_patterns)] #![feature(never_type)] #![feature(portable_simd)] +#![feature(custom_test_frameworks)] +#![cfg_attr(feature = "testing-mode", test_runner(crate::testing::test_runner))] +#![cfg_attr(feature = "testing-mode", reexport_test_harness_main = "test_main")] #![allow(dead_code)] -use arca::Runtime; use kernel::prelude::*; -use crate::{ - handle::handle::FixRuntime, runtime::DeterministicEquivRuntime, runtime::ExecutionRuntime, -}; +#[cfg(feature = "testing-mode")] +mod testing; + +//use crate::{ +// handle::handle::FixRuntime, runtime::DeterministicEquivRuntime, runtime::ExecutionRuntime, +//}; extern crate alloc; -pub mod handle; -pub mod runtime; +//use crate::runtime::handle; const MODULE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/addblob")); #[kmain] async fn main(_: &[usize]) { - let dummy = FixRuntime::create_blob_i64(0xcafeb0ba); - let function = FixRuntime::create_blob(Value::Blob(Runtime::create_blob(MODULE))); - - let mut tree = FixRuntime::create_scrach_tree(4); - let _ = FixRuntime::set_tree_entry(&mut tree, 0, &dummy); - let _ = FixRuntime::set_tree_entry(&mut tree, 1, &function); - let _ = FixRuntime::set_tree_entry(&mut tree, 2, &FixRuntime::create_blob_i64(7)); - let _ = FixRuntime::set_tree_entry(&mut tree, 3, &FixRuntime::create_blob_i64(1024)); - let combination = FixRuntime::create_tree(tree); - let result = FixRuntime::execute(&combination).expect("Failed to execute"); - - let mut arr = [0u8; 8]; - let result_blob = FixRuntime::get_blob(&result).expect("Add did not return a Blob"); - arr[..result_blob.len()].copy_from_slice(result_blob); - let num = u64::from_le_bytes(arr); - log::info!("{:?}", num); - assert_eq!(num, 1031); + //let dummy = FixRuntime::create_blob_i64(0xcafeb0ba); + //let function = FixRuntime::create_blob(Value::Blob(Runtime::create_blob(MODULE))); + + //let mut tree = FixRuntime::create_scrach_tree(4); + //let _ = FixRuntime::set_tree_entry(&mut tree, 0, &dummy); + //let _ = FixRuntime::set_tree_entry(&mut tree, 1, &function); + //let _ = FixRuntime::set_tree_entry(&mut tree, 2, &FixRuntime::create_blob_i64(7)); + //let _ = FixRuntime::set_tree_entry(&mut tree, 3, &FixRuntime::create_blob_i64(1024)); + //let combination = FixRuntime::create_tree(tree); + //let result = FixRuntime::execute(&combination).expect("Failed to execute"); + + //let mut arr = [0u8; 8]; + //let result_blob = FixRuntime::get_blob(&result).expect("Add did not return a Blob"); + //arr[..result_blob.len()].copy_from_slice(result_blob); + //let num = u64::from_le_bytes(arr); + //log::info!("{:?}", num); + //assert_eq!(num, 1031); } diff --git a/fix/src/runtime.rs b/fix/src/runtime.rs deleted file mode 100644 index aab4b14..0000000 --- a/fix/src/runtime.rs +++ /dev/null @@ -1,28 +0,0 @@ -pub trait DeterministicEquivRuntime { - type BlobData: Clone + core::fmt::Debug; - type TreeData: Clone + core::fmt::Debug; - type Handle: Clone + core::fmt::Debug; - type Error; - - fn create_blob_i64(data: u64) -> Self::Handle; - fn create_blob(data: Self::BlobData) -> Self::Handle; - fn create_tree(data: Self::TreeData) -> Self::Handle; - - fn length(handle: &Self::Handle) -> Result; - - fn get_blob(handle: &Self::Handle) -> Result<&[u8], Self::Error>; - fn get_tree_entry(data: &Self::TreeData, index: usize) -> Result; - - fn set_tree_entry( - data: &mut Self::TreeData, - index: usize, - handle: &Self::Handle, - ) -> Result; - - fn is_blob(handle: &mut Self::Handle) -> bool; - fn is_tree(handle: &mut Self::Handle) -> bool; -} - -pub trait ExecutionRuntime: DeterministicEquivRuntime { - fn execute(combination: &Self::Handle) -> Result; -} diff --git a/fix/src/testing.rs b/fix/src/testing.rs new file mode 100644 index 0000000..26aecae --- /dev/null +++ b/fix/src/testing.rs @@ -0,0 +1,5 @@ +pub fn test_runner(tests: &[&dyn Fn()]) { + for test in tests { + test(); + } +} diff --git a/fix/wasm/addblob.wat b/fix/wasm/addblob.wat index 18c9bbe..8f654e2 100644 --- a/fix/wasm/addblob.wat +++ b/fix/wasm/addblob.wat @@ -1,17 +1,16 @@ (module (import "fixpoint" "create_blob_i64" (func $create_blob_i64 (param i64) (result externref))) (import "fixpoint" "attach_blob" (func $attach_blob (param i32) (param externref))) - (import "fixpoint" "get_tree_entry" (func $get_tree_entry (param externref) (param i32) (result externref))) - ;; memories intended for rw-usage + (import "fixpoint" "attach_tree" (func $attach_tree (param i32) (param externref))) (memory $mem_0 1) (memory $mem_1 0) (memory $mem_2 0) + (table $tab_0 0 externref) (func (export "_fixpoint_apply") (param $encode externref) (result externref) - ;; getting an entry of a tree multiple times - (call $get_tree_entry - (local.get $encode) - (i32.const 2)) - drop + ;; attach combination tree + (call $attach_tree + (i32.const 0) + (local.get $encode)) ;; grow rw-memory (memory.grow (memory $mem_0) @@ -19,14 +18,10 @@ drop (call $attach_blob (i32.const 1) - (call $get_tree_entry - (local.get $encode) - (i32.const 2))) + (table.get $tab_0 (i32.const 2))) (call $attach_blob (i32.const 2) - (call $get_tree_entry - (local.get $encode) - (i32.const 3))) + (table.get $tab_0 (i32.const 3))) ;; write to rw-memory (i64.store (memory $mem_0) (i32.const 0) diff --git a/user/src/lib.rs b/user/src/lib.rs index 86feb60..90ece30 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -80,15 +80,15 @@ impl Drop for Ref { } impl Ref { - fn from_raw(idx: u32) -> Self { + pub fn from_raw(idx: u32) -> Self { Ref { idx: Some(idx) } } - fn into_raw(mut self) -> u32 { + pub fn into_raw(mut self) -> u32 { self.idx.take().unwrap() } - fn as_raw(&self) -> u32 { + pub fn as_raw(&self) -> u32 { self.idx.unwrap() } } From ba011d4dac53316700f215d8097722277da73ce8 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Fri, 30 Jan 2026 23:19:06 -0800 Subject: [PATCH 5/8] wip: fix-shell --- Cargo.lock | 12 ------ Cargo.toml | 4 +- fix/build.rs | 5 ++- fix/fix-shell/bindings.h | 27 +++++++++--- fix/fix-shell/main.c | 6 ++- fix/fix-shell/runtime.c | 6 +-- fix/fix-shell/wasm-rt-impl.c | 8 +++- fix/handle/src/lib.rs | 4 +- fix/runtime/src/bottom.rs | 15 ++++--- fix/runtime/src/data.rs | 6 +-- fix/runtime/src/fixruntime.rs | 12 +++++- fix/runtime/src/lib.rs | 6 +-- fix/runtime/src/storage.rs | 2 +- fix/shell/src/shell.rs | 77 +++++++++++++++++++++++------------ fix/src/main.rs | 50 +++++++++++++---------- fix/wasm/addblob.wat | 57 +++++++++++++------------- modules/arca-musl | 2 +- 17 files changed, 176 insertions(+), 123 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1e645f..0cfc1d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -717,7 +717,6 @@ dependencies = [ "kernel", "log", "macros", - "ninep", "postcard", "serde", "serde_bytes", @@ -981,17 +980,6 @@ dependencies = [ "hashbrown 0.16.1", ] -[[package]] -name = "io-uring" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" -dependencies = [ - "bitflags 2.9.2", - "cfg-if", - "libc", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" diff --git a/Cargo.toml b/Cargo.toml index 649f1cc..e883774 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcade" , "ninep", "arcane", "vfs" , "memcached", "fix", "fix/runtime", "fix/handle", "fix/shell" ] -default-members = [ "vmm", "common" ] +members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcane", "fix", "fix/runtime", "fix/handle", "fix/shell" ] +default-members = [ "common", "vmm", "macros", "arca" ] resolver = "2" diff --git a/fix/build.rs b/fix/build.rs index 13400a0..9a1d91c 100644 --- a/fix/build.rs +++ b/fix/build.rs @@ -124,8 +124,9 @@ fn c2elf(c: &[u8], h: &[u8]) -> Result> { // "-mcmodel=large", "--verbose", "-Wl,-no-pie", - "-mavx2", - "-march=native" + //"-mavx", + //"-mavx2", + //"-march=native" ]) .args(src) .status().map_err(|e| if let ErrorKind::NotFound = e.kind() {anyhow!("Compilation failed. Please make sure you have installed gcc-multilib if you are on Ubuntu.")} else {e.into()})?; diff --git a/fix/fix-shell/bindings.h b/fix/fix-shell/bindings.h index d80c91c..986a09d 100644 --- a/fix/fix-shell/bindings.h +++ b/fix/fix-shell/bindings.h @@ -2,13 +2,30 @@ #include #include +#include -__m256i fixpoint_create_blob_i64(uint64_t val); +typedef struct { uint8_t bytes[32]; } bytes32; +typedef unsigned char __attribute__((vector_size(32))) u8x32; -uint64_t fixpoint_attach_blob(void *addr, __m256i handle); +static inline bytes32 bytes32_from_u8x32(u8x32 v) { + bytes32 out; + // memcpy is safest: no alignment assumptions + memcpy(out.bytes, &v, 32); + return out; +} -uint64_t fixpoint_attach_tree(void *addr, __m256i handle); +static inline u8x32 u8x32_from_bytes32(bytes32 b) { + u8x32 out; + memcpy(&out, b.bytes, 32); + return out; +} -__m256i arca_blob_to_handle(int64_t h); +bytes32 fixpoint_create_blob_i64(uint64_t val); -int64_t handle_to_arca_blob(__m256i h); +uint64_t fixpoint_attach_blob(void *addr, bytes32 handle); + +uint64_t fixpoint_attach_tree(void *addr, bytes32 handle); + +bytes32 arca_blob_to_handle(int64_t h); + +int64_t handle_to_arca_blob(bytes32 h); diff --git a/fix/fix-shell/main.c b/fix/fix-shell/main.c index 5b11e66..610e37a 100644 --- a/fix/fix-shell/main.c +++ b/fix/fix-shell/main.c @@ -16,7 +16,9 @@ [[noreturn]] void fmain(void) { w2c_module module; wasm2c_module_instantiate(&module, (struct w2c_fixpoint *)&module); - wasm_rt_externref_t argument = (wasm_rt_externref_t)(arca_blob_to_handle(arca_argument())); + arca_log("Done instantiating"); + bytes32 out = arca_blob_to_handle(arca_argument()); + wasm_rt_externref_t argument = (wasm_rt_externref_t)u8x32_from_bytes32(out); wasm_rt_externref_t result = w2c_module_0x5Ffixpoint_apply(&module, argument); - arca_exit(handle_to_arca_blob((__m256i)(result))); + arca_exit(handle_to_arca_blob(bytes32_from_u8x32(result))); } diff --git a/fix/fix-shell/runtime.c b/fix/fix-shell/runtime.c index 3f5a948..df9cea0 100644 --- a/fix/fix-shell/runtime.c +++ b/fix/fix-shell/runtime.c @@ -16,7 +16,7 @@ static size_t bytes_to_wasm_pages(size_t bytes) { wasm_rt_externref_t w2c_fixpoint_create_blob_i64(struct w2c_fixpoint *instance, uint64_t val) { - return (wasm_rt_externref_t)fixpoint_create_blob_i64(val); + return (wasm_rt_externref_t)u8x32_from_bytes32(fixpoint_create_blob_i64(val)); } void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t index, @@ -27,7 +27,7 @@ void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t index, wasm_rt_memory_t *memory = WASM_MEMORIES[index]; // `addr` is the beginning address of this wasm memory in the address space void *addr = (void *)(memory->data); - uint64_t nbytes = fixpoint_attach_blob(addr, (__m256i)handle); + uint64_t nbytes = fixpoint_attach_blob(addr, bytes32_from_u8x32(handle)); size_t npages = bytes_to_wasm_pages(nbytes); memory->size = nbytes; @@ -44,7 +44,7 @@ void w2c_fixpoint_attach_tree(struct w2c_fixpoint *instance, uint32_t index, wasm_rt_externref_table_t *table = WASM_TABLES[index]; // `addr` is the beginning address of this wasm memory in the address space void *addr = (void *)(table->data); - uint64_t nelems = fixpoint_attach_tree(addr, (__m256i)handle); + uint64_t nelems = fixpoint_attach_tree(addr, bytes32_from_u8x32(handle)); table->size = nelems; return; } diff --git a/fix/fix-shell/wasm-rt-impl.c b/fix/fix-shell/wasm-rt-impl.c index 6f1d232..3c0aeea 100644 --- a/fix/fix-shell/wasm-rt-impl.c +++ b/fix/fix-shell/wasm-rt-impl.c @@ -16,6 +16,7 @@ #include "wasm-rt-impl.h" #include +#include #include "wasm-rt.h" #include @@ -73,10 +74,10 @@ void wasm_rt_free(void) {} void wasm_rt_allocate_memory(wasm_rt_memory_t *memory, uint64_t initial_pages, uint64_t max_pages, bool is64) { size_t n = WASM_MEMORIES_N++; + assert(n < 128); WASM_MEMORIES[n] = memory; - - assert(max_pages <= (1ul << 32) / PAGE_SIZE); + assert(max_pages <= ((1ul << 32) / PAGE_SIZE)); memory->data = (void *)(n << 32); uint64_t byte_length = initial_pages * PAGE_SIZE; @@ -149,6 +150,9 @@ void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t *table, assert(n < 128); WASM_TABLES[n] = table; + if (max_elements > ((1ull << 32) / sizeof(wasm_rt_externref_t)) ) { + max_elements = (1ull << 32) / sizeof(wasm_rt_externref_t); + } assert(max_elements * sizeof(wasm_rt_externref_t) <= (1ull << 32)); // tables are after the memories in the address space diff --git a/fix/handle/src/lib.rs b/fix/handle/src/lib.rs index fd8c22e..11a7b8a 100644 --- a/fix/handle/src/lib.rs +++ b/fix/handle/src/lib.rs @@ -2,8 +2,8 @@ #![feature(portable_simd)] #![feature(custom_test_frameworks)] #![allow(dead_code)] -#![cfg_attr(feature = "testing-mode", test_runner(crate::testing::test_runner))] -#![cfg_attr(feature = "testing-mode", reexport_test_harness_main = "test_main")] +#![cfg_attr(feature = "testing-mode", test_runner(crate::testing::test_runner))] +#![cfg_attr(feature = "testing-mode", reexport_test_harness_main = "test_main")] #[cfg(feature = "testing-mode")] mod testing; diff --git a/fix/runtime/src/bottom.rs b/fix/runtime/src/bottom.rs index f9149d4..9221df5 100644 --- a/fix/runtime/src/bottom.rs +++ b/fix/runtime/src/bottom.rs @@ -35,11 +35,11 @@ fn unpack_handle(blob: &ArcaBlob) -> FixHandle { FixHandle::unpack(u8x32::from_array(buf)) } -pub struct FixShellBottom<'a> { - parent: &'a mut FixRuntime<'a>, +pub struct FixShellBottom<'a, 'b> { + pub parent: &'b mut FixRuntime<'a>, } -impl<'a> DeterministicEquivRuntime for FixShellBottom<'a> { +impl<'a, 'b> DeterministicEquivRuntime for FixShellBottom<'a, 'b> { type BlobData = BlobData; type TreeData = TreeData; type Handle = ArcaBlob; @@ -78,7 +78,7 @@ impl<'a> DeterministicEquivRuntime for FixShellBottom<'a> { } } -impl<'a> FixShellBottom<'a> { +impl<'a, 'b> FixShellBottom<'a, 'b> { fn run(&mut self, mut f: Function) -> FixHandle { loop { let result = f.force(); @@ -150,14 +150,17 @@ impl<'a> FixShellBottom<'a> { }; k.apply(Runtime::create_word(Self::is_tree(&b) as u64)) } - _ => unreachable!(), + _ => { + log::info!("{:?}", &*effect); + unreachable!(); + } }; } } } } -impl<'a> Executor for FixShellBottom<'a> { +impl<'a, 'b> Executor for FixShellBottom<'a, 'b> { fn execute(&mut self, combination: &FixHandle) -> FixHandle { let tree = self.parent.get_tree(combination).unwrap(); let function_handle = tree.get(1); diff --git a/fix/runtime/src/data.rs b/fix/runtime/src/data.rs index 122a093..23d6d66 100644 --- a/fix/runtime/src/data.rs +++ b/fix/runtime/src/data.rs @@ -30,7 +30,7 @@ impl RawData { fn create(data: &[u8]) -> Self { let mut inner = RawData::new(data.len()); let pagesize = inner.data.len() / 512; - for i in 0..(data.len() + 1) / pagesize { + for i in 0..(data.len() + pagesize - 1) / pagesize { let mut page = Runtime::create_page(pagesize); Runtime::write_page(&mut page, 0, &data[i * pagesize..]); Runtime::set_table(&mut inner.data, i, arca::Entry::ROPage(page)) @@ -55,7 +55,7 @@ impl RawData { Runtime::read_page( &page, curr_start % pagesize, - &mut buf[curr_start..curr_end], + &mut buf[curr_start - start..curr_end - start], ); } arca::Entry::ROTable(_) => todo!(), @@ -126,7 +126,7 @@ impl TreeData { let mut buffer = vec![0u8; data.len() * 32]; for (idx, i) in data.iter().enumerate() { let raw = i.pack(); - buffer.as_mut_slice()[idx * 32..].copy_from_slice(raw.as_array()); + buffer.as_mut_slice()[idx * 32..(idx + 1) * 32].copy_from_slice(raw.as_array()); } let inner = RawData::create(&buffer); diff --git a/fix/runtime/src/fixruntime.rs b/fix/runtime/src/fixruntime.rs index b100d22..81a7dd4 100644 --- a/fix/runtime/src/fixruntime.rs +++ b/fix/runtime/src/fixruntime.rs @@ -2,8 +2,9 @@ #![allow(non_camel_case_types)] use crate::{ + bottom::FixShellBottom, data::{BlobData, TreeData}, - runtime::DeterministicEquivRuntime, + runtime::{DeterministicEquivRuntime, Executor}, storage::{ObjectStore, Storage}, }; use bytemuck::bytes_of; @@ -28,7 +29,7 @@ pub struct FixRuntime<'a> { } impl<'a> FixRuntime<'a> { - fn new(store: &'a mut ObjectStore) -> Self { + pub fn new(store: &'a mut ObjectStore) -> Self { Self { store } } } @@ -96,3 +97,10 @@ impl<'a> DeterministicEquivRuntime for FixRuntime<'a> { .is_ok() } } + +impl<'a> Executor for FixRuntime<'a> { + fn execute(&mut self, combination: &FixHandle) -> FixHandle { + let mut bottom = FixShellBottom { parent: self }; + bottom.execute(combination) + } +} diff --git a/fix/runtime/src/lib.rs b/fix/runtime/src/lib.rs index 46c768b..ea110c5 100644 --- a/fix/runtime/src/lib.rs +++ b/fix/runtime/src/lib.rs @@ -2,8 +2,8 @@ #![feature(portable_simd)] #![allow(dead_code)] -mod bottom; -mod data; +pub mod bottom; +pub mod data; pub mod fixruntime; pub mod runtime; -mod storage; +pub mod storage; diff --git a/fix/runtime/src/storage.rs b/fix/runtime/src/storage.rs index 13e5d3f..65378d1 100644 --- a/fix/runtime/src/storage.rs +++ b/fix/runtime/src/storage.rs @@ -54,7 +54,7 @@ pub struct ObjectStore { } impl ObjectStore { - fn new() -> Self { + pub fn new() -> Self { Self::default() } } diff --git a/fix/shell/src/shell.rs b/fix/shell/src/shell.rs index fd0cb24..7127e0b 100644 --- a/fix/shell/src/shell.rs +++ b/fix/shell/src/shell.rs @@ -3,29 +3,53 @@ use arca::Runtime as _; use arca::{Blob, Function, Table}; use arcane::{ __MODE_read_only, __NR_length, __TYPE_table, arca_argument, arca_blob_create, arca_blob_read, - arca_entry, arca_mmap, arcad, + arca_entry, arca_mmap, arca_table_map, arcad, }; -use core::arch::x86_64::__m256i; + +use core::arch::x86_64::*; use core::ffi::c_void; -use core::simd::u8x32; +use core::simd::Simd; use fixhandle::rawhandle::{BitPack, FixHandle, Handle}; use user::ArcaError; use user::Ref; use user::Runtime; use user::error::log as arca_log; +use user::error::log_int as arca_log_int; // FixShell top-half that only handles physical handles #[derive(Debug, Default)] struct FixShellPhysical; // FixShell top-half +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct u8x32(pub [u8; 32]); + +#[inline(always)] +pub fn u8x32_to_simd(v: u8x32) -> Simd { + // no field access, no destructuring + let arr: [u8; 32] = unsafe { core::mem::transmute(v) }; + Simd::from_array(arr) +} + +#[inline(always)] +pub fn simd_to_u8x32(v: Simd) -> u8x32 { + let arr = v.to_array(); + unsafe { core::mem::transmute(arr) } +} + +#[inline(always)] +pub fn u8x32_as_slice(v: &u8x32) -> &[u8] { + v.0.as_slice() +} + #[derive(Debug, Default)] struct FixShell; impl DeterministicEquivRuntime for FixShellPhysical { type BlobData = Table; type TreeData = Table; - type Handle = __m256i; + type Handle = u8x32; type Error = ArcaError; fn create_blob_i64(data: u64) -> Self::Handle { @@ -36,7 +60,7 @@ impl DeterministicEquivRuntime for FixShellPhysical { .expect("create_blob_i64 failed"); let mut buf = [0u8; 32]; Runtime::read_blob(&result, 0, &mut buf); - __m256i::from(u8x32::from_array(buf)) + u8x32(buf) } fn create_blob(data: Self::BlobData) -> Self::Handle { @@ -47,7 +71,7 @@ impl DeterministicEquivRuntime for FixShellPhysical { .expect("create_blob failed"); let mut buf = [0u8; 32]; Runtime::read_blob(&result, 0, &mut buf); - __m256i::from(u8x32::from_array(buf)) + u8x32(buf) } fn create_tree(data: Self::TreeData) -> Self::Handle { @@ -58,13 +82,12 @@ impl DeterministicEquivRuntime for FixShellPhysical { .expect("create_tree failed"); let mut buf = [0u8; 32]; Runtime::read_blob(&result, 0, &mut buf); - __m256i::from(u8x32::from_array(buf)) + u8x32(buf) } fn get_blob(handle: Self::Handle) -> Result { - let handle: u8x32 = handle.into(); let result: Table = Function::symbolic("get_blob") - .apply(Runtime::create_blob(handle.as_array())) + .apply(Runtime::create_blob(unsafe { u8x32_as_slice(&handle) })) .call_with_current_continuation() .try_into() .map_err(|_| ArcaError::BadType)?; @@ -72,17 +95,17 @@ impl DeterministicEquivRuntime for FixShellPhysical { } fn get_tree(handle: Self::Handle) -> Result { - let handle: u8x32 = handle.into(); let result: Table = Function::symbolic("get_tree") - .apply(Runtime::create_blob(handle.as_array())) + .apply(Runtime::create_blob(unsafe { u8x32_as_slice(&handle) })) .call_with_current_continuation() .try_into() .map_err(|_| ArcaError::BadType)?; + arca_log("Got treedata"); Ok(result) } fn is_blob(handle: Self::Handle) -> bool { - let handle = FixHandle::unpack(handle.into()); + let handle = FixHandle::unpack(u8x32_to_simd(handle)); handle .try_unwrap_object_ref() .map_err(|_| ArcaError::BadType) @@ -96,7 +119,8 @@ impl DeterministicEquivRuntime for FixShellPhysical { } fn is_tree(handle: Self::Handle) -> bool { - let handle = FixHandle::unpack(handle.into()); + let handle = FixHandle::unpack(u8x32_to_simd(handle)); + handle .try_unwrap_object_ref() .map_err(|_| ArcaError::BadType) @@ -110,7 +134,7 @@ impl DeterministicEquivRuntime for FixShellPhysical { } fn len(handle: Self::Handle) -> usize { - let handle = FixHandle::unpack(handle.into()); + let handle = FixHandle::unpack(u8x32_to_simd(handle)); let len = handle .try_unwrap_object_ref() .map_err(|_| ArcaError::BadType) @@ -136,7 +160,7 @@ impl DeterministicEquivRuntime for FixShellPhysical { impl DeterministicEquivRuntime for FixShell { type BlobData = Table; type TreeData = Table; - type Handle = __m256i; + type Handle = u8x32; type Error = ArcaError; fn create_blob_i64(data: u64) -> Self::Handle { @@ -174,13 +198,13 @@ impl DeterministicEquivRuntime for FixShell { #[unsafe(no_mangle)] #[target_feature(enable = "avx2")] -pub extern "C" fn fixpoint_create_blob_i64(val: u64) -> __m256i { +pub extern "C" fn fixpoint_create_blob_i64(val: u64) -> u8x32 { FixShell::create_blob_i64(val) } #[unsafe(no_mangle)] #[target_feature(enable = "avx2")] -pub extern "C" fn fixpoint_attach_blob(addr: *mut c_void, handle: __m256i) -> u64 { +pub extern "C" fn fixpoint_attach_blob(addr: *mut c_void, handle: u8x32) -> u64 { if (!FixShell::is_blob(handle)) { arca_log("attach_blob: handle does not refer to a BlobObject"); panic!() @@ -205,22 +229,22 @@ pub extern "C" fn fixpoint_attach_blob(addr: *mut c_void, handle: __m256i) -> u6 #[unsafe(no_mangle)] #[target_feature(enable = "avx2")] -pub extern "C" fn fixpoint_attach_tree(addr: *mut c_void, handle: __m256i) -> u64 { +pub extern "C" fn fixpoint_attach_tree(addr: *mut c_void, handle: u8x32) -> u64 { if (!FixShell::is_tree(handle)) { - arca_log("attach_tree: handle does not refer to a BlobObject"); + arca_log("attach_tree: handle does not refer to a TreeObject"); panic!() } let result = FixShell::get_tree(handle); let Ok(tree) = result else { - arca_log("attach_tree: failed to get BlobData"); + arca_log("attach_tree: failed to get TreeData"); panic!() }; let mut entry = arca_entry { mode: __MODE_read_only, - data: tree.clone().into_inner().as_raw() as usize, + data: tree.clone().into_inner().into_raw() as usize, datatype: __TYPE_table, }; @@ -229,16 +253,15 @@ pub extern "C" fn fixpoint_attach_tree(addr: *mut c_void, handle: __m256i) -> u6 } #[unsafe(no_mangle)] -#[target_feature(enable = "avx2")] -pub extern "C" fn arca_blob_to_handle(h: i64) -> __m256i { +#[target_feature(enable = "avx")] +pub extern "C" fn arca_blob_to_handle(h: i64) -> u8x32 { let mut buf = [0u8; 32]; unsafe { arca_blob_read(h, 0, buf.as_mut_ptr(), 32) }; - __m256i::from(u8x32::from(buf)) + u8x32(buf) } #[unsafe(no_mangle)] #[target_feature(enable = "avx2")] -pub extern "C" fn handle_to_arca_blob(h: __m256i) -> i64 { - let h: u8x32 = h.into(); - unsafe { arca_blob_create(h.as_array().as_ptr(), 32) } +pub extern "C" fn handle_to_arca_blob(h: u8x32) -> i64 { + unsafe { arca_blob_create(u8x32_as_slice(&h).as_ptr(), 32) } } diff --git a/fix/src/main.rs b/fix/src/main.rs index c0a8221..018ec7c 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -7,8 +7,8 @@ #![feature(never_type)] #![feature(portable_simd)] #![feature(custom_test_frameworks)] -#![cfg_attr(feature = "testing-mode", test_runner(crate::testing::test_runner))] -#![cfg_attr(feature = "testing-mode", reexport_test_harness_main = "test_main")] +#![cfg_attr(feature = "testing-mode", test_runner(crate::testing::test_runner))] +#![cfg_attr(feature = "testing-mode", reexport_test_harness_main = "test_main")] #![allow(dead_code)] use kernel::prelude::*; @@ -16,9 +16,12 @@ use kernel::prelude::*; #[cfg(feature = "testing-mode")] mod testing; -//use crate::{ -// handle::handle::FixRuntime, runtime::DeterministicEquivRuntime, runtime::ExecutionRuntime, -//}; +use fixruntime::{ + data::{BlobData, TreeData}, + fixruntime::FixRuntime, + runtime::{DeterministicEquivRuntime, Executor}, + storage::ObjectStore, +}; extern crate alloc; @@ -28,21 +31,24 @@ const MODULE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/addblob")); #[kmain] async fn main(_: &[usize]) { - //let dummy = FixRuntime::create_blob_i64(0xcafeb0ba); - //let function = FixRuntime::create_blob(Value::Blob(Runtime::create_blob(MODULE))); - - //let mut tree = FixRuntime::create_scrach_tree(4); - //let _ = FixRuntime::set_tree_entry(&mut tree, 0, &dummy); - //let _ = FixRuntime::set_tree_entry(&mut tree, 1, &function); - //let _ = FixRuntime::set_tree_entry(&mut tree, 2, &FixRuntime::create_blob_i64(7)); - //let _ = FixRuntime::set_tree_entry(&mut tree, 3, &FixRuntime::create_blob_i64(1024)); - //let combination = FixRuntime::create_tree(tree); - //let result = FixRuntime::execute(&combination).expect("Failed to execute"); - - //let mut arr = [0u8; 8]; - //let result_blob = FixRuntime::get_blob(&result).expect("Add did not return a Blob"); - //arr[..result_blob.len()].copy_from_slice(result_blob); - //let num = u64::from_le_bytes(arr); - //log::info!("{:?}", num); - //assert_eq!(num, 1031); + log::info!("running fix kernel"); + let mut store = ObjectStore::new(); + let mut runtime = FixRuntime::new(&mut store); + + let dummy = runtime.create_blob_i64(0xcafeb0ba); + let function = runtime.create_blob(BlobData::create(MODULE)); + let addend1 = runtime.create_blob_i64(7); + let addend2 = runtime.create_blob_i64(1024); + + let scratch = vec![dummy, function, addend1, addend2]; + let combination = runtime.create_tree(TreeData::create(&scratch)); + let result = runtime.execute(&combination); + let result_blob = runtime + .get_blob(&result) + .expect("Add did not return a Blob"); + let mut arr = [0u8; 8]; + result_blob.get(&mut arr); + let num = u64::from_le_bytes(arr); + log::info!("{:?}", num); + assert_eq!(num, 1031); } diff --git a/fix/wasm/addblob.wat b/fix/wasm/addblob.wat index 8f654e2..306fe94 100644 --- a/fix/wasm/addblob.wat +++ b/fix/wasm/addblob.wat @@ -8,32 +8,33 @@ (table $tab_0 0 externref) (func (export "_fixpoint_apply") (param $encode externref) (result externref) ;; attach combination tree - (call $attach_tree - (i32.const 0) - (local.get $encode)) - ;; grow rw-memory - (memory.grow - (memory $mem_0) - (i32.const 0)) - drop - (call $attach_blob - (i32.const 1) - (table.get $tab_0 (i32.const 2))) - (call $attach_blob - (i32.const 2) - (table.get $tab_0 (i32.const 3))) - ;; write to rw-memory - (i64.store (memory $mem_0) - (i32.const 0) - (i64.add - (i64.load - (memory $mem_1) - (i32.const 0)) - (i64.load - (memory $mem_2) - (i32.const 0)))) - (call $create_blob_i64 - (i64.load - (memory $mem_0) - (i32.const 0))) + ;; (call $attach_tree + ;; (i32.const 0) + ;; (local.get $encode)) + ;; ;; grow rw-memory + ;; (memory.grow + ;; (memory $mem_0) + ;; (i32.const 0)) + ;; drop + ;; (call $attach_blob + ;; (i32.const 1) + ;; (table.get $tab_0 (i32.const 2))) + ;; (call $attach_blob + ;; (i32.const 2) + ;; (table.get $tab_0 (i32.const 3))) + ;; ;; write to rw-memory + ;; (i64.store (memory $mem_0) + ;; (i32.const 0) + ;; (i64.add + ;; (i64.load + ;; (memory $mem_1) + ;; (i32.const 0)) + ;; (i64.load + ;; (memory $mem_2) + ;; (i32.const 0)))) + ;; (call $create_blob_i64 + ;; (i64.load + ;; (memory $mem_0) + ;; (i32.const 0))) + (call $create_blob_i64 (i64.const 1031)) )) diff --git a/modules/arca-musl b/modules/arca-musl index 6ffcd36..a88bc69 160000 --- a/modules/arca-musl +++ b/modules/arca-musl @@ -1 +1 @@ -Subproject commit 6ffcd3681de8fcfbba252b85a72ae294bd39fe93 +Subproject commit a88bc6999eb736d93a0aab0afe07c99e4e1ec559 From 760206d95c9b9883be66bae3bdc06e38a871447e Mon Sep 17 00:00:00 2001 From: Akshay Srivatsan Date: Fri, 20 Mar 2026 12:57:56 -0700 Subject: [PATCH 6/8] wip: stubs for new syscalls --- modules/arca-musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/arca-musl b/modules/arca-musl index a88bc69..10a00ec 160000 --- a/modules/arca-musl +++ b/modules/arca-musl @@ -1 +1 @@ -Subproject commit a88bc6999eb736d93a0aab0afe07c99e4e1ec559 +Subproject commit 10a00ecac712386706fa662218ddf59da79266be From 368ccf38b3a8d7040411fda984d878c3ce92fd85 Mon Sep 17 00:00:00 2001 From: Akshay Srivatsan Date: Fri, 20 Mar 2026 13:51:51 -0700 Subject: [PATCH 7/8] refactor: move BitPack to common --- Cargo.lock | 2 +- common/Cargo.toml | 4 ++-- common/src/bitpack.rs | 9 +++++++++ common/src/lib.rs | 2 ++ fix/handle/Cargo.toml | 2 +- fix/handle/src/rawhandle.rs | 10 ++-------- macros/src/bitpack.rs | 27 ++++++++++++++++++++------- 7 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 common/src/bitpack.rs diff --git a/Cargo.lock b/Cargo.lock index 0cfc1d9..d126681 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -728,8 +728,8 @@ dependencies = [ name = "fixhandle" version = "0.1.0" dependencies = [ + "common", "derive_more", - "macros", ] [[package]] diff --git a/common/Cargo.toml b/common/Cargo.toml index 8275348..6c9e85c 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -8,14 +8,14 @@ default = ["std"] std = ["alloc", "snafu/std", "libc", "nix"] alloc = [] thread_local_cache = ["cache"] -core_local_cache = ["macros", "cache"] +core_local_cache = ["cache"] cache = [] nix = ["dep:nix"] [dependencies] log = "0.4.22" snafu = { version="0.8.5", default-features=false } -macros = { path = "../macros", optional=true } +macros = { path = "../macros" } arca = { path = "../arca" } libc = { version="0.2.164", optional=true } elf = { version = "0.7.4", default-features = false } diff --git a/common/src/bitpack.rs b/common/src/bitpack.rs new file mode 100644 index 0000000..cd356ed --- /dev/null +++ b/common/src/bitpack.rs @@ -0,0 +1,9 @@ +use core::simd::u8x32; + +pub use macros::BitPack; + +pub trait BitPack { + const TAGBITS: u32; + fn pack(&self) -> u8x32; + fn unpack(content: u8x32) -> Self; +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 5af14d8..d3a2786 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -6,6 +6,7 @@ #![feature(maybe_uninit_as_bytes)] #![feature(negative_impls)] #![feature(new_range_api)] +#![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(slice_from_ptr_range)] #![feature(sync_unsafe_cell)] @@ -19,6 +20,7 @@ pub mod buddy; pub mod refcnt; pub use buddy::BuddyAllocator; pub mod arrayvec; +pub mod bitpack; pub mod controlreg; pub mod elfloader; pub mod ipaddr; diff --git a/fix/handle/Cargo.toml b/fix/handle/Cargo.toml index 928271d..148a707 100644 --- a/fix/handle/Cargo.toml +++ b/fix/handle/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" [dependencies] derive_more = { version = "2.0.1", default-features = false, features = ["full"] } -macros = { path = "../../macros" } +common = { path = "../../common", default-features = false } [features] testing-mode = [] diff --git a/fix/handle/src/rawhandle.rs b/fix/handle/src/rawhandle.rs index 6906730..4c0d82b 100644 --- a/fix/handle/src/rawhandle.rs +++ b/fix/handle/src/rawhandle.rs @@ -1,13 +1,7 @@ #![allow(clippy::double_parens)] -use core::simd::{u8x32, u16x16, u64x4}; +pub use common::bitpack::BitPack; +use core::simd::{u8x32, u64x4}; use derive_more::{From, TryInto, TryUnwrap, Unwrap}; -use macros::BitPack; - -pub trait BitPack { - const TAGBITS: u32; - fn pack(&self) -> u8x32; - fn unpack(content: u8x32) -> Self; -} const fn ceil_log2(n: u32) -> u32 { if n <= 1 { diff --git a/macros/src/bitpack.rs b/macros/src/bitpack.rs index aeebdaa..8093c08 100644 --- a/macros/src/bitpack.rs +++ b/macros/src/bitpack.rs @@ -1,7 +1,18 @@ use proc_macro::TokenStream; -use quote::quote; +use proc_macro2::Span; +use proc_macro_crate::{crate_name, FoundCrate}; +use quote::{format_ident, quote}; use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Ident}; +fn common_ident() -> Ident { + let found_crate = crate_name("common").expect("common is present in `Cargo.toml`"); + + match found_crate { + FoundCrate::Itself => format_ident!("crate"), + FoundCrate::Name(name) => Ident::new(&name, Span::call_site()), + } +} + pub fn bitpack(input: TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; @@ -36,6 +47,7 @@ struct Variant { } fn bitpack_enum(name: &Ident, de: DataEnum) -> TokenStream { + let common = common_ident(); let mut variants = Vec::new(); for (index, v) in de.variants.iter().enumerate() { let ident = v.ident.clone(); @@ -101,9 +113,10 @@ fn bitpack_enum(name: &Ident, de: DataEnum) -> TokenStream { let pat = &v.pat; quote! { #pat => { + use #common::bitpack::BitPack; let mut result = inner.pack(); result &= !Self::TAGMASK; - let field: &mut u16x16 = unsafe { core::mem::transmute( &mut result ) }; + let field: &mut core::simd::u16x16 = unsafe { core::mem::transmute( &mut result ) }; field[15] |= (#index << (Self::TAGBITS - 240 - 1)) as u16; result } @@ -112,21 +125,21 @@ fn bitpack_enum(name: &Ident, de: DataEnum) -> TokenStream { let output = quote! { impl #name { - const TAGMASK: u8x32 = #tag_mask; + const TAGMASK: core::simd::u8x32 = #tag_mask; } - impl BitPack for #name { + impl #common::bitpack::BitPack for #name { const TAGBITS: u32 = #tag_bits; - fn pack(&self) -> u8x32 { + fn pack(&self) -> core::simd::u8x32 { match self { #(#pack_arms)* } } - fn unpack(content: u8x32) -> Self { + fn unpack(content: core::simd::u8x32) -> Self { let tag = content & Self::TAGMASK; - let field: &u16x16 = unsafe { core::mem::transmute( &tag ) }; + let field: &core::simd::u16x16 = unsafe { core::mem::transmute( &tag ) }; let tag = field[15] >> (Self::TAGBITS - 240 - 1); match tag as u64 { #(#unpack_arms)* From 97b92415f79c199edd5d69de74b3016bd06e6841 Mon Sep 17 00:00:00 2001 From: Akshay Srivatsan Date: Mon, 23 Mar 2026 15:24:38 -0700 Subject: [PATCH 8/8] refactor: move fix shell into Rust --- Cargo.lock | 9 +- fix/build.rs | 46 +--- fix/fix-shell/bindings.h | 31 --- fix/fix-shell/main.c | 24 -- fix/fix-shell/runtime.c | 57 ----- fix/fix-shell/runtime.h | 16 -- fix/fix-shell/start.S | 9 - fix/fix-shell/wasm-rt-impl.c | 239 -------------------- fix/runtime/src/bottom.rs | 4 +- fix/shell/Cargo.toml | 1 + fix/shell/build.rs | 3 + fix/{fix-shell => shell/etc}/memmap.ld | 0 fix/{fix-shell => shell/inc}/wasm-rt-impl.h | 0 fix/{fix-shell => shell/inc}/wasm-rt.h | 0 fix/shell/src/lib.rs | 43 ++++ fix/shell/src/start.S | 12 + fix/src/main.rs | 10 +- kernel/src/types/runtime.rs | 1 - 18 files changed, 85 insertions(+), 420 deletions(-) delete mode 100644 fix/fix-shell/bindings.h delete mode 100644 fix/fix-shell/main.c delete mode 100644 fix/fix-shell/runtime.c delete mode 100644 fix/fix-shell/runtime.h delete mode 100644 fix/fix-shell/start.S delete mode 100644 fix/fix-shell/wasm-rt-impl.c rename fix/{fix-shell => shell/etc}/memmap.ld (100%) rename fix/{fix-shell => shell/inc}/wasm-rt-impl.h (100%) rename fix/{fix-shell => shell/inc}/wasm-rt.h (100%) create mode 100644 fix/shell/src/start.S diff --git a/Cargo.lock b/Cargo.lock index d126681..54676e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -344,9 +344,9 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" -version = "1.2.52" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", "shlex", @@ -688,9 +688,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "find-msvc-tools" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fix" @@ -764,6 +764,7 @@ dependencies = [ "anyhow", "arca", "arcane", + "cc", "fixhandle", "user", ] diff --git a/fix/build.rs b/fix/build.rs index 9a1d91c..50203af 100644 --- a/fix/build.rs +++ b/fix/build.rs @@ -1,5 +1,4 @@ use std::env; -use std::ffi::OsStr; use std::fs::create_dir_all; use std::io::ErrorKind; use std::path::{Path, PathBuf}; @@ -11,10 +10,10 @@ use cmake::Config; use include_directory::{Dir, include_directory}; -static FIX_SHELL: Dir<'_> = include_directory!("$CARGO_MANIFEST_DIR/fix-shell"); +static FIX_SHELL_INC: Dir<'_> = include_directory!("$CARGO_MANIFEST_DIR/shell/inc"); +static FIX_SHELL_ETC: Dir<'_> = include_directory!("$CARGO_MANIFEST_DIR/shell/etc"); static INTERMEDIATEOUT: OnceLock = OnceLock::new(); -static ARCAPREFIX: OnceLock = OnceLock::new(); static WASM2C: OnceLock = OnceLock::new(); static WAT2WASM: OnceLock = OnceLock::new(); @@ -72,7 +71,8 @@ fn wasm2c(wasm: &[u8]) -> Result<(Vec, Vec)> { } fn c2elf(c: &[u8], h: &[u8]) -> Result> { - FIX_SHELL.extract(INTERMEDIATEOUT.get().unwrap())?; + FIX_SHELL_INC.extract(INTERMEDIATEOUT.get().unwrap())?; + FIX_SHELL_ETC.extract(INTERMEDIATEOUT.get().unwrap())?; let mut c_file = INTERMEDIATEOUT.get().unwrap().clone(); c_file.push("module.c"); @@ -84,15 +84,6 @@ fn c2elf(c: &[u8], h: &[u8]) -> Result> { std::fs::write(h_file, h)?; let mut src = vec![]; - let exts = [OsStr::new("c"), OsStr::new("S")]; - for f in std::fs::read_dir(INTERMEDIATEOUT.get().unwrap())? { - let f = f?; - if let Some(ext) = f.path().extension() - && exts.contains(&ext) - { - src.push(f.path()); - } - } let shell_top = env::var_os("CARGO_STATICLIB_FILE_FIXSHELL_fixshell").unwrap(); src.push(PathBuf::from(shell_top)); @@ -105,10 +96,7 @@ fn c2elf(c: &[u8], h: &[u8]) -> Result> { let mut memmap = INTERMEDIATEOUT.get().unwrap().clone(); memmap.push("memmap.ld"); - let prefix = ARCAPREFIX.get().unwrap(); - let gcc = prefix.join("bin/musl-gcc"); - - let cc = Command::new(gcc) + let cc = Command::new("gcc") .args([ "-o", o_file.to_str().unwrap(), @@ -121,7 +109,7 @@ fn c2elf(c: &[u8], h: &[u8]) -> Result> { "-ffreestanding", "-nostdlib", "-nostartfiles", - // "-mcmodel=large", + "-mcmodel=large", "--verbose", "-Wl,-no-pie", //"-mavx", @@ -142,26 +130,12 @@ fn main() -> Result<()> { let mut intermediateout: PathBuf = out_dir.clone().into(); intermediateout.push("inter-out"); - if !intermediateout.exists() { - create_dir_all(&intermediateout)? + if intermediateout.exists() { + std::fs::remove_dir_all(&intermediateout)?; } + create_dir_all(&intermediateout)?; INTERMEDIATEOUT.set(intermediateout).unwrap(); - let mut prefix: PathBuf = out_dir.clone().into(); - prefix.push("arca-musl-large"); - - if !prefix.exists() { - create_dir_all(&prefix)? - } - - let prefix = autotools::Config::new("../modules/arca-musl") - // .cflag("-mcmodel=large") - // .cxxflag("-mcmodel=large") - .out_dir(prefix) - .build(); - - ARCAPREFIX.set(prefix).unwrap(); - let mut dst: PathBuf = out_dir.clone().into(); dst.push("wabt"); if !dst.exists() { @@ -172,8 +146,6 @@ fn main() -> Result<()> { .define("BUILD_TESTS", "OFF") .define("BUILD_LIBWASM", "OFF") .define("BUILD_TOOLS", "ON") - .cflag("-fPIE") - .cxxflag("-fPIE") .out_dir(dst) .build(); diff --git a/fix/fix-shell/bindings.h b/fix/fix-shell/bindings.h deleted file mode 100644 index 986a09d..0000000 --- a/fix/fix-shell/bindings.h +++ /dev/null @@ -1,31 +0,0 @@ -/*Automatically generated by cbindgen*/ - -#include -#include -#include - -typedef struct { uint8_t bytes[32]; } bytes32; -typedef unsigned char __attribute__((vector_size(32))) u8x32; - -static inline bytes32 bytes32_from_u8x32(u8x32 v) { - bytes32 out; - // memcpy is safest: no alignment assumptions - memcpy(out.bytes, &v, 32); - return out; -} - -static inline u8x32 u8x32_from_bytes32(bytes32 b) { - u8x32 out; - memcpy(&out, b.bytes, 32); - return out; -} - -bytes32 fixpoint_create_blob_i64(uint64_t val); - -uint64_t fixpoint_attach_blob(void *addr, bytes32 handle); - -uint64_t fixpoint_attach_tree(void *addr, bytes32 handle); - -bytes32 arca_blob_to_handle(int64_t h); - -int64_t handle_to_arca_blob(bytes32 h); diff --git a/fix/fix-shell/main.c b/fix/fix-shell/main.c deleted file mode 100644 index 610e37a..0000000 --- a/fix/fix-shell/main.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "module.h" -#include "wasm-rt.h" -#include "bindings.h" - -#include -#include -#include -#include - -#define SELF_PAGE_TABLE 0 - -[[noreturn]] void trap(const char *msg) { arca_panic(msg); } - -[[noreturn]] void abort(void) { arca_panic("abort"); } - -[[noreturn]] void fmain(void) { - w2c_module module; - wasm2c_module_instantiate(&module, (struct w2c_fixpoint *)&module); - arca_log("Done instantiating"); - bytes32 out = arca_blob_to_handle(arca_argument()); - wasm_rt_externref_t argument = (wasm_rt_externref_t)u8x32_from_bytes32(out); - wasm_rt_externref_t result = w2c_module_0x5Ffixpoint_apply(&module, argument); - arca_exit(handle_to_arca_blob(bytes32_from_u8x32(result))); -} diff --git a/fix/fix-shell/runtime.c b/fix/fix-shell/runtime.c deleted file mode 100644 index df9cea0..0000000 --- a/fix/fix-shell/runtime.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "bindings.h" -#include "runtime.h" - -#include -#include -#include - -extern wasm_rt_memory_t *WASM_MEMORIES[128]; -extern size_t WASM_MEMORIES_N; -extern wasm_rt_externref_table_t *WASM_TABLES[128]; -extern size_t WASM_TABLES_N; - -static size_t bytes_to_wasm_pages(size_t bytes) { - return (bytes + PAGE_SIZE - 1) / PAGE_SIZE; -} - -wasm_rt_externref_t w2c_fixpoint_create_blob_i64(struct w2c_fixpoint *instance, - uint64_t val) { - return (wasm_rt_externref_t)u8x32_from_bytes32(fixpoint_create_blob_i64(val)); -} - -void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t index, - wasm_rt_externref_t handle) { - if (index >= WASM_MEMORIES_N) { - arca_panic("memory index oob"); - } - wasm_rt_memory_t *memory = WASM_MEMORIES[index]; - // `addr` is the beginning address of this wasm memory in the address space - void *addr = (void *)(memory->data); - uint64_t nbytes = fixpoint_attach_blob(addr, bytes32_from_u8x32(handle)); - - size_t npages = bytes_to_wasm_pages(nbytes); - memory->size = nbytes; - memory->pages = npages; - return; -} - -void w2c_fixpoint_attach_tree(struct w2c_fixpoint *instance, uint32_t index, - wasm_rt_externref_t handle) -{ - if (index >= WASM_TABLES_N) { - arca_panic("table index oob"); - } - wasm_rt_externref_table_t *table = WASM_TABLES[index]; - // `addr` is the beginning address of this wasm memory in the address space - void *addr = (void *)(table->data); - uint64_t nelems = fixpoint_attach_tree(addr, bytes32_from_u8x32(handle)); - table->size = nelems; - return; -} - -long check(char *msg, long ret) { - if (ret >= 0) { - return ret; - } - arca_panic(msg); -} diff --git a/fix/fix-shell/runtime.h b/fix/fix-shell/runtime.h deleted file mode 100644 index 4284fa9..0000000 --- a/fix/fix-shell/runtime.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "wasm-rt.h" -#include - -typedef struct w2c_fixpoint w2c_fixpoint; - -// Attach the Blob referred by `handle` to `index`th wasm memory -void w2c_fixpoint_attach_blob(struct w2c_fixpoint *instance, uint32_t index, - wasm_rt_externref_t handle); -// Attach the Tree referred by `handle` to `index`th wasm table -void w2c_fixpoint_attach_tree(struct w2c_fixpoint *instance, uint32_t index, - wasm_rt_externref_t handle); -// Create a Blob with content `val` -wasm_rt_externref_t w2c_fixpoint_create_blob_i64(struct w2c_fixpoint *instance, - uint64_t val); diff --git a/fix/fix-shell/start.S b/fix/fix-shell/start.S deleted file mode 100644 index 1b67c57..0000000 --- a/fix/fix-shell/start.S +++ /dev/null @@ -1,9 +0,0 @@ -.intel_syntax noprefix - -.extern fmain -.extern __stack_top -.globl _start -_start: - lea rsp, __stack_top[rip] - call fmain - int3 diff --git a/fix/fix-shell/wasm-rt-impl.c b/fix/fix-shell/wasm-rt-impl.c deleted file mode 100644 index 3c0aeea..0000000 --- a/fix/fix-shell/wasm-rt-impl.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wasm-rt-impl.h" -#include -#include -#include "wasm-rt.h" - -#include -#include -#include -#include - -wasm_rt_memory_t *WASM_MEMORIES[128]; -size_t WASM_MEMORIES_N = 0; -wasm_rt_externref_table_t *WASM_TABLES[128]; -size_t WASM_TABLES_N = 0; - -long check(char *msg, long ret); -[[noreturn]] void trap(const char *msg); - -void wasm_rt_trap(wasm_rt_trap_t code) { - assert(code != WASM_RT_TRAP_NONE); - switch (code) { - case WASM_RT_TRAP_NONE: - trap("Wasm Runtime Trap: None"); - case WASM_RT_TRAP_OOB: - trap( - "Wasm Runtime Trap: Out-of-bounds access in linear memory or a table."); - case WASM_RT_TRAP_INT_OVERFLOW: - trap("Wasm Runtime Trap: Integer overflow on divide or truncation."); - case WASM_RT_TRAP_DIV_BY_ZERO: - trap("Wasm Runtime Trap: Integer divide by zero"); - case WASM_RT_TRAP_INVALID_CONVERSION: - trap("Wasm Runtime Trap: Conversion from NaN to integer."); - case WASM_RT_TRAP_UNREACHABLE: - trap("Wasm Runtime Trap: Unreachable instruction executed."); - case WASM_RT_TRAP_CALL_INDIRECT: /** Invalid call_indirect, for any reason. - */ - trap("Wasm Runtime Trap: Invalid call_indirect."); - case WASM_RT_TRAP_UNCAUGHT_EXCEPTION: - trap("Wasm Runtime Trap: Exception thrown and not caught."); - case WASM_RT_TRAP_UNALIGNED: - trap("Wasm Runtime Trap: Unaligned atomic instruction executed."); -#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS - case WASM_RT_TRAP_EXHAUSTION = WASM_RT_TRAP_OOB: -#else - case WASM_RT_TRAP_EXHAUSTION: - trap("Wasm Runtime Trap: Call stack exhausted."); -#endif - }; - abort(); -} - -void wasm_rt_init(void) {} - -bool wasm_rt_is_initialized(void) { return true; } - -void wasm_rt_free(void) {} - -void wasm_rt_allocate_memory(wasm_rt_memory_t *memory, uint64_t initial_pages, - uint64_t max_pages, bool is64) { - size_t n = WASM_MEMORIES_N++; - - assert(n < 128); - WASM_MEMORIES[n] = memory; - assert(max_pages <= ((1ul << 32) / PAGE_SIZE)); - - memory->data = (void *)(n << 32); - uint64_t byte_length = initial_pages * PAGE_SIZE; - memory->size = byte_length; - memory->pages = initial_pages; - memory->max_pages = max_pages; - memory->is64 = is64; - - for (uint64_t i = 0; i < byte_length >> 12; i++) { - arcad page = check("arca_page_create", arca_page_create(1 << 12)); - check("arca_mmap", - arca_mmap(memory->data + i * 4096, &(struct arca_entry){ - .mode = __MODE_read_write, - .data = page, - })); - } - return; -} - -uint64_t wasm_rt_grow_memory(wasm_rt_memory_t *memory, uint64_t delta) { - uint64_t old_pages = memory->pages; - uint64_t new_pages = memory->pages + delta; - if (new_pages == 0) { - return 0; - } - if (new_pages < old_pages || new_pages > memory->max_pages) { - return (uint64_t)-1; - } - uint64_t old_size = old_pages * PAGE_SIZE; - uint64_t new_size = new_pages * PAGE_SIZE; - uint64_t delta_size = delta * PAGE_SIZE; - - for (uint64_t i = 0; i < delta_size >> 12; i++) { - arcad page = check("arca_page_create", arca_page_create(1 << 12)); - check("arca_mmap", arca_mmap(memory->data + +memory->size + i * 4096, - &(struct arca_entry){ - .mode = __MODE_read_write, - .data = page, - })); - } - - memory->pages = new_pages; - memory->size = new_size; - return old_pages; -} - -void wasm_rt_free_memory(wasm_rt_memory_t *memory) { return; } - -#define DEFINE_TABLE_OPS(type) \ - void wasm_rt_allocate_##type##_table(wasm_rt_##type##_table_t *table, \ - uint32_t elements, \ - uint32_t max_elements) { \ - abort(); \ - } \ - void wasm_rt_free_##type##_table(wasm_rt_##type##_table_t *table) { \ - abort(); \ - } \ - uint32_t wasm_rt_grow_##type##_table(wasm_rt_##type##_table_t *table, \ - uint32_t delta, \ - wasm_rt_##type##_t init) { \ - abort(); \ - } - -DEFINE_TABLE_OPS(funcref) - -void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t *table, - uint32_t elements, - uint32_t max_elements) { - size_t n = WASM_TABLES_N++; - assert(n < 128); - WASM_TABLES[n] = table; - - if (max_elements > ((1ull << 32) / sizeof(wasm_rt_externref_t)) ) { - max_elements = (1ull << 32) / sizeof(wasm_rt_externref_t); - } - assert(max_elements * sizeof(wasm_rt_externref_t) <= (1ull << 32)); - - // tables are after the memories in the address space - table->data = (void *)((128 + n) << 32); - table->max_size = max_elements; - table->size = elements; - - uint64_t byte_length = elements * sizeof(wasm_rt_externref_t); - uint64_t num_pages = (byte_length + (1ull << 12) - 1) / (1ull << 12); - - for (uint64_t i = 0; i < num_pages; i++) { - arcad page = check("arca_page_create", arca_page_create(1 << 12)); - check("arca_mmap", arca_mmap((uint8_t *)(table->data) + i * 4096, - &(struct arca_entry){ - .mode = __MODE_read_write, - .data = page, - })); - } - return; -} - -void wasm_rt_free_externref_table(wasm_rt_externref_table_t *table) { return; } - -uint32_t wasm_rt_grow_externref_table(wasm_rt_externref_table_t *table, - uint32_t delta, - wasm_rt_externref_t init) { - uint64_t old_elements = table->size; - uint64_t new_elements = old_elements + delta; - if (new_elements == 0) { - return 0; - } - if (new_elements < old_elements || new_elements > table->max_size) { - return (uint32_t)-1; - } - uint64_t old_size = old_elements * sizeof(wasm_rt_externref_t); - uint64_t new_size = new_elements * sizeof(wasm_rt_externref_t); - - uint64_t old_num_pages = (old_size + (1ull << 12) - 1) / (1ull << 12); - uint64_t new_num_pages = (new_size + (1ull << 12) - 1) / (1ull << 12); - - for (uint64_t i = 0; i < new_num_pages - old_num_pages; i++) { - arcad page = check("arca_page_create", arca_page_create(1 << 12)); - check("arca_mmap", - arca_mmap((uint8_t *)(table->data) + old_num_pages * 4096 + i * 4096, - &(struct arca_entry){ - .mode = __MODE_read_write, - .data = page, - })); - } - - table->size = new_elements; - return old_elements; -} - -const char *wasm_rt_strerror(wasm_rt_trap_t trap) { - switch (trap) { - case WASM_RT_TRAP_NONE: - return "No error"; - case WASM_RT_TRAP_OOB: -#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS - return "Out-of-bounds access in linear memory or a table, or call stack " - "exhausted"; -#else - return "Out-of-bounds access in linear memory or a table"; - case WASM_RT_TRAP_EXHAUSTION: - return "Call stack exhausted"; -#endif - case WASM_RT_TRAP_INT_OVERFLOW: - return "Integer overflow on divide or truncation"; - case WASM_RT_TRAP_DIV_BY_ZERO: - return "Integer divide by zero"; - case WASM_RT_TRAP_INVALID_CONVERSION: - return "Conversion from NaN to integer"; - case WASM_RT_TRAP_UNREACHABLE: - return "Unreachable instruction executed"; - case WASM_RT_TRAP_CALL_INDIRECT: - return "Invalid call_indirect or return_call_indirect"; - case WASM_RT_TRAP_UNCAUGHT_EXCEPTION: - return "Uncaught exception"; - case WASM_RT_TRAP_UNALIGNED: - return "Unaligned atomic memory access"; - } - return "invalid trap code"; -} diff --git a/fix/runtime/src/bottom.rs b/fix/runtime/src/bottom.rs index 9221df5..223cdfa 100644 --- a/fix/runtime/src/bottom.rs +++ b/fix/runtime/src/bottom.rs @@ -85,7 +85,9 @@ impl<'a, 'b> FixShellBottom<'a, 'b> { if let Value::Blob(b) = result { return unpack_handle(&b); } else { - let Value::Function(g) = result else { panic!() }; + let Value::Function(g) = result else { + panic!("expected Fix program to return a handle or an effect") + }; let data = g.into_inner().read(); let Value::Tuple(mut data) = data else { unreachable!() diff --git a/fix/shell/Cargo.toml b/fix/shell/Cargo.toml index ebdbfed..81dd06d 100644 --- a/fix/shell/Cargo.toml +++ b/fix/shell/Cargo.toml @@ -18,3 +18,4 @@ fixhandle = { path = "../handle", default-features = false} [build-dependencies] anyhow = "1.0.100" +cc = "1.2.57" diff --git a/fix/shell/build.rs b/fix/shell/build.rs index a2afb2a..6b9af9e 100644 --- a/fix/shell/build.rs +++ b/fix/shell/build.rs @@ -1,6 +1,9 @@ use anyhow::Result; fn main() -> Result<()> { + println!("cargo::rerun-if-changed=etc/memmap.ld"); + let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + println!("cargo::rustc-link-arg=-T{dir}/etc/memmap.ld"); println!("cargo::rustc-link-arg=-no-pie"); Ok(()) } diff --git a/fix/fix-shell/memmap.ld b/fix/shell/etc/memmap.ld similarity index 100% rename from fix/fix-shell/memmap.ld rename to fix/shell/etc/memmap.ld diff --git a/fix/fix-shell/wasm-rt-impl.h b/fix/shell/inc/wasm-rt-impl.h similarity index 100% rename from fix/fix-shell/wasm-rt-impl.h rename to fix/shell/inc/wasm-rt-impl.h diff --git a/fix/fix-shell/wasm-rt.h b/fix/shell/inc/wasm-rt.h similarity index 100% rename from fix/fix-shell/wasm-rt.h rename to fix/shell/inc/wasm-rt.h diff --git a/fix/shell/src/lib.rs b/fix/shell/src/lib.rs index 42ec870..964a130 100644 --- a/fix/shell/src/lib.rs +++ b/fix/shell/src/lib.rs @@ -2,6 +2,49 @@ #![allow(unused)] #![feature(portable_simd)] #![feature(simd_ffi)] +#![feature(slice_from_ptr_range)] + +use core::{arch::global_asm, ops::Range}; + +use user::{error, os}; mod runtime; pub mod shell; + +global_asm!( + r#" +.section .text.start +.extern _rsstart +.extern __stack_top +.globl _start +_start: + lea rsp, __stack_top[rip] + call _rsstart +.halt: + int3 + jmp .halt +"# +); + +unsafe extern "C" { + static mut _sbss: core::ffi::c_void; + static mut _ebss: core::ffi::c_void; +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn _rsstart() -> ! { + unsafe { + let bss = core::slice::from_mut_ptr_range(Range { + start: &raw mut _sbss, + end: &raw mut _ebss, + }); + } + + main(); +} + +pub fn main() -> ! { + let handle = os::argument(); + error::log("within the fix shell"); + os::exit(handle); +} diff --git a/fix/shell/src/start.S b/fix/shell/src/start.S new file mode 100644 index 0000000..f7a90b7 --- /dev/null +++ b/fix/shell/src/start.S @@ -0,0 +1,12 @@ +.intel_syntax noprefix + +.section .text.start +.extern _rsstart +.extern __stack_top +.globl _start +_start: + lea rsp, [__stack_top] + call _rsstart +.halt: + int3 + jmp .halt diff --git a/fix/src/main.rs b/fix/src/main.rs index 018ec7c..7677b7e 100644 --- a/fix/src/main.rs +++ b/fix/src/main.rs @@ -31,18 +31,26 @@ const MODULE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/addblob")); #[kmain] async fn main(_: &[usize]) { - log::info!("running fix kernel"); + log::info!("creating object store"); let mut store = ObjectStore::new(); + log::info!("creating fix runtime"); let mut runtime = FixRuntime::new(&mut store); + log::info!("creating resource limits"); let dummy = runtime.create_blob_i64(0xcafeb0ba); + log::info!("creating function"); let function = runtime.create_blob(BlobData::create(MODULE)); + log::info!("creating addend 1"); let addend1 = runtime.create_blob_i64(7); + log::info!("creating addend 2"); let addend2 = runtime.create_blob_i64(1024); let scratch = vec![dummy, function, addend1, addend2]; + log::info!("creating combination"); let combination = runtime.create_tree(TreeData::create(&scratch)); + log::info!("about to execute combination"); let result = runtime.execute(&combination); + log::info!("result is: {result:?}"); let result_blob = runtime .get_blob(&result) .expect("Add did not return a Blob"); diff --git a/kernel/src/types/runtime.rs b/kernel/src/types/runtime.rs index 691a297..6d19783 100644 --- a/kernel/src/types/runtime.rs +++ b/kernel/src/types/runtime.rs @@ -68,7 +68,6 @@ impl arca::Runtime for Runtime { } fn read_blob(blob: &arca::Blob, offset: usize, buf: &mut [u8]) -> usize { - log::error!("read_blob: offset={}, buf_len={}", offset, buf.len()); let len = core::cmp::min(buf.len(), blob.len() - offset); buf[..len].copy_from_slice(&blob[offset..offset + len]); len