From ae35a3df33f4a04c9db96306e1e32df05920fff9 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:49:17 +0100 Subject: [PATCH 01/18] work towards different thread tables for each target --- src/instructions/control/stop_all.rs | 67 +++++++--- .../event/poll_waiting_threads.rs | 7 +- src/instructions/hq/yield.rs | 24 ++-- src/wasm.rs | 2 +- src/wasm/func.rs | 10 ++ src/wasm/mem_layout.rs | 4 +- src/wasm/project.rs | 12 +- src/wasm/registries.rs | 2 +- src/wasm/registries/globals.rs | 35 ++++++ src/wasm/registries/tables.rs | 116 +++++++++++------- 10 files changed, 185 insertions(+), 94 deletions(-) diff --git a/src/instructions/control/stop_all.rs b/src/instructions/control/stop_all.rs index 3b2ca327..6dc6540a 100644 --- a/src/instructions/control/stop_all.rs +++ b/src/instructions/control/stop_all.rs @@ -1,31 +1,62 @@ -use wasm_encoder::{ConstExpr, HeapType}; +use wasm_encoder::HeapType; use super::super::prelude::*; use crate::instructions_test; -use crate::wasm::{GlobalExportable, GlobalMutable, ThreadsTable}; +use crate::wasm::StepTarget; -pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult> { - let threads_count = func.registries().globals().register( - "threads_count".into(), - ( - ValType::I32, - ConstExpr::i32_const(0), - GlobalMutable(true), - GlobalExportable(true), - ), - )?; - - let threads_table = func.registries().tables().register::()?; - let thread_struct_type = func.registries().types().thread_struct_type()?; - - Ok(wasm![ +fn clear_thread( + threads_count: u32, + threads_table: u32, + thread_struct_type: u32, +) -> Vec { + wasm![ I32Const(0), #LazyGlobalSet(threads_count), I32Const(0), RefNull(HeapType::Concrete(thread_struct_type)), TableSize(threads_table), TableFill(threads_table), - ]) + ] +} + +pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult> { + let thread_struct_type = func.registries().types().thread_struct_type()?; + let total_threads_count = func.registries().globals().threads_count()?; + let num_sprites = func.costume_names().len() as u32; + + Ok(wasm![ + I32Const(0), + #LazyGlobalSet(total_threads_count), + ] + .into_iter() + .chain(clear_thread( + func.registries() + .globals() + .target_threads_count(StepTarget::Stage)?, + func.registries() + .tables() + .threads_table(StepTarget::Stage, func.registries().types())?, + thread_struct_type, + )) + .chain( + (0..num_sprites) + .map(|n| { + let step_target = StepTarget::Sprite(n); + Ok(clear_thread( + func.registries() + .globals() + .target_threads_count(step_target)?, + func.registries() + .tables() + .threads_table(step_target, func.registries().types())?, + thread_struct_type, + )) + }) + .collect::>>()? + .into_iter() + .flatten(), + ) + .collect()) } pub fn acceptable_inputs() -> HQResult> { diff --git a/src/instructions/event/poll_waiting_threads.rs b/src/instructions/event/poll_waiting_threads.rs index 3d8c4b6d..da78001b 100644 --- a/src/instructions/event/poll_waiting_threads.rs +++ b/src/instructions/event/poll_waiting_threads.rs @@ -7,7 +7,7 @@ use wasm_encoder::{BlockType as WasmBlockType, FieldType, HeapType, StorageType}; use super::super::prelude::*; -use crate::wasm::{StepFunc, ThreadsTable}; +use crate::wasm::StepFunc; pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult> { let i32_array_type = func @@ -35,7 +35,10 @@ pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult()?; + let threads_table = func + .registries() + .tables() + .threads_table(func.target(), func.registries().types())?; Ok(wasm![ LocalGet(1), // this should never have additional function arguments so this is fine diff --git a/src/instructions/hq/yield.rs b/src/instructions/hq/yield.rs index 6f04d8de..9c9e0e64 100644 --- a/src/instructions/hq/yield.rs +++ b/src/instructions/hq/yield.rs @@ -1,9 +1,9 @@ -use wasm_encoder::{BlockType, ConstExpr, HeapType}; +use wasm_encoder::{BlockType, HeapType}; use super::super::prelude::*; use crate::instructions_test; use crate::ir::{Step, StepIndex}; -use crate::wasm::{GlobalExportable, GlobalMutable, StepFunc, ThreadsTable}; +use crate::wasm::StepFunc; #[derive(Debug, Clone)] pub enum YieldMode { @@ -55,19 +55,14 @@ pub fn wasm( _inputs: Rc<[IrType]>, Fields { mode: yield_mode }: &Fields, ) -> HQResult> { - let threads_count = func.registries().globals().register( - "threads_count".into(), - ( - ValType::I32, - ConstExpr::i32_const(0), - GlobalMutable(true), - GlobalExportable(true), - ), - )?; + let threads_count = func.registries().globals().threads_count()?; Ok(match yield_mode { YieldMode::None => { - let threads_table = func.registries().tables().register::()?; + let threads_table = func + .registries() + .tables() + .threads_table(func.target(), func.registries().types())?; let thread_struct_ty = func.registries().types().thread_struct_type()?; let stack_array_ty = func.registries().types().stack_array_type()?; let stack_struct_ty = func.registries().types().stack_struct_type()?; @@ -146,7 +141,10 @@ pub fn wasm( func.compile_inner_step(Rc::clone(step))? } YieldMode::Schedule(step_index) => { - let threads_table = func.registries().tables().register::()?; + let threads_table = func + .registries() + .tables() + .threads_table(func.target(), func.registries().types())?; let thread_struct_ty = func.registries().types().thread_struct_type()?; let local = func.local(ValType::Ref(RefType { nullable: false, diff --git a/src/wasm.rs b/src/wasm.rs index 0300dd28..2597e1b8 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -11,5 +11,5 @@ pub use flags::WasmFlags; pub use func::{Instruction as InternalInstruction, StepFunc, StepTarget}; pub use project::{FinishedWasm, WasmProject}; pub use registries::{ - GlobalExportable, GlobalMutable, Registries, StepsTable, StringsTable, ThreadsTable, + GlobalExportable, GlobalMutable, Registries, StringsTable, }; diff --git a/src/wasm/func.rs b/src/wasm/func.rs index 44cfc4f2..b3675747 100644 --- a/src/wasm/func.rs +++ b/src/wasm/func.rs @@ -213,6 +213,16 @@ pub enum StepTarget { Sprite(u32), } +impl StepTarget { + #[must_use] + pub fn suffix_id(&self) -> Cow<'_, str> { + match self { + Self::Stage => "_stage".into(), + Self::Sprite(id) => format!("_{id}").into(), + } + } +} + /// representation of a step's function #[derive(Clone)] pub struct StepFunc { diff --git a/src/wasm/mem_layout.rs b/src/wasm/mem_layout.rs index df8b098f..a25873f2 100644 --- a/src/wasm/mem_layout.rs +++ b/src/wasm/mem_layout.rs @@ -100,8 +100,8 @@ memory_layout! { PEN_DOWN: i8 /// non-zero if sprite is visible, 0 otherwise (i8) VISIBLE: i8 - /// bytes 58-59 padding - _PADDING: i16 + /// sprite layer - 0 is bottom (not including stage! as that is always lowest) + LAYER: i16 /// current costume number, 0-indexed (i32) COSTUME: i32 /// sprite size, where default is 100(%) (f64) diff --git a/src/wasm/project.rs b/src/wasm/project.rs index b3ecb3bf..396894af 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -8,7 +8,7 @@ use wasm_encoder::{ }; use wasm_gen::wasm; -use super::{ExternalEnvironment, GlobalExportable, GlobalMutable, Registries}; +use super::{ExternalEnvironment, Registries}; use crate::ir::{Event, IrProject, IrType, StepIndex}; use crate::prelude::*; use crate::wasm::registries::functions::static_functions::{ @@ -407,15 +407,7 @@ impl WasmProject { N: TryFrom, >::Error: fmt::Debug, { - self.registries().globals().register( - "threads_count".into(), - ( - ValType::I32, - ConstExpr::i32_const(0), - GlobalMutable(true), - GlobalExportable(true), - ), - ) + self.registries().globals().threads_count() } #[expect(clippy::needless_pass_by_value, reason = "annoying to borrow a box")] diff --git a/src/wasm/registries.rs b/src/wasm/registries.rs index b12a1ff5..13e5f801 100644 --- a/src/wasm/registries.rs +++ b/src/wasm/registries.rs @@ -11,7 +11,7 @@ pub use functions::{ExternalFunctionRegistry, StaticFunctionRegistry}; pub use globals::{GlobalExportable, GlobalMutable, GlobalRegistry}; pub use lists::ListRegistry; pub use strings::{StringRegistry, TabledStringRegistry}; -pub use tables::{StepsTable, StringsTable, TableRegistry, ThreadsTable}; +pub use tables::{StringsTable, TableRegistry}; pub use targets::SpriteRegistry; pub use types::TypeRegistry; pub use variables::VariableRegistry; diff --git a/src/wasm/registries/globals.rs b/src/wasm/registries/globals.rs index 77111ae2..aac749c0 100644 --- a/src/wasm/registries/globals.rs +++ b/src/wasm/registries/globals.rs @@ -1,9 +1,11 @@ use core::ops::Deref; +use core::fmt::Display; use wasm_encoder::{ConstExpr, ExportKind, ExportSection, GlobalSection, GlobalType, ValType}; use crate::prelude::*; use crate::registry::MapRegistry; +use crate::wasm::StepTarget; #[derive(Copy, Clone, Debug)] pub struct GlobalMutable(pub bool); @@ -29,6 +31,39 @@ pub type GlobalRegistry = MapRegistry, (ValType, ConstExpr, GlobalMutable, GlobalExportable)>; impl GlobalRegistry { + fn threads_count_with_id(&self, id: S) -> HQResult + where + N: TryFrom, + >::Error: fmt::Debug, + S: Display, + { + self.register( + format!("threads_count{id}").into(), + ( + ValType::I32, + ConstExpr::i32_const(0), + GlobalMutable(true), + GlobalExportable(true), + ), + ) + } + + pub fn threads_count(&self) -> HQResult + where + N: TryFrom, + >::Error: fmt::Debug, + { + self.threads_count_with_id("") + } + + pub fn target_threads_count(&self, target: StepTarget) -> HQResult + where + N: TryFrom, + >::Error: fmt::Debug, + { + self.threads_count_with_id(target.suffix_id()) + } + pub fn finish( self, globals: &mut GlobalSection, diff --git a/src/wasm/registries/tables.rs b/src/wasm/registries/tables.rs index d9158277..fc729975 100644 --- a/src/wasm/registries/tables.rs +++ b/src/wasm/registries/tables.rs @@ -3,6 +3,8 @@ use wasm_encoder::{ }; use crate::prelude::*; +use crate::wasm::StepTarget; +use crate::wasm::registries::TypeRegistry; #[derive(Clone, Debug)] pub struct TableOptions { @@ -22,6 +24,26 @@ impl RegistryType for TableRegistrar { pub type TableRegistry = NamedRegistry; impl TableRegistry { + pub fn threads_table(&self, target: StepTarget, types: &Rc) -> HQResult + where + N: TryFrom, + >::Error: fmt::Debug, + { + self.register_dyn( + format!("threads{}", target.suffix_id()).into(), + TableOptions { + element_type: RefType { + nullable: true, + heap_type: HeapType::Concrete(types.thread_struct_type()?), + }, + min: 0, + max: None, + init: None, + export_name: Some("threads"), + }, + ) + } + pub fn finish(self, tables: &mut TableSection, exports: &mut ExportSection) { for ( _key, @@ -73,51 +95,51 @@ impl NamedRegistryItem for StringsTable { }; } -pub struct StepsTable; -impl NamedRegistryItem for StepsTable { - const VALUE: TableOptions = TableOptions { - element_type: RefType::FUNCREF, - min: 0, - max: None, - init: None, - export_name: None, - }; -} -impl NamedRegistryItemOverride for StepsTable { - fn r#override(step_count: u64) -> TableOptions { - TableOptions { - element_type: RefType::FUNCREF, - min: step_count, - max: Some(step_count), - init: None, - export_name: None, - } - } -} +// pub struct StepsTable; +// impl NamedRegistryItem for StepsTable { +// const VALUE: TableOptions = TableOptions { +// element_type: RefType::FUNCREF, +// min: 0, +// max: None, +// init: None, +// export_name: None, +// }; +// } +// impl NamedRegistryItemOverride for StepsTable { +// fn r#override(step_count: u64) -> TableOptions { +// TableOptions { +// element_type: RefType::FUNCREF, +// min: step_count, +// max: Some(step_count), +// init: None, +// export_name: None, +// } +// } +// } -pub struct ThreadsTable; -impl NamedRegistryItem for ThreadsTable { - const VALUE: TableOptions = TableOptions { - element_type: RefType::ARRAYREF, - min: 0, - max: None, - init: None, - export_name: Some("threads"), - }; -} -impl NamedRegistryItemOverride for ThreadsTable { - fn r#override(stack_struct_ty: u32) -> TableOptions { - // todo: if we don't need any stacks (i.e. no non-warped procedure, no broadcast & wait), - // revert to old behaviour and just store funcrefs (noop for null). - TableOptions { - element_type: RefType { - nullable: true, - heap_type: HeapType::Concrete(stack_struct_ty), - }, - min: 0, - max: None, - init: None, - export_name: Some("threads"), - } - } -} +// pub struct ThreadsTable; +// impl NamedRegistryItem for ThreadsTable { +// const VALUE: TableOptions = TableOptions { +// element_type: RefType::ARRAYREF, +// min: 0, +// max: None, +// init: None, +// export_name: Some("threads"), +// }; +// } +// impl NamedRegistryItemOverride for ThreadsTable { +// fn r#override(stack_struct_ty: u32) -> TableOptions { +// // todo: if we don't need any stacks (i.e. no non-warped procedure, no broadcast & wait), +// // revert to old behaviour and just store funcrefs (noop for null). +// TableOptions { +// element_type: RefType { +// nullable: true, +// heap_type: HeapType::Concrete(stack_struct_ty), +// }, +// min: 0, +// max: None, +// init: None, +// export_name: Some("threads"), +// } +// } +// } From 18dfea49d8601faee6a2b2a8e19158ee4a7507f3 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Fri, 14 Aug 2026 20:44:06 +0100 Subject: [PATCH 02/18] progress? --- src/wasm/project.rs | 18 ++--- .../registries/functions/spawn_threads.rs | 76 +++++++++++-------- src/wasm/registries/globals.rs | 57 ++++++++++---- src/wasm/registries/types.rs | 76 +++++++++++++++---- 4 files changed, 153 insertions(+), 74 deletions(-) diff --git a/src/wasm/project.rs b/src/wasm/project.rs index 396894af..e84f518d 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -14,7 +14,7 @@ use crate::prelude::*; use crate::wasm::registries::functions::static_functions::{ MarkWaitingFlag, SpawnNewThread, SpawnThreadInStack, }; -use crate::wasm::{StepFunc, StringsTable, ThreadsTable, WasmFlags}; +use crate::wasm::{StepFunc, StepTarget, StringsTable, WasmFlags}; /// A respresentation of a WASM representation of a project. Cannot be created directly; /// use `TryFrom`. @@ -139,7 +139,7 @@ impl WasmProject { self.registries() .static_functions() .register_override::(( - self.registries().types().step_func_type()?, + self.registries().types().step_func()?, self.registries().types().stack_struct_type()?, self.registries().types().stack_array_type()?, self.registries().types().thread_struct_type()?, @@ -149,7 +149,7 @@ impl WasmProject { self.registries() .static_functions() .register_override::(( - self.registries().types().step_func_type()?, + self.registries().types().step_func()?, self.registries().types().stack_struct_type()?, self.registries().types().stack_array_type()?, self.registries().types().thread_struct_type()?, @@ -202,12 +202,6 @@ impl WasmProject { function_index: self.imported_func_count()? + functions.len() - 1, }; - self.registries() - .tables() - .register_override::( - self.registries().types().thread_struct_type()?, - )?; - elements.declared(Elements::Functions( (self.imported_func_count()? + self.static_func_count()? ..self.imported_func_count()? @@ -374,12 +368,12 @@ impl WasmProject { Ok(()) } - fn threads_table_index(&self) -> HQResult + fn threads_table_index(&self, target: StepTarget) -> HQResult where N: TryFrom, >::Error: fmt::Debug, { - self.registries().tables().register::() + self.registries().tables().threads_table(target, self.registries().types()) } fn spawn_new_thread_func(&self) -> HQResult @@ -620,7 +614,7 @@ impl WasmProject { ), ]); - let step_func_ty = self.registries().types().step_func_type()?; + let step_func_ty = self.registries().types().step_func()?; let stack_array_ty = self.registries().types().stack_array_type()?; let instructions = wasm![ diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index b10185c2..f8fa5a27 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -127,16 +127,17 @@ impl NamedRegistryItemOverride /// Spawn a new thread with the provided step function. This does not call it /// immediately, instead leaving that for the scheduler or calling function to do so. /// -/// Takes 2 parameters: -/// - step funcref - the step to spawn +/// Takes 3 parameters: +/// - step funcref - the step to spawn /// - ref null struct - the stack struct to spawn it with +/// - i32 - the index of the sprite to spawn a thread for, or -1 for the stage /// /// Override with: /// - u32 - the index of the step func type /// - u32 - the index of the stack struct type /// - u32 - the index of the stack array type /// - u32 - the index of the thread struct type -/// - u32 - the index of the threads table +/// - u32 - the index of the threads array pub struct SpawnNewThread; impl NamedRegistryItem for SpawnNewThread { const VALUE: MaybeStaticFunction = MaybeStaticFunction { @@ -144,10 +145,25 @@ impl NamedRegistryItem for SpawnNewThread { maybe_populate: || None, }; } -pub type SpawnNewThreadOverride = (u32, u32, u32, u32, u32); +pub struct SpawnNewThreadOverride { + func_ty: u32, + stack_struct_ty: u32, + stack_array_ty: u32, + thread_struct_ty: u32, + threads_array_index: u32, + threads_array_ty: u32, +} + impl NamedRegistryItemOverride for SpawnNewThread { fn r#override( - (func_ty, stack_struct_ty, stack_array_ty, thread_struct_ty, threads_table_index): SpawnNewThreadOverride, + SpawnNewThreadOverride { + func_ty, + stack_struct_ty, + stack_array_ty, + thread_struct_ty, + threads_array_index, + threads_array_ty, + }: SpawnNewThreadOverride, ) -> MaybeStaticFunction { MaybeStaticFunction { static_function: Some(StaticFunction { @@ -166,31 +182,31 @@ impl NamedRegistryItemOverride for }), ]), returns: Box::from([]), - locals: Box::from([]), - instructions: (wasm_const![ - I32Const(1), - LocalGet(0), - LocalGet(1), - StructNew(stack_struct_ty), - // todo: play around with initial size of stack array - RefNull(HeapType::Concrete(stack_struct_ty)), - RefNull(HeapType::Concrete(stack_struct_ty)), - RefNull(HeapType::Concrete(stack_struct_ty)), - RefNull(HeapType::Concrete(stack_struct_ty)), - RefNull(HeapType::Concrete(stack_struct_ty)), - RefNull(HeapType::Concrete(stack_struct_ty)), - RefNull(HeapType::Concrete(stack_struct_ty)), - ArrayNewFixed { - array_size: 8, - array_type_index: stack_array_ty, - }, - StructNew(thread_struct_ty), - I32Const(1), - TableGrow(threads_table_index), - Drop, - End, - ] as &[_]) - .into(), + locals: Box::from([ValType::Ref(RefType { + nullable: false, + heap_type: HeapType::Concrete(stack_array_ty), + })]), + instructions: { + const STACK_ARRAY_LOCAL: u32 = 3; + (wasm_const![ + // TODO get + I32Const(1), // stack size + // todo: play around with initial size of stack array + I32Const(8), + ArrayNewDefault(stack_array_ty), + LocalTee(STACK_ARRAY_LOCAL), + StructNew(thread_struct_ty), + I32Const(0), // index 0 into stack array + I32Const(1), // stack size + LocalGet(0), // step func + LocalGet(1), // stack struct param + StructNew(stack_struct_ty), // stack struct + ArraySet(stack_array_ty), // set 0th element of stack array to stack struct + ArraySet(threads_array_ty), + End, + ] as &[_]) + .into() + }, }), maybe_populate: || None, } diff --git a/src/wasm/registries/globals.rs b/src/wasm/registries/globals.rs index aac749c0..ef117a9e 100644 --- a/src/wasm/registries/globals.rs +++ b/src/wasm/registries/globals.rs @@ -1,11 +1,13 @@ use core::ops::Deref; -use core::fmt::Display; -use wasm_encoder::{ConstExpr, ExportKind, ExportSection, GlobalSection, GlobalType, ValType}; +use wasm_encoder::{ + ConstExpr, ExportKind, ExportSection, GlobalSection, GlobalType, Instruction, + RefType, ValType, +}; use crate::prelude::*; use crate::registry::MapRegistry; -use crate::wasm::StepTarget; +use crate::wasm::registries::TypeRegistry; #[derive(Copy, Clone, Debug)] pub struct GlobalMutable(pub bool); @@ -31,14 +33,13 @@ pub type GlobalRegistry = MapRegistry, (ValType, ConstExpr, GlobalMutable, GlobalExportable)>; impl GlobalRegistry { - fn threads_count_with_id(&self, id: S) -> HQResult + pub fn threads_count(&self) -> HQResult where N: TryFrom, >::Error: fmt::Debug, - S: Display, { self.register( - format!("threads_count{id}").into(), + "threads_count".into(), ( ValType::I32, ConstExpr::i32_const(0), @@ -48,20 +49,44 @@ impl GlobalRegistry { ) } - pub fn threads_count(&self) -> HQResult + // threadss isn't a typo here - using the Haskell convention of adding extra s's to + // the end of identifiers for nested lists + pub fn threadss(&self, types: &Rc, num_sprites: u32) -> HQResult where N: TryFrom, >::Error: fmt::Debug, { - self.threads_count_with_id("") - } - - pub fn target_threads_count(&self, target: StepTarget) -> HQResult - where - N: TryFrom, - >::Error: fmt::Debug, - { - self.threads_count_with_id(target.suffix_id()) + let array_array_type = types.thread_list_array_type()?; + let array_type = types.thread_array_type()?; + self.register( + "threadss".into(), + ( + ValType::Ref(RefType { + nullable: false, + heap_type: wasm_encoder::HeapType::Concrete(array_array_type), + }), + ConstExpr::extended( + (0..num_sprites) + .map(|i| { + [ + Instruction::I32Const(i as i32), + Instruction::I32Const(0), + Instruction::ArrayNewFixed { + array_type_index: array_type, + array_size: 0, + }, + ] + }) + .flatten() + .chain([Instruction::ArrayNewFixed { + array_type_index: array_array_type, + array_size: num_sprites, + }]), + ), // TODO: initialise properly + GlobalMutable(true), + GlobalExportable(false), + ), + ) } pub fn finish( diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index 4cee021d..2e7c045a 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -49,17 +49,37 @@ impl TypeRegistry { }, }); - pub fn step_func_type(&self) -> HQResult { + pub fn step_func(&self) -> HQResult { self.function(vec![ValType::I32, Self::STRUCT_REF], vec![]) } + pub fn dyn_array_container(&self, field: ValType) -> HQResult { + let arr_type = self.array(StorageType::Val(field), true)?; + self.struct_(vec![FieldType { + element_type: Self::ref_storage(arr_type, false), + mutable: true, + }]) + } + + pub fn ref_(heap_type: u32, nullable: bool) -> RefType { + RefType { + nullable, + heap_type: HeapType::Concrete(heap_type), + } + } + + pub fn ref_val(heap_type: u32, nullable: bool) -> ValType { + ValType::Ref(Self::ref_(heap_type, nullable)) + } + + pub fn ref_storage(heap_type: u32, nullable: bool) -> StorageType { + StorageType::Val(Self::ref_val(heap_type, nullable)) + } + pub fn stack_struct_type(&self) -> HQResult { self.struct_(vec![ FieldType { - element_type: StorageType::Val(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(self.step_func_type()?), - })), + element_type: Self::ref_storage(self.step_func()?, false), mutable: true, }, FieldType { @@ -70,13 +90,7 @@ impl TypeRegistry { } pub fn stack_array_type(&self) -> HQResult { - self.array( - StorageType::Val(ValType::Ref(RefType { - nullable: true, - heap_type: HeapType::Concrete(self.stack_struct_type()?), - })), - true, - ) + self.array(Self::ref_storage(self.stack_struct_type()?, true), true) } pub fn thread_struct_type(&self) -> HQResult { @@ -86,15 +100,45 @@ impl TypeRegistry { mutable: true, }, FieldType { - element_type: StorageType::Val(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(self.stack_array_type()?), - })), + element_type: Self::ref_storage(self.stack_array_type()?, false), + mutable: true, + }, + ]) + } + + pub fn thread_array_type(&self) -> HQResult { + self.array(Self::ref_storage(self.thread_struct_type()?, true), true) + } + + pub fn thread_list_struct_type(&self) -> HQResult { + self.struct_(vec![ + // target index + FieldType { + element_type: StorageType::Val(ValType::I32), + mutable: true, + }, + // number of threads + FieldType { + element_type: StorageType::Val(ValType::I32), + mutable: true, + }, + FieldType { + element_type: Self::ref_storage(self.thread_array_type()?, false), mutable: true, }, ]) } + pub fn thread_list_array_type(&self) -> HQResult { + self.array( + StorageType::Val(ValType::Ref(RefType { + nullable: true, + heap_type: HeapType::Concrete(self.thread_list_struct_type()?), + })), + true, + ) + } + pub fn proc_arg_struct_type( &self, arg_vars: &core::cell::Ref<'_, Vec>, From 0c0d9d96a35b089e6c82a937b5719c3a1ad1d4fa Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish10107@users.noreply.github.com> Date: Sun, 16 Aug 2026 20:24:40 +0100 Subject: [PATCH 03/18] start working on types in the type system --- src/registry.rs | 43 ++++++++------ src/wasm/registries/functions.rs | 1 + src/wasm/registries/types.rs | 97 +++++++++++++++++++++++++++++--- 3 files changed, 116 insertions(+), 25 deletions(-) diff --git a/src/registry.rs b/src/registry.rs index 69f8312b..29a6da20 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -2,6 +2,13 @@ use core::hash::Hash; use crate::prelude::*; +pub trait RegistryResult: TryFrom {} + +impl RegistryResult for N +where + N: TryFrom, +{} + #[derive(Clone)] pub struct MapRegistry(RefCell>) where @@ -70,6 +77,10 @@ pub trait RegistryType { type Value; } +pub trait CompTimeRegistrand { + fn register(registry: &R) -> HQResult; +} + pub trait Registry: Sized + RegistryType { fn registry(&self) -> &RefCell>; @@ -79,8 +90,7 @@ pub trait Registry: Sized + RegistryType { /// the casting logic in here. fn register(&self, key: Self::Key, value: Self::Value) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, { self.registry() .try_borrow_mut() @@ -98,8 +108,7 @@ pub trait Registry: Sized + RegistryType { fn register_override(&self, key: Self::Key, value: Self::Value) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, { self.registry() .try_borrow_mut() @@ -115,6 +124,14 @@ pub trait Registry: Sized + RegistryType { .map_err(|_| make_hq_bug!("registry item index out of bounds")) } + fn register_comp(&self) -> HQResult + where + R: CompTimeRegistrand, + N: RegistryResult + { + R::register(self) + } + // TODO: register_override_ifexists or similar - for things like mark_waiting_flag, // which need to be overriden if they are registered, but don't actually need to be // registered always. @@ -123,8 +140,7 @@ pub trait Registry: Sized + RegistryType { pub trait RegistryDefault: Registry { fn register_default(&self, key: Self::Key) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, { self.register(key, Self::Value::default()) } @@ -234,8 +250,7 @@ where /// Registers a `NamedRegistryItem` using its key function and its `const VALUE` pub fn register(&self) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, T: NamedRegistryItem, { self.0.register(R::name::(), T::VALUE) @@ -245,8 +260,7 @@ where /// `Registry` pub fn register_dyn(&self, key: R::Key, value: R::Value) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, { self.0.register(key, value) } @@ -255,8 +269,7 @@ where /// `register_override` on the underlying `Registry` pub fn register_dyn_override(&self, key: R::Key, value: R::Value) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, { self.0.register_override(key, value) } @@ -265,8 +278,7 @@ where /// associated with the corresponding `NamedRegistryItemOverride` pub fn register_override(&self, override_arg: A) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, T: NamedRegistryItem + NamedRegistryItemOverride, { self.0 @@ -277,8 +289,7 @@ where /// types associated with the corresponding `TryNamedRegistryItemOverride` pub fn try_register_override(&self, override_arg: A) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, T: NamedRegistryItem + TryNamedRegistryItemOverride, { self.0 diff --git a/src/wasm/registries/functions.rs b/src/wasm/registries/functions.rs index 72f487b4..93bd0cb9 100644 --- a/src/wasm/registries/functions.rs +++ b/src/wasm/registries/functions.rs @@ -1,5 +1,6 @@ #![allow(clippy::cast_possible_wrap, reason = "can't use try_into in const")] +mod dyn_array; mod mark_waiting_flag; mod pen_colour; mod spawn_threads; diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index 2e7c045a..a88f3474 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -2,19 +2,21 @@ use wasm_encoder::{ AbstractHeapType, FieldType, HeapType, RefType, StorageType, TypeSection, ValType, }; +use core::marker::PhantomData; + use crate::ir::RcVar; use crate::prelude::*; -use crate::registry::SetRegistry; +use crate::registry::{CompTimeRegistrand, RegistryResult, SetRegistry}; use crate::wasm::WasmProject; #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum WasmType { +pub enum CompoundType { Function(Vec, Vec), Array(StorageType, bool), Struct(Vec), } -pub type TypeRegistry = SetRegistry; +pub type TypeRegistry = SetRegistry; impl TypeRegistry { pub fn function(&self, params: Vec, returns: Vec) -> HQResult @@ -22,7 +24,7 @@ impl TypeRegistry { N: TryFrom, >::Error: fmt::Debug, { - self.register_default(WasmType::Function(params, returns)) + self.register_default(CompoundType::Function(params, returns)) } pub fn array(&self, elem_type: StorageType, mutable: bool) -> HQResult @@ -30,7 +32,7 @@ impl TypeRegistry { N: TryFrom, >::Error: fmt::Debug, { - self.register_default(WasmType::Array(elem_type, mutable)) + self.register_default(CompoundType::Array(elem_type, mutable)) } pub fn struct_(&self, fields: Vec) -> HQResult @@ -38,7 +40,7 @@ impl TypeRegistry { N: TryFrom, >::Error: fmt::Debug, { - self.register_default(WasmType::Struct(fields)) + self.register_default(CompoundType::Struct(fields)) } pub const STRUCT_REF: ValType = ValType::Ref(RefType { @@ -161,10 +163,87 @@ impl TypeRegistry { pub fn finish(self, types: &mut TypeSection) { for ty in self.registry().take().keys().cloned() { match ty { - WasmType::Function(params, results) => types.ty().function(params, results), - WasmType::Array(elem_type, mutable) => types.ty().array(&elem_type, mutable), - WasmType::Struct(fields) => types.ty().struct_(fields), + CompoundType::Function(params, results) => types.ty().function(params, results), + CompoundType::Array(elem_type, mutable) => types.ty().array(&elem_type, mutable), + CompoundType::Struct(fields) => types.ty().struct_(fields), } } } } + +pub trait THeapType: CompTimeRegistrand {} +impl THeapType for T where T: CompTimeRegistrand {} + +pub trait TRefType { + type HeapType: THeapType; + const NULLABLE: bool; +} + +pub struct TNullable(PhantomData); + +pub struct TNonNullable(PhantomData); + +impl TRefType for TNullable where T: THeapType { + type HeapType = T; + const NULLABLE: bool = true; +} + +impl TRefType for TNonNullable where T: THeapType { + type HeapType = T; + const NULLABLE: bool = true; +} + +pub trait TValType { + fn val_type(types: &TypeRegistry) -> ValType; +} + +pub struct DynArray(PhantomData); + +impl CompTimeRegistrand for DynArray where T: TRefType { + fn register(types: &TypeRegistry) -> HQResult { + types.dyn_array_container( + TypeRegistry::ref_val( + T::HeapType::register(types)?, + T::NULLABLE, + ) + ) + } +} + +pub trait TFieldType { + type ValType: TValType; + const MUTABLE: bool; +} + +trait CompTypeList { + fn fields(types: &TypeRegistry) -> Vec; +} + +impl CompTypeList for () { + fn fields(_: &TypeRegistry) -> Vec { + vec![] + } +} + +impl CompTypeList for (Head, Tail) where Head: CompTypeList, Tail: TFieldType { + fn fields(types: &TypeRegistry) -> Vec { + let mut fields = Head::fields(types); + fields.push( + FieldType { + mutable: Tail::MUTABLE, + element_type: StorageType::Val(Tail::ValType::val_type(types)), + } + ); + fields + } +} + +struct TStruct(PhantomData); + +impl CompTimeRegistrand for TStruct where Fields: CompTypeList { + fn register(types: &TypeRegistry) -> HQResult { + types.struct_( + Fields::fields(types) + ) + } +} From 09d1df671ce3c8cfd518e04be90822c492afc726 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish10107@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:23:41 +0100 Subject: [PATCH 04/18] more type system types and start implementing dyn_array funcs --- src/wasm/registries/functions/dyn_array.rs | 108 +++++++++++++++++++++ src/wasm/registries/types.rs | 74 ++++++++++---- 2 files changed, 163 insertions(+), 19 deletions(-) create mode 100644 src/wasm/registries/functions/dyn_array.rs diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs new file mode 100644 index 00000000..70f73deb --- /dev/null +++ b/src/wasm/registries/functions/dyn_array.rs @@ -0,0 +1,108 @@ + +use wasm_encoder::{BlockType as WasmBlockType, ValType}; +use wasm_gen::wasm_const; + +use core::marker::PhantomData; + +use super::{MaybeStaticFunction, StaticFunction}; +use crate::{prelude::*, wasm::registries::{TypeRegistry, types::{TDynArray, TDynArrayField, TValType}}}; + +/// Pushes an element to a dynamic (resizeable) array +/// +/// Takes 2 parameters: +/// ref dynamic_array - the array +/// t - the element +pub struct DynArrayPush(PhantomData); +impl NamedRegistryItem for DynArrayPush { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + maybe_populate: || None, + }; +} + +pub struct DynArrayPushOverride { + types: Rc, +} + +impl TryNamedRegistryItemOverride + for DynArrayPush +{ + fn try_override( + DynArrayPushOverride { types }: DynArrayPushOverride, + ) -> HQResult { + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(MaybeStaticFunction { + static_function: Some(StaticFunction { + export: None, + instructions: Box::from(wasm_const![ + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 0, + }, + ArrayLen, + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 1, + }, + LocalTee(2), + I32Eq, + If(WasmBlockType::Empty), + LocalGet(2), + I32Const(1), + I32Shl, + ArrayNewDefault(array_type), // dest + LocalTee(3), + I32Const(0), // dest index + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 0, + }, // src + I32Const(0), // src index + LocalGet(2), // length + ArrayCopy { + array_type_index_dst: array_type, + array_type_index_src: array_type, + }, + LocalGet(0), + LocalGet(3), + StructSet { + struct_type_index: struct_type, + field_index: 0, + }, + End, + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 0, + }, + LocalGet(2), + LocalGet(1), + ArraySet(array_type), + LocalGet(0), + LocalGet(2), + I32Const(1), + I32Add, + StructSet { + struct_type_index: struct_type, + field_index: 1, + }, + ] as &[_]), + params: Box::from([ + TypeRegistry::ref_val(struct_type, false), + T::val_type(&types)?, + ]), + returns: Box::from([]), + locals: Box::from([ + ValType::I32, + TypeRegistry::ref_val(array_type, false), + ]), + }), + maybe_populate: || None, + }) + } +} + diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index a88f3474..856a122a 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -187,6 +187,7 @@ impl TRefType for TNullable where T: THeapType { type HeapType = T; const NULLABLE: bool = true; } +impl TDefaultable for TNullable {} impl TRefType for TNonNullable where T: THeapType { type HeapType = T; @@ -194,56 +195,91 @@ impl TRefType for TNonNullable where T: THeapType { } pub trait TValType { - fn val_type(types: &TypeRegistry) -> ValType; + fn val_type(types: &TypeRegistry) -> HQResult; } -pub struct DynArray(PhantomData); +impl TValType for T where T: TRefType { + fn val_type(types: &TypeRegistry) -> HQResult { + Ok(TypeRegistry::ref_val( + T::HeapType::register(types)?, + T::NULLABLE, + )) + } +} -impl CompTimeRegistrand for DynArray where T: TRefType { - fn register(types: &TypeRegistry) -> HQResult { - types.dyn_array_container( - TypeRegistry::ref_val( - T::HeapType::register(types)?, - T::NULLABLE, - ) - ) +pub struct TI32; + +impl TValType for TI32 { + fn val_type(types: &TypeRegistry) -> HQResult { + Ok(ValType::I32) } } +impl TDefaultable for TI32 {} pub trait TFieldType { type ValType: TValType; const MUTABLE: bool; } +pub struct TMutField(PhantomData); +pub struct TConstField(PhantomData); + +impl TFieldType for TMutField { + type ValType = T; + const MUTABLE: bool = true; +} + +impl TFieldType for TConstField { + type ValType = T; + const MUTABLE: bool = false; +} + +pub trait TDefaultable: TValType {} + + trait CompTypeList { - fn fields(types: &TypeRegistry) -> Vec; + fn fields(types: &TypeRegistry) -> HQResult>; } impl CompTypeList for () { - fn fields(_: &TypeRegistry) -> Vec { - vec![] + fn fields(_: &TypeRegistry) -> HQResult> { + Ok(vec![]) } } impl CompTypeList for (Head, Tail) where Head: CompTypeList, Tail: TFieldType { - fn fields(types: &TypeRegistry) -> Vec { - let mut fields = Head::fields(types); + fn fields(types: &TypeRegistry) -> HQResult> { + let mut fields = Head::fields(types)?; fields.push( FieldType { mutable: Tail::MUTABLE, - element_type: StorageType::Val(Tail::ValType::val_type(types)), + element_type: StorageType::Val(Tail::ValType::val_type(types)?), } ); - fields + Ok(fields) } } -struct TStruct(PhantomData); +pub struct TStruct(PhantomData); impl CompTimeRegistrand for TStruct where Fields: CompTypeList { fn register(types: &TypeRegistry) -> HQResult { types.struct_( - Fields::fields(types) + Fields::fields(types)? ) } } + +pub struct TArray(PhantomData); + +impl CompTimeRegistrand for TArray { + fn register(types: &TypeRegistry) -> HQResult { + types.array( + StorageType::Val(Field::ValType::val_type(types)?), + Field::MUTABLE, + ) + } +} + +pub type TDynArrayField = TArray>; +pub type TDynArray = TStruct<(((), TMutField>>), TMutField)>; From b2faa61fc1f295445e703e757d5b286a0aa39fdf Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Wed, 19 Aug 2026 23:52:10 +0100 Subject: [PATCH 05/18] rewrite `SpawnNewThreadInStack` with new dyn arrays + threadss array global --- src/instructions/hq/yield.rs | 3 +- src/instructions/procedures/call_nonwarp.rs | 3 +- src/registry.rs | 7 +- src/wasm.rs | 4 +- src/wasm/mem_layout.rs | 2 +- src/wasm/project.rs | 13 +- src/wasm/registries/functions.rs | 2 +- src/wasm/registries/functions/dyn_array.rs | 173 +++++++++--- .../registries/functions/spawn_threads.rs | 161 ++++++----- src/wasm/registries/globals.rs | 13 +- src/wasm/registries/tables.rs | 3 +- src/wasm/registries/types.rs | 253 +++++++++--------- 12 files changed, 365 insertions(+), 272 deletions(-) diff --git a/src/instructions/hq/yield.rs b/src/instructions/hq/yield.rs index 9c9e0e64..b2f65d24 100644 --- a/src/instructions/hq/yield.rs +++ b/src/instructions/hq/yield.rs @@ -4,6 +4,7 @@ use super::super::prelude::*; use crate::instructions_test; use crate::ir::{Step, StepIndex}; use crate::wasm::StepFunc; +use crate::wasm::registries::types::TStepFunc; #[derive(Debug, Clone)] pub enum YieldMode { @@ -75,7 +76,7 @@ pub fn wasm( heap_type: HeapType::Concrete(stack_struct_ty), }))?; let i32_local = func.local(ValType::I32)?; - let step_func_ty = func.registries().types().step_func_type()?; + let step_func_ty = func.registries().types().register_comp::()?; func.free_local(thread_struct_local)?; func.free_local(stack_struct_local)?; func.free_local(i32_local)?; diff --git a/src/instructions/procedures/call_nonwarp.rs b/src/instructions/procedures/call_nonwarp.rs index 54347734..231d7f90 100644 --- a/src/instructions/procedures/call_nonwarp.rs +++ b/src/instructions/procedures/call_nonwarp.rs @@ -4,6 +4,7 @@ use super::super::prelude::*; use crate::instructions_test; use crate::ir::{Proc, StepIndex}; use crate::wasm::registries::functions::static_functions::SpawnThreadInStack; +use crate::wasm::registries::types::TStepFunc; use crate::wasm::{StepFunc, WasmProject}; #[derive(Clone, Debug)] @@ -102,7 +103,7 @@ pub fn wasm( LocalGet((func.params().len() - 2).try_into().map_err(|_| make_hq_bug!("local index out of bounds"))?), LocalGet(arg_struct_local), #LazyNonWarpedProcRef(Rc::clone(proc)), - ReturnCallRef(func.registries().types().step_func_type()?) + ReturnCallRef(func.registries().types().register_comp::()?) ]); Ok(wasm) diff --git a/src/registry.rs b/src/registry.rs index 29a6da20..1b992bc2 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -4,10 +4,7 @@ use crate::prelude::*; pub trait RegistryResult: TryFrom {} -impl RegistryResult for N -where - N: TryFrom, -{} +impl RegistryResult for N where N: TryFrom {} #[derive(Clone)] pub struct MapRegistry(RefCell>) @@ -127,7 +124,7 @@ pub trait Registry: Sized + RegistryType { fn register_comp(&self) -> HQResult where R: CompTimeRegistrand, - N: RegistryResult + N: RegistryResult, { R::register(self) } diff --git a/src/wasm.rs b/src/wasm.rs index 2597e1b8..d1727632 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -10,6 +10,4 @@ pub use external::ExternalEnvironment; pub use flags::WasmFlags; pub use func::{Instruction as InternalInstruction, StepFunc, StepTarget}; pub use project::{FinishedWasm, WasmProject}; -pub use registries::{ - GlobalExportable, GlobalMutable, Registries, StringsTable, -}; +pub use registries::{GlobalExportable, GlobalMutable, Registries, StringsTable}; diff --git a/src/wasm/mem_layout.rs b/src/wasm/mem_layout.rs index a25873f2..11693863 100644 --- a/src/wasm/mem_layout.rs +++ b/src/wasm/mem_layout.rs @@ -100,7 +100,7 @@ memory_layout! { PEN_DOWN: i8 /// non-zero if sprite is visible, 0 otherwise (i8) VISIBLE: i8 - /// sprite layer - 0 is bottom (not including stage! as that is always lowest) + /// sprite layer - 0 is bottom (not including stage! as that is always lowest) (i16) LAYER: i16 /// current costume number, 0-indexed (i32) COSTUME: i32 diff --git a/src/wasm/project.rs b/src/wasm/project.rs index e84f518d..fae3c2d7 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -14,6 +14,7 @@ use crate::prelude::*; use crate::wasm::registries::functions::static_functions::{ MarkWaitingFlag, SpawnNewThread, SpawnThreadInStack, }; +use crate::wasm::registries::types::{TStackStruct, TStepFunc}; use crate::wasm::{StepFunc, StepTarget, StringsTable, WasmFlags}; /// A respresentation of a WASM representation of a project. Cannot be created directly; @@ -139,8 +140,8 @@ impl WasmProject { self.registries() .static_functions() .register_override::(( - self.registries().types().step_func()?, - self.registries().types().stack_struct_type()?, + self.registries().types().register_comp::()?, + self.registries().types().register_comp::()?, self.registries().types().stack_array_type()?, self.registries().types().thread_struct_type()?, self.threads_table_index()?, @@ -149,8 +150,8 @@ impl WasmProject { self.registries() .static_functions() .register_override::(( - self.registries().types().step_func()?, - self.registries().types().stack_struct_type()?, + self.registries().types().register_comp::()?, + self.registries().types().register_comp::()?, self.registries().types().stack_array_type()?, self.registries().types().thread_struct_type()?, self.threads_table_index()?, @@ -373,7 +374,9 @@ impl WasmProject { N: TryFrom, >::Error: fmt::Debug, { - self.registries().tables().threads_table(target, self.registries().types()) + self.registries() + .tables() + .threads_table(target, self.registries().types()) } fn spawn_new_thread_func(&self) -> HQResult diff --git a/src/wasm/registries/functions.rs b/src/wasm/registries/functions.rs index 93bd0cb9..1a4e57b7 100644 --- a/src/wasm/registries/functions.rs +++ b/src/wasm/registries/functions.rs @@ -110,6 +110,6 @@ pub mod static_functions { pub use super::mark_waiting_flag::MarkWaitingFlag; pub use super::pen_colour::{UpdatePenColorFromHSV, UpdatePenColorFromRGB}; pub use super::spawn_threads::{ - SpawnNewThread, SpawnNewThreadOverride, SpawnThreadInStack, SpawnThreadInStackOverride, + SpawnNewThread, SpawnNewThreadOverride, SpawnThreadInStack, }; } diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs index 70f73deb..6d174814 100644 --- a/src/wasm/registries/functions/dyn_array.rs +++ b/src/wasm/registries/functions/dyn_array.rs @@ -1,16 +1,21 @@ +use core::marker::PhantomData; use wasm_encoder::{BlockType as WasmBlockType, ValType}; use wasm_gen::wasm_const; -use core::marker::PhantomData; - use super::{MaybeStaticFunction, StaticFunction}; -use crate::{prelude::*, wasm::registries::{TypeRegistry, types::{TDynArray, TDynArrayField, TValType}}}; +use crate::prelude::*; +use crate::wasm::registries::TypeRegistry; +use crate::wasm::registries::types::{TDynArray, TDynArrayField, TNonNullable, TValType}; + +pub struct DynArrayFuncOverride { + types: Rc, +} /// Pushes an element to a dynamic (resizeable) array /// /// Takes 2 parameters: -/// ref dynamic_array - the array +/// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TValType`) /// t - the element pub struct DynArrayPush(PhantomData); impl NamedRegistryItem for DynArrayPush { @@ -20,15 +25,11 @@ impl NamedRegistryItem for DynArrayPush { }; } -pub struct DynArrayPushOverride { - types: Rc, -} - -impl TryNamedRegistryItemOverride +impl TryNamedRegistryItemOverride for DynArrayPush { fn try_override( - DynArrayPushOverride { types }: DynArrayPushOverride, + DynArrayFuncOverride { types }: DynArrayFuncOverride, ) -> HQResult { let struct_type = types.register_comp::, u32>()?; let array_type = types.register_comp::, u32>()?; @@ -50,29 +51,29 @@ impl TryNamedRegistryItemOverride TryNamedRegistryItemOverride>>::val_type(&types)?, T::val_type(&types)?, ]), returns: Box::from([]), locals: Box::from([ ValType::I32, - TypeRegistry::ref_val(array_type, false), + >>::val_type(&types)?, ]), }), maybe_populate: || None, @@ -106,3 +107,105 @@ impl TryNamedRegistryItemOverride - the dynamic array struct (obtained from `TDynArray` for `T: TValType`) +/// i32 - the index +/// +/// Returns t +pub struct DynArrayGet(PhantomData); +impl NamedRegistryItem for DynArrayGet { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + maybe_populate: || None, + }; +} + +impl TryNamedRegistryItemOverride + for DynArrayGet +{ + fn try_override( + DynArrayFuncOverride { types }: DynArrayFuncOverride, + ) -> HQResult { + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(MaybeStaticFunction { + static_function: Some(StaticFunction { + export: None, + instructions: Box::from(wasm_const![ + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 0, + }, + LocalGet(1), + ArrayGet(array_type), + ] as &[_]), + params: Box::from([ + >>::val_type(&types)?, + ValType::I32, + ]), + returns: Box::from([T::val_type(&types)?]), + locals: Box::from([]), + }), + maybe_populate: || None, + }) + } +} + +/// Pops the last element from a dynamic (resizeable) array +/// +/// Takes 1 parameters: +/// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TValType`) +/// +/// Returns t +pub struct DynArrayPop(PhantomData); +impl NamedRegistryItem for DynArrayPop { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + maybe_populate: || None, + }; +} + +impl TryNamedRegistryItemOverride + for DynArrayPop +{ + fn try_override( + DynArrayFuncOverride { types }: DynArrayFuncOverride, + ) -> HQResult { + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(MaybeStaticFunction { + static_function: Some(StaticFunction { + export: None, + instructions: Box::from(wasm_const![ + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 0, + }, + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 1, + }, + I32Const(1), + I32Sub, + LocalTee(1), + ArrayGet(array_type), + LocalGet(0), + LocalGet(1), + StructSet { + struct_type_index: struct_type, + field_index: 1, + }, + ] as &[_]), + params: Box::from([>>::val_type(&types)?]), + returns: Box::from([T::val_type(&types)?]), + locals: Box::from([ValType::I32]), + }), + maybe_populate: || None, + }) + } +} diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index f8fa5a27..d68ce24f 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -1,24 +1,38 @@ -use wasm_encoder::{AbstractHeapType, HeapType, RefType, ValType}; +use wasm_encoder::{ + AbstractHeapType, BlockType as WasmBlockType, HeapType, MemArg, RefType, ValType, +}; use wasm_gen::wasm_const; use super::{MaybeStaticFunction, StaticFunction}; use crate::prelude::*; +use crate::wasm::mem_layout; +use crate::wasm::registries::functions::dyn_array::{DynArrayGet, DynArrayPop, DynArrayPush}; +use crate::wasm::registries::types::{ + THeapType, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TStructRef, + TTargetThreadArray, TValType, +}; +use crate::wasm::registries::{GlobalRegistry, StaticFunctionRegistry, TypeRegistry}; + +pub struct SpawnThreadFuncOverride { + types: Rc, + globals: Rc, + static_functions: Rc, + num_sprites: u32, + imported_func_count: u32, +} /// Spawns a new thread in the same stack (i.e. a thread that yields back to the current -/// thread once it completes.) +/// thread once it completes.) The step that is provided to return to will be written into +/// the current stack frame, and the new thread's step is added to the top of the current +/// frame with the provided struct argument so that that will run until completion before +/// yielding to the provided next step. /// /// Takes 4 parameters: +/// - i32 - the index of the calling target /// - i32 - the current thread index /// - step funcref - the step to spawn /// - structref - the structref to pass to the step being spawned /// - step funcref - the step to return to after -/// -/// Override with: -/// - u32 - the index of the step func type -/// - u32 - the index of the stack struct type -/// - u32 - the index of the stack array type -/// - u32 - the index of the thread struct type -/// - u32 - the index of the threads table pub struct SpawnThreadInStack; impl NamedRegistryItem for SpawnThreadInStack { const VALUE: MaybeStaticFunction = MaybeStaticFunction { @@ -26,101 +40,80 @@ impl NamedRegistryItem for SpawnThreadInStack { maybe_populate: || None, }; } -pub type SpawnThreadInStackOverride = (u32, u32, u32, u32, u32); -impl NamedRegistryItemOverride +impl TryNamedRegistryItemOverride for SpawnThreadInStack { - fn r#override( - (func_ty, stack_struct_type, stack_array_type, thread_struct_type, threads_table): SpawnThreadInStackOverride, - ) -> MaybeStaticFunction { - MaybeStaticFunction { + fn try_override( + SpawnThreadFuncOverride { + types, + globals, + static_functions, + num_sprites, + imported_func_count, + }: SpawnThreadFuncOverride, + ) -> HQResult { + let stack_struct_type = types.register_comp::()?; + let target_threads_type = types.register_comp::()?; + let target_threads_global = globals.threadss(&types, num_sprites)?; + let dyn_array_push = static_functions.register::, u32>()?; + type StackStruct = TNullable; + Ok(MaybeStaticFunction { static_function: Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ - LocalGet(1), - LocalGet(2), - StructNew(stack_struct_type), - LocalSet(4), LocalGet(0), - TableGet(threads_table), - RefAsNonNull, + I32Eqz, // if this is not the stage, we need to find its layer + If(WasmBlockType::Empty), + LocalGet(0), + I32Const(mem_layout::sprite::BLOCK_SIZE as i32), + I32Mul, + I32Load16U(MemArg { + offset: (mem_layout::stage::BLOCK_SIZE + mem_layout::sprite::LAYER) as u64, + align: 1, + memory_index: 0, + }), + LocalSet(0), // local 0 is now index of sprite in + End, + GlobalGet(target_threads_global), + LocalGet(0), + ArrayGet(target_threads_type), + LocalGet(1), + Call( + imported_func_count + + static_functions + .register::>, u32>()? + ), LocalTee(5), - StructGet { - struct_type_index: thread_struct_type, - field_index: 1, - }, + Call( + imported_func_count + + static_functions.register::, u32>()? + ), + Drop, LocalGet(5), - StructGet { - struct_type_index: thread_struct_type, - field_index: 0, - }, LocalGet(4), - // todo: consider the case where we need to resize the array - ArraySet(stack_array_type), - LocalGet(5), - StructGet { - struct_type_index: thread_struct_type, - field_index: 1, - }, + RefNull(TStackStruct::heap_type(&types)?), + StructNew(stack_struct_type), + Call(imported_func_count + dyn_array_push), // TODO: this will do unnecessary bounds checks. Just mutate the last element. LocalGet(5), - StructGet { - struct_type_index: thread_struct_type, - field_index: 0, - }, - I32Const(1), - I32Sub, - ArrayGet(stack_array_type), + LocalGet(2), LocalGet(3), - StructSet { - struct_type_index: stack_struct_type, - field_index: 0, - }, - LocalGet(5), - LocalGet(5), - StructGet { - struct_type_index: thread_struct_type, - field_index: 0, - }, - I32Const(1), - I32Add, - StructSet { - struct_type_index: thread_struct_type, - field_index: 0, - }, - End + StructNew(stack_struct_type), + Call(imported_func_count + dyn_array_push), ] as &[_]), params: Box::from([ ValType::I32, - ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(func_ty), - }), - ValType::Ref(RefType { - nullable: true, - heap_type: wasm_encoder::HeapType::Abstract { - shared: false, - ty: AbstractHeapType::Struct, - }, - }), - ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(func_ty), - }), + ValType::I32, + >::val_type(&types)?, + >::val_type(&types)?, + >::val_type(&types)?, ]), returns: Box::from([]), locals: Box::from([ - ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(stack_struct_type), - }), - ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(thread_struct_type), - }), + >::val_type(&types)?, ]), }), maybe_populate: || None, - } + }) } } diff --git a/src/wasm/registries/globals.rs b/src/wasm/registries/globals.rs index ef117a9e..e64d064c 100644 --- a/src/wasm/registries/globals.rs +++ b/src/wasm/registries/globals.rs @@ -1,13 +1,13 @@ use core::ops::Deref; use wasm_encoder::{ - ConstExpr, ExportKind, ExportSection, GlobalSection, GlobalType, Instruction, - RefType, ValType, + ConstExpr, ExportKind, ExportSection, GlobalSection, GlobalType, Instruction, ValType, }; use crate::prelude::*; use crate::registry::MapRegistry; use crate::wasm::registries::TypeRegistry; +use crate::wasm::registries::types::{TNonNullable, TTargetThreadArray, TThreadArray, TValType}; #[derive(Copy, Clone, Debug)] pub struct GlobalMutable(pub bool); @@ -56,15 +56,12 @@ impl GlobalRegistry { N: TryFrom, >::Error: fmt::Debug, { - let array_array_type = types.thread_list_array_type()?; - let array_type = types.thread_array_type()?; + let array_array_type = types.register_comp::()?; + let array_type = types.register_comp::()?; self.register( "threadss".into(), ( - ValType::Ref(RefType { - nullable: false, - heap_type: wasm_encoder::HeapType::Concrete(array_array_type), - }), + >::val_type(&types)?, ConstExpr::extended( (0..num_sprites) .map(|i| { diff --git a/src/wasm/registries/tables.rs b/src/wasm/registries/tables.rs index fc729975..1d639df0 100644 --- a/src/wasm/registries/tables.rs +++ b/src/wasm/registries/tables.rs @@ -5,6 +5,7 @@ use wasm_encoder::{ use crate::prelude::*; use crate::wasm::StepTarget; use crate::wasm::registries::TypeRegistry; +use crate::wasm::registries::types::TThreadStruct; #[derive(Clone, Debug)] pub struct TableOptions { @@ -34,7 +35,7 @@ impl TableRegistry { TableOptions { element_type: RefType { nullable: true, - heap_type: HeapType::Concrete(types.thread_struct_type()?), + heap_type: HeapType::Concrete(types.register_comp::()?), }, min: 0, max: None, diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index 856a122a..8ae3ffc9 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -1,9 +1,9 @@ +use core::marker::PhantomData; + use wasm_encoder::{ AbstractHeapType, FieldType, HeapType, RefType, StorageType, TypeSection, ValType, }; -use core::marker::PhantomData; - use crate::ir::RcVar; use crate::prelude::*; use crate::registry::{CompTimeRegistrand, RegistryResult, SetRegistry}; @@ -21,24 +21,21 @@ pub type TypeRegistry = SetRegistry; impl TypeRegistry { pub fn function(&self, params: Vec, returns: Vec) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, { self.register_default(CompoundType::Function(params, returns)) } pub fn array(&self, elem_type: StorageType, mutable: bool) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, { self.register_default(CompoundType::Array(elem_type, mutable)) } pub fn struct_(&self, fields: Vec) -> HQResult where - N: TryFrom, - >::Error: fmt::Debug, + N: RegistryResult, { self.register_default(CompoundType::Struct(fields)) } @@ -51,96 +48,6 @@ impl TypeRegistry { }, }); - pub fn step_func(&self) -> HQResult { - self.function(vec![ValType::I32, Self::STRUCT_REF], vec![]) - } - - pub fn dyn_array_container(&self, field: ValType) -> HQResult { - let arr_type = self.array(StorageType::Val(field), true)?; - self.struct_(vec![FieldType { - element_type: Self::ref_storage(arr_type, false), - mutable: true, - }]) - } - - pub fn ref_(heap_type: u32, nullable: bool) -> RefType { - RefType { - nullable, - heap_type: HeapType::Concrete(heap_type), - } - } - - pub fn ref_val(heap_type: u32, nullable: bool) -> ValType { - ValType::Ref(Self::ref_(heap_type, nullable)) - } - - pub fn ref_storage(heap_type: u32, nullable: bool) -> StorageType { - StorageType::Val(Self::ref_val(heap_type, nullable)) - } - - pub fn stack_struct_type(&self) -> HQResult { - self.struct_(vec![ - FieldType { - element_type: Self::ref_storage(self.step_func()?, false), - mutable: true, - }, - FieldType { - element_type: StorageType::Val(Self::STRUCT_REF), - mutable: false, - }, - ]) - } - - pub fn stack_array_type(&self) -> HQResult { - self.array(Self::ref_storage(self.stack_struct_type()?, true), true) - } - - pub fn thread_struct_type(&self) -> HQResult { - self.struct_(vec![ - FieldType { - element_type: StorageType::Val(ValType::I32), - mutable: true, - }, - FieldType { - element_type: Self::ref_storage(self.stack_array_type()?, false), - mutable: true, - }, - ]) - } - - pub fn thread_array_type(&self) -> HQResult { - self.array(Self::ref_storage(self.thread_struct_type()?, true), true) - } - - pub fn thread_list_struct_type(&self) -> HQResult { - self.struct_(vec![ - // target index - FieldType { - element_type: StorageType::Val(ValType::I32), - mutable: true, - }, - // number of threads - FieldType { - element_type: StorageType::Val(ValType::I32), - mutable: true, - }, - FieldType { - element_type: Self::ref_storage(self.thread_array_type()?, false), - mutable: true, - }, - ]) - } - - pub fn thread_list_array_type(&self) -> HQResult { - self.array( - StorageType::Val(ValType::Ref(RefType { - nullable: true, - heap_type: HeapType::Concrete(self.thread_list_struct_type()?), - })), - true, - ) - } - pub fn proc_arg_struct_type( &self, arg_vars: &core::cell::Ref<'_, Vec>, @@ -171,25 +78,56 @@ impl TypeRegistry { } } -pub trait THeapType: CompTimeRegistrand {} -impl THeapType for T where T: CompTimeRegistrand {} +pub trait THeapType { + fn heap_type(types: &TypeRegistry) -> HQResult; +} + +impl THeapType for T +where + T: CompTimeRegistrand, +{ + fn heap_type(types: &TypeRegistry) -> HQResult { + Ok(HeapType::Concrete(types.register_comp::()?)) + } +} + +pub struct TStructRef; +impl THeapType for TStructRef { + fn heap_type(_types: &TypeRegistry) -> HQResult { + Ok(HeapType::Abstract { + shared: false, + ty: AbstractHeapType::Struct, + }) + } +} pub trait TRefType { type HeapType: THeapType; const NULLABLE: bool; + + fn ref_type(types: &TypeRegistry) -> HQResult { + Ok(RefType { + nullable: Self::NULLABLE, + heap_type: Self::HeapType::heap_type(types)?, + }) + } } pub struct TNullable(PhantomData); - -pub struct TNonNullable(PhantomData); - -impl TRefType for TNullable where T: THeapType { +impl TRefType for TNullable +where + T: THeapType, +{ type HeapType = T; const NULLABLE: bool = true; } impl TDefaultable for TNullable {} -impl TRefType for TNonNullable where T: THeapType { +pub struct TNonNullable(PhantomData); +impl TRefType for TNonNullable +where + T: THeapType, +{ type HeapType = T; const NULLABLE: bool = true; } @@ -198,19 +136,19 @@ pub trait TValType { fn val_type(types: &TypeRegistry) -> HQResult; } -impl TValType for T where T: TRefType { +impl TValType for T +where + T: TRefType, +{ fn val_type(types: &TypeRegistry) -> HQResult { - Ok(TypeRegistry::ref_val( - T::HeapType::register(types)?, - T::NULLABLE, - )) + Ok(ValType::Ref(T::ref_type(types)?)) } } pub struct TI32; impl TValType for TI32 { - fn val_type(types: &TypeRegistry) -> HQResult { + fn val_type(_types: &TypeRegistry) -> HQResult { Ok(ValType::I32) } } @@ -219,6 +157,13 @@ impl TDefaultable for TI32 {} pub trait TFieldType { type ValType: TValType; const MUTABLE: bool; + + fn field_type(types: &TypeRegistry) -> HQResult { + Ok(FieldType { + element_type: StorageType::Val(Self::ValType::val_type(types)?), + mutable: Self::MUTABLE, + }) + } } pub struct TMutField(PhantomData); @@ -227,7 +172,7 @@ pub struct TConstField(PhantomData); impl TFieldType for TMutField { type ValType = T; const MUTABLE: bool = true; -} +} impl TFieldType for TConstField { type ValType = T; @@ -236,37 +181,36 @@ impl TFieldType for TConstField { pub trait TDefaultable: TValType {} - -trait CompTypeList { +trait TFieldList { fn fields(types: &TypeRegistry) -> HQResult>; } -impl CompTypeList for () { +impl TFieldList for () { fn fields(_: &TypeRegistry) -> HQResult> { Ok(vec![]) } } -impl CompTypeList for (Head, Tail) where Head: CompTypeList, Tail: TFieldType { +impl TFieldList for (Head, Tail) +where + Head: TFieldList, + Tail: TFieldType, +{ fn fields(types: &TypeRegistry) -> HQResult> { let mut fields = Head::fields(types)?; - fields.push( - FieldType { - mutable: Tail::MUTABLE, - element_type: StorageType::Val(Tail::ValType::val_type(types)?), - } - ); + fields.push(Tail::field_type(types)?); Ok(fields) } } pub struct TStruct(PhantomData); -impl CompTimeRegistrand for TStruct where Fields: CompTypeList { +impl CompTimeRegistrand for TStruct +where + Fields: TFieldList, +{ fn register(types: &TypeRegistry) -> HQResult { - types.struct_( - Fields::fields(types)? - ) + types.struct_(Fields::fields(types)?) } } @@ -281,5 +225,60 @@ impl CompTimeRegistrand for TArray } } +trait TValTypeList { + fn val_types(types: &TypeRegistry) -> HQResult>; +} + +impl TValTypeList for () { + fn val_types(_: &TypeRegistry) -> HQResult> { + Ok(vec![]) + } +} + +impl TValTypeList for (Head, Tail) +where + Head: TValTypeList, + Tail: TValType, +{ + fn val_types(types: &TypeRegistry) -> HQResult> { + let mut val_types = Head::val_types(types)?; + val_types.push(Tail::val_type(types)?); + Ok(val_types) + } +} + +pub struct TFunc(PhantomData, PhantomData); + +impl CompTimeRegistrand for TFunc +where + Params: TValTypeList, + Result: TValTypeList, +{ + fn register(types: &TypeRegistry) -> HQResult { + types.function(Params::val_types(types)?, Result::val_types(types)?) + } +} + +pub type TStepFunc = TFunc<(((), TI32), TNullable), ()>; + pub type TDynArrayField = TArray>; -pub type TDynArray = TStruct<(((), TMutField>>), TMutField)>; +pub type TDynArray = TStruct<( + ((), TMutField>>), + TMutField, +)>; + +pub type TStackStruct = TStruct<( + ((), TMutField>), + TConstField>, +)>; + +pub type TStackArray = TDynArray>; + +pub type TThreadArray = TDynArray>; + +pub type TTargetThreadsStruct = TStruct<( + (((), TMutField), TMutField), + TMutField>, +)>; + +pub type TTargetThreadArray = TArray>>; From 435604eac434919ddb8b28c5790b7f032d482ebd Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Thu, 20 Aug 2026 22:34:55 +0100 Subject: [PATCH 06/18] finish thread spawning routines, start cleaning up other references --- src/wasm/project.rs | 72 ++++----- src/wasm/registries.rs | 9 +- src/wasm/registries/functions.rs | 7 +- src/wasm/registries/functions/dyn_array.rs | 67 ++++++-- .../registries/functions/spawn_threads.rs | 144 +++++++++--------- src/wasm/registries/globals.rs | 2 +- src/wasm/registries/tables.rs | 27 +--- 7 files changed, 179 insertions(+), 149 deletions(-) diff --git a/src/wasm/project.rs b/src/wasm/project.rs index fae3c2d7..a88a829a 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -12,9 +12,9 @@ use super::{ExternalEnvironment, Registries}; use crate::ir::{Event, IrProject, IrType, StepIndex}; use crate::prelude::*; use crate::wasm::registries::functions::static_functions::{ - MarkWaitingFlag, SpawnNewThread, SpawnThreadInStack, + MarkWaitingFlag, SpawnNewThread, SpawnThreadFuncOverride, SpawnThreadInStack, }; -use crate::wasm::registries::types::{TStackStruct, TStepFunc}; +use crate::wasm::registries::types::{TStackArray, TStackStruct, TStepFunc}; use crate::wasm::{StepFunc, StepTarget, StringsTable, WasmFlags}; /// A respresentation of a WASM representation of a project. Cannot be created directly; @@ -137,25 +137,23 @@ impl WasmProject { .clone() .finish(&mut imports, self.registries().types())?; + let spawn_thread_func_override = SpawnThreadFuncOverride { + types: Rc::clone(self.registries().types()), + static_functions: Rc::clone(self.registries().static_functions()), + globals: Rc::clone(self.registries().globals()), + num_sprites: self.costume_names().len() as u32, + imported_func_count: self.imported_func_count()?, + }; + self.registries() .static_functions() - .register_override::(( - self.registries().types().register_comp::()?, - self.registries().types().register_comp::()?, - self.registries().types().stack_array_type()?, - self.registries().types().thread_struct_type()?, - self.threads_table_index()?, - ))?; + .try_register_override::( + spawn_thread_func_override.clone(), + )?; self.registries() .static_functions() - .register_override::(( - self.registries().types().register_comp::()?, - self.registries().types().register_comp::()?, - self.registries().types().stack_array_type()?, - self.registries().types().thread_struct_type()?, - self.threads_table_index()?, - ))?; + .try_register_override::(spawn_thread_func_override)?; self.registries() .static_functions() @@ -166,7 +164,7 @@ impl WasmProject { }], )?)?; - self.registries().static_functions().clone().finish( + Rc::unwrap_or_clone(self.registries().static_functions().clone()).finish( &mut functions, &mut exports, &mut codes, @@ -183,7 +181,7 @@ impl WasmProject { self.threads_count_global()?, self.spawn_new_thread_func()?, self.spawn_thread_in_stack_func()?, - self.threads_table_index()?, + self.threadss_global()?, self.imported_func_count()?, self.static_func_count()?, self.imported_global_count()?, @@ -276,7 +274,7 @@ impl WasmProject { exports.export("memory", ExportKind::Memory, 0); - self.registries().globals().clone().finish( + Rc::unwrap_or_clone(self.registries().globals().clone()).finish( &mut globals, &mut exports, self.imported_global_count()?, @@ -369,16 +367,6 @@ impl WasmProject { Ok(()) } - fn threads_table_index(&self, target: StepTarget) -> HQResult - where - N: TryFrom, - >::Error: fmt::Debug, - { - self.registries() - .tables() - .threads_table(target, self.registries().types()) - } - fn spawn_new_thread_func(&self) -> HQResult where N: TryFrom, @@ -407,6 +395,16 @@ impl WasmProject { self.registries().globals().threads_count() } + fn threadss_global(&self) -> HQResult + where + N: TryFrom, + >::Error: fmt::Debug, + { + self.registries() + .globals() + .threadss(self.registries().types(), self.costume_names().len() as u32) + } + #[expect(clippy::needless_pass_by_value, reason = "annoying to borrow a box")] fn finish_event( &self, @@ -444,7 +442,7 @@ impl WasmProject { self.threads_count_global()?, self.spawn_new_thread_func()?, self.spawn_thread_in_stack_func()?, - self.threads_table_index()?, + self.threadss_global()?, self.imported_func_count()?, self.static_func_count()?, self.imported_global_count()?, @@ -467,7 +465,7 @@ impl WasmProject { self.threads_count_global()?, self.spawn_new_thread_func()?, self.spawn_thread_in_stack_func()?, - self.threads_table_index()?, + self.threadss_global()?, self.imported_func_count()?, self.static_func_count()?, self.imported_global_count()?, @@ -566,7 +564,7 @@ impl WasmProject { self.threads_count_global()?, self.spawn_new_thread_func()?, self.spawn_thread_in_stack_func()?, - self.threads_table_index()?, + self.threadss_global()?, self.imported_func_count()?, self.static_func_count()?, self.imported_global_count()?, @@ -596,8 +594,14 @@ impl WasmProject { codes: &mut CodeSection, exports: &mut ExportSection, ) -> HQResult<()> { - let thread_struct_type = self.registries().types().thread_struct_type()?; - let stack_struct_ty = self.registries().types().stack_struct_type()?; + let thread_struct_type = self + .registries() + .types() + .register_comp::()?; + let stack_struct_ty = self + .registries() + .types() + .register_comp::()?; let mut tick_func = Function::new(vec![ (2, ValType::I32), diff --git a/src/wasm/registries.rs b/src/wasm/registries.rs index 13e5f801..376f6520 100644 --- a/src/wasm/registries.rs +++ b/src/wasm/registries.rs @@ -22,7 +22,7 @@ pub struct Registries { strings: Rc, tabled_strings: Rc, external_functions: ExternalFunctionRegistry, - static_functions: StaticFunctionRegistry, + static_functions: Rc, types: Rc, tables: TableRegistry, globals: Rc, @@ -39,6 +39,7 @@ impl Default for Registries { let types = Rc::new(TypeRegistry::default()); let variables = VariableRegistry::new(&globals, &strings, &tabled_strings); let lists = ListRegistry::new(&globals, &types, &strings, &tabled_strings); + let static_functions = Rc::new(StaticFunctionRegistry::default()); Self { globals, variables, @@ -48,7 +49,7 @@ impl Default for Registries { tables: TableRegistry::default(), types, sprites: SpriteRegistry::default(), - static_functions: StaticFunctionRegistry::default(), + static_functions, lists, } } @@ -67,7 +68,7 @@ impl Registries { &self.external_functions } - pub const fn static_functions(&self) -> &StaticFunctionRegistry { + pub const fn static_functions(&self) -> &Rc { &self.static_functions } @@ -79,7 +80,7 @@ impl Registries { &self.tables } - pub fn globals(&self) -> &GlobalRegistry { + pub fn globals(&self) -> &Rc { &self.globals } diff --git a/src/wasm/registries/functions.rs b/src/wasm/registries/functions.rs index 1a4e57b7..e7e32383 100644 --- a/src/wasm/registries/functions.rs +++ b/src/wasm/registries/functions.rs @@ -107,9 +107,10 @@ impl StaticFunctionRegistry { } pub mod static_functions { + pub use super::dyn_array::{ + DynArrayFuncOverride, DynArrayGet, DynArrayNew, DynArrayPop, DynArrayPush, + }; pub use super::mark_waiting_flag::MarkWaitingFlag; pub use super::pen_colour::{UpdatePenColorFromHSV, UpdatePenColorFromRGB}; - pub use super::spawn_threads::{ - SpawnNewThread, SpawnNewThreadOverride, SpawnThreadInStack, - }; + pub use super::spawn_threads::{SpawnNewThread, SpawnThreadFuncOverride, SpawnThreadInStack}; } diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs index 6d174814..fa13ffe7 100644 --- a/src/wasm/registries/functions/dyn_array.rs +++ b/src/wasm/registries/functions/dyn_array.rs @@ -6,27 +6,30 @@ use wasm_gen::wasm_const; use super::{MaybeStaticFunction, StaticFunction}; use crate::prelude::*; use crate::wasm::registries::TypeRegistry; -use crate::wasm::registries::types::{TDynArray, TDynArrayField, TNonNullable, TValType}; +use crate::wasm::registries::types::{ + TDefaultable, TDynArray, TDynArrayField, TNonNullable, TValType, +}; +#[derive(Clone)] pub struct DynArrayFuncOverride { - types: Rc, + pub types: Rc, } /// Pushes an element to a dynamic (resizeable) array /// /// Takes 2 parameters: -/// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TValType`) +/// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// t - the element pub struct DynArrayPush(PhantomData); -impl NamedRegistryItem for DynArrayPush { +impl NamedRegistryItem for DynArrayPush { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride - for DynArrayPush +impl + TryNamedRegistryItemOverride for DynArrayPush { fn try_override( DynArrayFuncOverride { types }: DynArrayFuncOverride, @@ -110,19 +113,19 @@ impl TryNamedRegistryItemOverride - the dynamic array struct (obtained from `TDynArray` for `T: TValType`) +/// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// i32 - the index /// /// Returns t pub struct DynArrayGet(PhantomData); -impl NamedRegistryItem for DynArrayGet { +impl NamedRegistryItem for DynArrayGet { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride +impl TryNamedRegistryItemOverride for DynArrayGet { fn try_override( @@ -157,18 +160,18 @@ impl TryNamedRegistryItemOverride - the dynamic array struct (obtained from `TDynArray` for `T: TValType`) +/// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// /// Returns t pub struct DynArrayPop(PhantomData); -impl NamedRegistryItem for DynArrayPop { +impl NamedRegistryItem for DynArrayPop { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride +impl TryNamedRegistryItemOverride for DynArrayPop { fn try_override( @@ -209,3 +212,43 @@ impl TryNamedRegistryItemOverride +pub struct DynArrayNew(PhantomData); +impl NamedRegistryItem for DynArrayNew { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + maybe_populate: || None, + }; +} + +impl TryNamedRegistryItemOverride + for DynArrayNew +{ + fn try_override( + DynArrayFuncOverride { types }: DynArrayFuncOverride, + ) -> HQResult { + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(MaybeStaticFunction { + static_function: Some(StaticFunction { + export: None, + instructions: Box::from(wasm_const![ + LocalGet(0), + ArrayNewDefault(array_type), + I32Const(0), + StructNew(struct_type), + ] as &[_]), + params: Box::from([ValType::I32]), + returns: Box::from([>>::val_type(&types)?]), + locals: Box::from([]), + }), + maybe_populate: || None, + }) + } +} diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index d68ce24f..f7301df8 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -1,26 +1,29 @@ -use wasm_encoder::{ - AbstractHeapType, BlockType as WasmBlockType, HeapType, MemArg, RefType, ValType, -}; +use wasm_encoder::{BlockType as WasmBlockType, MemArg, ValType}; use wasm_gen::wasm_const; use super::{MaybeStaticFunction, StaticFunction}; use crate::prelude::*; use crate::wasm::mem_layout; -use crate::wasm::registries::functions::dyn_array::{DynArrayGet, DynArrayPop, DynArrayPush}; +use crate::wasm::registries::functions::dyn_array::{ + DynArrayGet, DynArrayNew, DynArrayPop, DynArrayPush, +}; use crate::wasm::registries::types::{ - THeapType, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TStructRef, - TTargetThreadArray, TValType, + THeapType, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, + TThreadArray, TValType, }; use crate::wasm::registries::{GlobalRegistry, StaticFunctionRegistry, TypeRegistry}; +#[derive(Clone)] pub struct SpawnThreadFuncOverride { - types: Rc, - globals: Rc, - static_functions: Rc, - num_sprites: u32, - imported_func_count: u32, + pub types: Rc, + pub globals: Rc, + pub static_functions: Rc, + pub num_sprites: u32, + pub imported_func_count: u32, } +type StackStructRef = TNullable; + /// Spawns a new thread in the same stack (i.e. a thread that yields back to the current /// thread once it completes.) The step that is provided to return to will be written into /// the current stack frame, and the new thread's step is added to the top of the current @@ -55,8 +58,7 @@ impl TryNamedRegistryItemOverride let stack_struct_type = types.register_comp::()?; let target_threads_type = types.register_comp::()?; let target_threads_global = globals.threadss(&types, num_sprites)?; - let dyn_array_push = static_functions.register::, u32>()?; - type StackStruct = TNullable; + let dyn_array_push = static_functions.register::, u32>()?; Ok(MaybeStaticFunction { static_function: Some(StaticFunction { export: None, @@ -86,7 +88,7 @@ impl TryNamedRegistryItemOverride LocalTee(5), Call( imported_func_count - + static_functions.register::, u32>()? + + static_functions.register::, u32>()? ), Drop, LocalGet(5), @@ -104,13 +106,11 @@ impl TryNamedRegistryItemOverride ValType::I32, ValType::I32, >::val_type(&types)?, - >::val_type(&types)?, + StackStructRef::val_type(&types)?, >::val_type(&types)?, ]), returns: Box::from([]), - locals: Box::from([ - >::val_type(&types)?, - ]), + locals: Box::from([>::val_type(&types)?]), }), maybe_populate: || None, }) @@ -121,9 +121,9 @@ impl TryNamedRegistryItemOverride /// immediately, instead leaving that for the scheduler or calling function to do so. /// /// Takes 3 parameters: +/// - i32 - the index of the target to spawn a thread for /// - step funcref - the step to spawn /// - ref null struct - the stack struct to spawn it with -/// - i32 - the index of the sprite to spawn a thread for, or -1 for the stage /// /// Override with: /// - u32 - the index of the step func type @@ -138,70 +138,76 @@ impl NamedRegistryItem for SpawnNewThread { maybe_populate: || None, }; } -pub struct SpawnNewThreadOverride { - func_ty: u32, - stack_struct_ty: u32, - stack_array_ty: u32, - thread_struct_ty: u32, - threads_array_index: u32, - threads_array_ty: u32, -} -impl NamedRegistryItemOverride for SpawnNewThread { - fn r#override( - SpawnNewThreadOverride { - func_ty, - stack_struct_ty, - stack_array_ty, - thread_struct_ty, - threads_array_index, - threads_array_ty, - }: SpawnNewThreadOverride, - ) -> MaybeStaticFunction { - MaybeStaticFunction { +impl TryNamedRegistryItemOverride for SpawnNewThread { + fn try_override( + SpawnThreadFuncOverride { + types, + globals, + static_functions, + num_sprites, + imported_func_count, + }: SpawnThreadFuncOverride, + ) -> HQResult { + let stack_struct_type = types.register_comp::()?; + let target_threads_type = types.register_comp::()?; + let target_threads_global = globals.threadss(&types, num_sprites)?; + Ok(MaybeStaticFunction { static_function: Some(StaticFunction { export: None, params: Box::from([ - ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(func_ty), - }), - ValType::Ref(RefType { - nullable: true, - heap_type: wasm_encoder::HeapType::Abstract { - shared: false, - ty: AbstractHeapType::Struct, - }, - }), + ValType::I32, + >::val_type(&types)?, + StackStructRef::val_type(&types)?, ]), returns: Box::from([]), - locals: Box::from([ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(stack_array_ty), - })]), + locals: Box::from([>::val_type(&types)?]), instructions: { - const STACK_ARRAY_LOCAL: u32 = 3; (wasm_const![ - // TODO get - I32Const(1), // stack size - // todo: play around with initial size of stack array + LocalGet(0), + I32Eqz, // if this is not the stage, we need to find its layer + If(WasmBlockType::Empty), + LocalGet(0), + I32Const(mem_layout::sprite::BLOCK_SIZE as i32), + I32Mul, + I32Load16U(MemArg { + offset: (mem_layout::stage::BLOCK_SIZE + mem_layout::sprite::LAYER) + as u64, + align: 1, + memory_index: 0, + }), + LocalSet(0), // local 0 is now index of sprite in + End, + GlobalGet(target_threads_global), + LocalGet(0), + ArrayGet(target_threads_type), I32Const(8), - ArrayNewDefault(stack_array_ty), - LocalTee(STACK_ARRAY_LOCAL), - StructNew(thread_struct_ty), - I32Const(0), // index 0 into stack array - I32Const(1), // stack size - LocalGet(0), // step func - LocalGet(1), // stack struct param - StructNew(stack_struct_ty), // stack struct - ArraySet(stack_array_ty), // set 0th element of stack array to stack struct - ArraySet(threads_array_ty), + Call( + imported_func_count + + static_functions + .register::, u32>()? + ), + LocalTee(3), + LocalGet(1), + LocalGet(2), + StructNew(stack_struct_type), + Call( + imported_func_count + + static_functions + .register::, u32>()? + ), + LocalGet(3), + Call( + imported_func_count + + static_functions + .register::>, u32>()? + ), End, ] as &[_]) .into() }, }), maybe_populate: || None, - } + }) } } diff --git a/src/wasm/registries/globals.rs b/src/wasm/registries/globals.rs index e64d064c..4babf3bc 100644 --- a/src/wasm/registries/globals.rs +++ b/src/wasm/registries/globals.rs @@ -63,7 +63,7 @@ impl GlobalRegistry { ( >::val_type(&types)?, ConstExpr::extended( - (0..num_sprites) + (0..=num_sprites) // stage + sprites .map(|i| { [ Instruction::I32Const(i as i32), diff --git a/src/wasm/registries/tables.rs b/src/wasm/registries/tables.rs index 1d639df0..eacd01b4 100644 --- a/src/wasm/registries/tables.rs +++ b/src/wasm/registries/tables.rs @@ -1,11 +1,6 @@ -use wasm_encoder::{ - ConstExpr, ExportKind, ExportSection, HeapType, RefType, TableSection, TableType, -}; +use wasm_encoder::{ConstExpr, ExportKind, ExportSection, RefType, TableSection, TableType}; use crate::prelude::*; -use crate::wasm::StepTarget; -use crate::wasm::registries::TypeRegistry; -use crate::wasm::registries::types::TThreadStruct; #[derive(Clone, Debug)] pub struct TableOptions { @@ -25,26 +20,6 @@ impl RegistryType for TableRegistrar { pub type TableRegistry = NamedRegistry; impl TableRegistry { - pub fn threads_table(&self, target: StepTarget, types: &Rc) -> HQResult - where - N: TryFrom, - >::Error: fmt::Debug, - { - self.register_dyn( - format!("threads{}", target.suffix_id()).into(), - TableOptions { - element_type: RefType { - nullable: true, - heap_type: HeapType::Concrete(types.register_comp::()?), - }, - min: 0, - max: None, - init: None, - export_name: Some("threads"), - }, - ) - } - pub fn finish(self, tables: &mut TableSection, exports: &mut ExportSection) { for ( _key, From 02599e969e167b6d1206e5d834108ebda290e347 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Sun, 23 Aug 2026 21:33:37 +0100 Subject: [PATCH 07/18] rewrite more functions and instructions to use new thread layout --- src/instructions/control/stop_all.rs | 66 ++++---- .../event/poll_waiting_threads.rs | 102 ++++++------ src/instructions/procedures/argument.rs | 4 +- src/wasm/func.rs | 8 +- src/wasm/project.rs | 154 ++++++++++-------- src/wasm/registries/functions.rs | 3 +- src/wasm/registries/functions/dyn_array.rs | 130 +++++++++++++++ .../registries/functions/spawn_threads.rs | 11 +- src/wasm/registries/types.rs | 2 +- 9 files changed, 315 insertions(+), 165 deletions(-) diff --git a/src/instructions/control/stop_all.rs b/src/instructions/control/stop_all.rs index 6dc6540a..441d2547 100644 --- a/src/instructions/control/stop_all.rs +++ b/src/instructions/control/stop_all.rs @@ -2,7 +2,8 @@ use wasm_encoder::HeapType; use super::super::prelude::*; use crate::instructions_test; -use crate::wasm::StepTarget; +use crate::wasm::registries::functions::static_functions::DynArrayClear; +use crate::wasm::registries::types::{TNullable, TTargetThreadArray, TThreadArray}; fn clear_thread( threads_count: u32, @@ -20,43 +21,42 @@ fn clear_thread( } pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult> { - let thread_struct_type = func.registries().types().thread_struct_type()?; + let local_target_counter = func.local(ValType::I32)?; + func.free_local(local_target_counter)?; + let threadss_global = func + .registries() + .globals() + .threadss(func.registries().types(), func.costume_names().len() as u32)?; let total_threads_count = func.registries().globals().threads_count()?; - let num_sprites = func.costume_names().len() as u32; + let num_targets = 1 + func.costume_names().len() as i32; + let array_type = func + .registries() + .types() + .register_comp::()?; + let dyn_array_clear = func + .registries() + .static_functions() + .register::>, _>()?; Ok(wasm![ I32Const(0), #LazyGlobalSet(total_threads_count), - ] - .into_iter() - .chain(clear_thread( - func.registries() - .globals() - .target_threads_count(StepTarget::Stage)?, - func.registries() - .tables() - .threads_table(StepTarget::Stage, func.registries().types())?, - thread_struct_type, - )) - .chain( - (0..num_sprites) - .map(|n| { - let step_target = StepTarget::Sprite(n); - Ok(clear_thread( - func.registries() - .globals() - .target_threads_count(step_target)?, - func.registries() - .tables() - .threads_table(step_target, func.registries().types())?, - thread_struct_type, - )) - }) - .collect::>>()? - .into_iter() - .flatten(), - ) - .collect()) + I32Const(0), + LocalSet(local_target_counter), + Loop(wasm_encoder::BlockType::Empty), + #LazyGlobalGet(threadss_global), + LocalGet(local_target_counter), + ArrayGet(array_type), + #StaticFunctionCall(dyn_array_clear), + LocalGet(local_target_counter), + I32Const(1), + I32Add, + LocalTee(local_target_counter), + I32Const(num_targets), + I32LtS, + BrIf(0), + End, + ]) } pub fn acceptable_inputs() -> HQResult> { diff --git a/src/instructions/event/poll_waiting_threads.rs b/src/instructions/event/poll_waiting_threads.rs index da78001b..0d6df6c4 100644 --- a/src/instructions/event/poll_waiting_threads.rs +++ b/src/instructions/event/poll_waiting_threads.rs @@ -4,48 +4,48 @@ //! //! Returns 1 if still waiting on any threads, 0 otherwise. -use wasm_encoder::{BlockType as WasmBlockType, FieldType, HeapType, StorageType}; +use wasm_encoder::BlockType as WasmBlockType; use super::super::prelude::*; use crate::wasm::StepFunc; +use crate::wasm::registries::functions::static_functions::DynArrayLen; +use crate::wasm::registries::types::{ + TArray, TConstField, THeapType, TMutField, TNonNullable, TNullable, TStackArray, TStackStruct, + TStruct, TValType, +}; + +type TWaitingThreadArray = TArray>>; +type TPollStruct = TStruct<((), TConstField>)>; pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult> { - let i32_array_type = func - .registries() - .types() - .array(StorageType::Val(ValType::I32), true)?; - let poll_struct_type = func.registries().types().struct_(vec![FieldType { - mutable: false, - element_type: StorageType::Val(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(i32_array_type), - })), - }])?; - - let arr_local = func.local(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(i32_array_type), - }))?; + let types = Rc::clone(func.registries().types()); + + let thread_array_type = types.register_comp::()?; + let poll_struct_type = types.register_comp::()?; + + let arr_local = func.local(>::val_type(&types)?)?; func.free_local(arr_local)?; let arr_len_local = func.local(ValType::I32)?; let i_local = func.local(ValType::I32)?; + let stack_local = func.local(>::val_type(&types)?)?; let wait_local = func.local(ValType::I32)?; func.free_local(arr_len_local)?; + func.free_local(stack_local)?; func.free_local(i_local)?; func.free_local(wait_local)?; - let threads_table = func + let dyn_array_len = func .registries() - .tables() - .threads_table(func.target(), func.registries().types())?; + .static_functions() + .register::>, _>()?; Ok(wasm![ - LocalGet(1), // this should never have additional function arguments so this is fine - RefCastNonNull(HeapType::Concrete(poll_struct_type)), + LocalGet(1), // this step should never have additional function arguments so this is fine + RefCastNonNull(TPollStruct::heap_type(&types)?), StructGet { struct_type_index: poll_struct_type, - field_index: 0 + field_index: 0, }, LocalTee(arr_local), ArrayLen, @@ -54,35 +54,37 @@ pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult`. @@ -143,6 +147,7 @@ impl WasmProject { globals: Rc::clone(self.registries().globals()), num_sprites: self.costume_names().len() as u32, imported_func_count: self.imported_func_count()?, + imported_global_count: self.imported_global_count()?, }; self.registries() @@ -594,92 +599,101 @@ impl WasmProject { codes: &mut CodeSection, exports: &mut ExportSection, ) -> HQResult<()> { - let thread_struct_type = self - .registries() - .types() - .register_comp::()?; - let stack_struct_ty = self - .registries() - .types() - .register_comp::()?; + let types = Rc::clone(self.registries().types()); let mut tick_func = Function::new(vec![ - (2, ValType::I32), - ( - 1, - ValType::Ref(RefType { - nullable: true, - heap_type: HeapType::Concrete(thread_struct_type), - }), - ), - ( - 1, - ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(stack_struct_ty), - }), - ), + (3, ValType::I32), + (1, >::val_type(&types)?), + (1, >::val_type(&types)?), + (1, >::val_type(&types)?), ]); - let step_func_ty = self.registries().types().step_func()?; - let stack_array_ty = self.registries().types().stack_array_type()?; + let stack_struct_type = types.register_comp::()?; + let target_thread_struct_type = types.register_comp::()?; + let target_threads_array_type = types.register_comp::()?; + let step_func_ty = types.register_comp::()?; + + let threadss_global = self.threadss_global()?; + + let targets_num = 1 + self.costume_names().len() as i32; + + hq_assert!(targets_num > 0); + + const LOCAL_TARGET_INDEX: u32 = 0; + const LOCAL_STACK_INDEX: u32 = 1; + const LOCAL_THREADS_NUM: u32 = 2; + const LOCAL_THREAD_LIST: u32 = 3; + const LOCAL_THREAD: u32 = 4; + const LOCAL_STEP: u32 = 5; let instructions = wasm![ - TableSize(self.threads_table_index()?), - LocalTee(1), - I32Eqz, - BrIf(0), Loop(WasmBlockType::Empty), - LocalGet(0), - LocalGet(0), - TableGet(self.threads_table_index()?), - LocalTee(2), - RefIsNull, - If(WasmBlockType::Empty), - LocalGet(0), - I32Const(1), - I32Add, - LocalTee(0), - LocalGet(1), - I32LtS, - If(WasmBlockType::Empty), - Br(2), - Else, - Return, - End, - End, - LocalGet(2), - RefAsNonNull, + #LazyGlobalGet(threadss_global), + LocalGet(LOCAL_TARGET_INDEX), + ArrayGet(target_threads_array_type), StructGet { - struct_type_index: thread_struct_type, - field_index: 1 + struct_type_index: target_thread_struct_type, + field_index: 1, }, - LocalGet(2), + LocalTee(LOCAL_THREAD_LIST), + #StaticFunctionCall( + self.registries() + .static_functions() + .register::>, u32>()? + ), + LocalTee(LOCAL_THREADS_NUM), + I32Eqz, + BrIf(0), + I32Const(0), + LocalSet(LOCAL_STACK_INDEX), + Loop(WasmBlockType::Empty), + LocalGet(LOCAL_THREAD_LIST), + LocalGet(LOCAL_STACK_INDEX), + #StaticFunctionCall( + self.registries() + .static_functions() + .register::>, u32>()? + ), RefAsNonNull, - StructGet { - struct_type_index: thread_struct_type, - field_index: 0 - }, + LocalTee(LOCAL_THREAD), + LocalGet(LOCAL_THREAD), + #StaticFunctionCall( + self.registries() + .static_functions() + .register::>, u32>()? + ), I32Const(1), I32Sub, - ArrayGet(stack_array_ty), + #StaticFunctionCall( + self.registries() + .static_functions() + .register::>, u32>()? + ), + LocalTee(LOCAL_STEP), RefAsNonNull, - LocalTee(3), StructGet { - struct_type_index: stack_struct_ty, - field_index: 1 + struct_type_index: stack_struct_type, + field_index: 1, }, LocalGet(3), StructGet { - struct_type_index: stack_struct_ty, - field_index: 0 + struct_type_index: stack_struct_type, + field_index: 0, }, CallRef(step_func_ty), - LocalGet(0), + LocalGet(LOCAL_STACK_INDEX), I32Const(1), I32Add, - LocalTee(0), - LocalGet(1), + LocalTee(LOCAL_STACK_INDEX), + LocalGet(LOCAL_THREADS_NUM), + I32LtS, + BrIf(0), + End, + LocalGet(LOCAL_TARGET_INDEX), + I32Const(1), + I32Add, + LocalTee(LOCAL_TARGET_INDEX), + I32Const(targets_num), I32LtS, BrIf(0), End, @@ -691,7 +705,7 @@ impl WasmProject { self.threads_count_global()?, self.spawn_new_thread_func()?, self.spawn_thread_in_stack_func()?, - self.threads_table_index()?, + self.threadss_global()?, self.imported_func_count()?, self.static_func_count()?, self.imported_global_count()?, @@ -700,7 +714,7 @@ impl WasmProject { } } tick_func.instruction(&Instruction::End); - funcs.function(self.registries().types().function(vec![], vec![])?); + funcs.function(types.register_comp::, _>()?); codes.function(&tick_func); exports.export( "tick", diff --git a/src/wasm/registries/functions.rs b/src/wasm/registries/functions.rs index e7e32383..15940774 100644 --- a/src/wasm/registries/functions.rs +++ b/src/wasm/registries/functions.rs @@ -108,7 +108,8 @@ impl StaticFunctionRegistry { pub mod static_functions { pub use super::dyn_array::{ - DynArrayFuncOverride, DynArrayGet, DynArrayNew, DynArrayPop, DynArrayPush, + DynArrayClear, DynArrayFuncOverride, DynArrayGet, DynArrayLen, DynArrayNew, DynArrayPop, + DynArrayPush, }; pub use super::mark_waiting_flag::MarkWaitingFlag; pub use super::pen_colour::{UpdatePenColorFromHSV, UpdatePenColorFromRGB}; diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs index fa13ffe7..2ab31b27 100644 --- a/src/wasm/registries/functions/dyn_array.rs +++ b/src/wasm/registries/functions/dyn_array.rs @@ -157,6 +157,54 @@ impl TryNamedRegistryItemOverride - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) +/// i32 - the index +/// t - the element +pub struct DynArraySet(PhantomData); +impl NamedRegistryItem for DynArraySet { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + maybe_populate: || None, + }; +} + +impl TryNamedRegistryItemOverride + for DynArraySet +{ + fn try_override( + DynArrayFuncOverride { types }: DynArrayFuncOverride, + ) -> HQResult { + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(MaybeStaticFunction { + static_function: Some(StaticFunction { + export: None, + instructions: Box::from(wasm_const![ + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 0, + }, + LocalGet(1), + LocalGet(2), + ArrayGet(array_type), + ] as &[_]), + params: Box::from([ + >>::val_type(&types)?, + ValType::I32, + T::val_type(&types)?, + ]), + returns: Box::from([T::val_type(&types)?]), + locals: Box::from([]), + }), + maybe_populate: || None, + }) + } +} + /// Pops the last element from a dynamic (resizeable) array /// /// Takes 1 parameters: @@ -252,3 +300,85 @@ impl TryNamedRegistryItemOverride - the dynamic array +/// +/// Returns i32 +pub struct DynArrayLen(PhantomData); +impl NamedRegistryItem for DynArrayLen { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + maybe_populate: || None, + }; +} + +impl TryNamedRegistryItemOverride + for DynArrayLen +{ + fn try_override( + DynArrayFuncOverride { types }: DynArrayFuncOverride, + ) -> HQResult { + let struct_type = types.register_comp::, u32>()?; + Ok(MaybeStaticFunction { + static_function: Some(StaticFunction { + export: None, + instructions: Box::from(wasm_const![ + LocalGet(0), + StructGet { + struct_type_index: struct_type, + field_index: 1 + }, + ] as &[_]), + params: Box::from([>>::val_type(&types)?]), + returns: Box::from([ValType::I32]), + locals: Box::from([]), + }), + maybe_populate: || None, + }) + } +} + +/// Clears the given dynamic array to length 0 (but doesn't actually drop any of the elements) +/// +/// Takes 1 parameters: +/// ref dynamic_array - the dynamic array +pub struct DynArrayClear(PhantomData); +impl NamedRegistryItem for DynArrayClear { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + maybe_populate: || None, + }; +} + +impl TryNamedRegistryItemOverride + for DynArrayClear +{ + fn try_override( + DynArrayFuncOverride { types }: DynArrayFuncOverride, + ) -> HQResult { + let struct_type = types.register_comp::, u32>()?; + Ok(MaybeStaticFunction { + static_function: Some(StaticFunction { + export: None, + instructions: Box::from(wasm_const![ + LocalGet(0), + I32Const(0), + StructSet { + struct_type_index: struct_type, + field_index: 1 + }, + ] as &[_]), + params: Box::from([>>::val_type(&types)?]), + returns: Box::from([ValType::I32]), + locals: Box::from([]), + }), + maybe_populate: || None, + }) + } +} + + + diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index f7301df8..cc6bfb30 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -20,6 +20,7 @@ pub struct SpawnThreadFuncOverride { pub static_functions: Rc, pub num_sprites: u32, pub imported_func_count: u32, + pub imported_global_count: u32, } type StackStructRef = TNullable; @@ -53,11 +54,12 @@ impl TryNamedRegistryItemOverride static_functions, num_sprites, imported_func_count, + imported_global_count, }: SpawnThreadFuncOverride, ) -> HQResult { let stack_struct_type = types.register_comp::()?; let target_threads_type = types.register_comp::()?; - let target_threads_global = globals.threadss(&types, num_sprites)?; + let target_threads_global: u32 = globals.threadss(&types, num_sprites)?; let dyn_array_push = static_functions.register::, u32>()?; Ok(MaybeStaticFunction { static_function: Some(StaticFunction { @@ -76,7 +78,7 @@ impl TryNamedRegistryItemOverride }), LocalSet(0), // local 0 is now index of sprite in End, - GlobalGet(target_threads_global), + GlobalGet(imported_global_count + target_threads_global), LocalGet(0), ArrayGet(target_threads_type), LocalGet(1), @@ -147,11 +149,12 @@ impl TryNamedRegistryItemOverride static_functions, num_sprites, imported_func_count, + imported_global_count, }: SpawnThreadFuncOverride, ) -> HQResult { let stack_struct_type = types.register_comp::()?; let target_threads_type = types.register_comp::()?; - let target_threads_global = globals.threadss(&types, num_sprites)?; + let target_threads_global: u32 = globals.threadss(&types, num_sprites)?; Ok(MaybeStaticFunction { static_function: Some(StaticFunction { export: None, @@ -178,7 +181,7 @@ impl TryNamedRegistryItemOverride }), LocalSet(0), // local 0 is now index of sprite in End, - GlobalGet(target_threads_global), + GlobalGet(imported_global_count + target_threads_global), LocalGet(0), ArrayGet(target_threads_type), I32Const(8), diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index 8ae3ffc9..14f00c61 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -277,7 +277,7 @@ pub type TStackArray = TDynArray>; pub type TThreadArray = TDynArray>; pub type TTargetThreadsStruct = TStruct<( - (((), TMutField), TMutField), + ((), TMutField), TMutField>, )>; From 30ec8732c48a9f55e975654f5190848ce303d306 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Sun, 23 Aug 2026 23:23:45 +0100 Subject: [PATCH 08/18] remove a layer of indirection in thread referencing --- .../registries/functions/spawn_threads.rs | 68 +++++-------------- src/wasm/registries/types.rs | 2 +- 2 files changed, 18 insertions(+), 52 deletions(-) diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index cc6bfb30..5dc084fa 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -1,14 +1,12 @@ -use wasm_encoder::{BlockType as WasmBlockType, MemArg, ValType}; +use wasm_encoder::{BlockType as WasmBlockType, HeapType, MemArg, ValType}; use wasm_gen::wasm_const; use super::{MaybeStaticFunction, StaticFunction}; use crate::prelude::*; use crate::wasm::mem_layout; -use crate::wasm::registries::functions::dyn_array::{ - DynArrayGet, DynArrayNew, DynArrayPop, DynArrayPush, -}; +use crate::wasm::registries::functions::dyn_array::{DynArrayNew, DynArrayPop, DynArrayPush}; use crate::wasm::registries::types::{ - THeapType, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, + TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, TThreadArray, TValType, }; use crate::wasm::registries::{GlobalRegistry, StaticFunctionRegistry, TypeRegistry}; @@ -32,11 +30,10 @@ type StackStructRef = TNullable; /// yielding to the provided next step. /// /// Takes 4 parameters: -/// - i32 - the index of the calling target -/// - i32 - the current thread index -/// - step funcref - the step to spawn +/// - ref stack_array - the current stack +/// - ref step_func - the step to spawn /// - structref - the structref to pass to the step being spawned -/// - step funcref - the step to return to after +/// - ref step_func - the step to return to after pub struct SpawnThreadInStack; impl NamedRegistryItem for SpawnThreadInStack { const VALUE: MaybeStaticFunction = MaybeStaticFunction { @@ -50,69 +47,45 @@ impl TryNamedRegistryItemOverride fn try_override( SpawnThreadFuncOverride { types, - globals, static_functions, - num_sprites, imported_func_count, - imported_global_count, + .. }: SpawnThreadFuncOverride, ) -> HQResult { let stack_struct_type = types.register_comp::()?; - let target_threads_type = types.register_comp::()?; - let target_threads_global: u32 = globals.threadss(&types, num_sprites)?; let dyn_array_push = static_functions.register::, u32>()?; Ok(MaybeStaticFunction { static_function: Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), - I32Eqz, // if this is not the stage, we need to find its layer - If(WasmBlockType::Empty), - LocalGet(0), - I32Const(mem_layout::sprite::BLOCK_SIZE as i32), - I32Mul, - I32Load16U(MemArg { - offset: (mem_layout::stage::BLOCK_SIZE + mem_layout::sprite::LAYER) as u64, - align: 1, - memory_index: 0, - }), - LocalSet(0), // local 0 is now index of sprite in - End, - GlobalGet(imported_global_count + target_threads_global), - LocalGet(0), - ArrayGet(target_threads_type), - LocalGet(1), - Call( - imported_func_count - + static_functions - .register::>, u32>()? - ), - LocalTee(5), Call( imported_func_count + static_functions.register::, u32>()? ), Drop, - LocalGet(5), - LocalGet(4), - RefNull(TStackStruct::heap_type(&types)?), + LocalGet(0), + LocalGet(3), + RefNull(HeapType::Abstract { + shared: false, + ty: wasm_encoder::AbstractHeapType::Struct + }), StructNew(stack_struct_type), Call(imported_func_count + dyn_array_push), // TODO: this will do unnecessary bounds checks. Just mutate the last element. - LocalGet(5), + LocalGet(0), + LocalGet(1), LocalGet(2), - LocalGet(3), StructNew(stack_struct_type), Call(imported_func_count + dyn_array_push), ] as &[_]), params: Box::from([ - ValType::I32, - ValType::I32, + >::val_type(&types)?, >::val_type(&types)?, StackStructRef::val_type(&types)?, >::val_type(&types)?, ]), returns: Box::from([]), - locals: Box::from([>::val_type(&types)?]), + locals: Box::from([]), }), maybe_populate: || None, }) @@ -126,13 +99,6 @@ impl TryNamedRegistryItemOverride /// - i32 - the index of the target to spawn a thread for /// - step funcref - the step to spawn /// - ref null struct - the stack struct to spawn it with -/// -/// Override with: -/// - u32 - the index of the step func type -/// - u32 - the index of the stack struct type -/// - u32 - the index of the stack array type -/// - u32 - the index of the thread struct type -/// - u32 - the index of the threads array pub struct SpawnNewThread; impl NamedRegistryItem for SpawnNewThread { const VALUE: MaybeStaticFunction = MaybeStaticFunction { diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index 14f00c61..8afd5ba1 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -259,7 +259,7 @@ where } } -pub type TStepFunc = TFunc<(((), TI32), TNullable), ()>; +pub type TStepFunc = TFunc<(((), TNonNullable), TNullable), ()>; pub type TDynArrayField = TArray>; pub type TDynArray = TStruct<( From c5c2071e4cd66fe3c55a786841445ed0bc2a5297 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Fri, 4 Sep 2026 20:41:57 +0100 Subject: [PATCH 09/18] finally a typesafe representation of mutually recursive types? --- Cargo.toml | 6 +- rust-toolchain.toml | 2 +- src/ir/blocks/special.rs | 2 +- src/lib.rs | 7 +- src/wasm/project.rs | 8 +- src/wasm/registries/functions/dyn_array.rs | 32 +- .../registries/functions/spawn_threads.rs | 16 +- src/wasm/registries/globals.rs | 4 +- src/wasm/registries/types.rs | 595 +++++++++++++++--- 9 files changed, 546 insertions(+), 126 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7826d25..b351c1ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ publish = false serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } serde_json = { version = "1.0.150", default-features = false, features = ["alloc"] } enum-field-getter = { path = "enum-field-getter" } -wasm-encoder = "0.245.1" +wasm-encoder = "0.258.0" indexmap = { version = "2.14.0", default-features = false } hashers = "1.0.1" uuid = { version = "1.23.3", default-features = false, features = ["v4", "js"] } @@ -22,8 +22,8 @@ wasm-gen = { path = "wasm-gen", version = "0.2.0" } petgraph = { version = "0.8.1", default-features = false, features = ["stable_graph"] } [dev-dependencies] -wasmparser = { git = "https://github.com/pufferfish101007/wasm-tools.git", rev = "4e9ffc0" } -wasmprinter = "0.245.1" +wasmparser = "0.258.0" +wasmprinter = "0.258.0" [target.'cfg(not(target_family = "wasm"))'.dev-dependencies] # ezno-checker = { git = "https://github.com/kaleidawave/ezno.git", rev = "96d5058bdbb0cde924be008ca1e5a67fe39f46b9" } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a4540fe6..42ba26da 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-08-07" +channel = "nightly-2026-08-31" targets = [ "wasm32-unknown-unknown" ] \ No newline at end of file diff --git a/src/ir/blocks/special.rs b/src/ir/blocks/special.rs index c0b27b7c..e9acf8f0 100644 --- a/src/ir/blocks/special.rs +++ b/src/ir/blocks/special.rs @@ -106,7 +106,7 @@ pub fn from_special_block( 9 => { let hex = (*SHORTHAND_HEX_COLOUR_REGEX).replace(value, "$1$1$2$2$3$3"); if let Some(captures) = (*HEX_COLOUR_REGEX).captures(&hex) { - if let box [r, g, b] = (1..4) + if let deref!([r, g, b]) = (1..4) .map(|i| &captures[i]) .map(|capture| { u8::from_str_radix(capture, 16) diff --git a/src/lib.rs b/src/lib.rs index f752682d..6de882e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,14 @@ #![feature(stmt_expr_attributes)] // used in error.rs for panic mode #![feature(associated_type_defaults)] // used in registry.rs for default key type for NamedRegistry -#![feature(box_patterns)] // used in ir/blocks/special.rs to match Box<[_]> as array +#![feature(deref_patterns)] // used in ir/blocks/special.rs to match Box<[_]> as array #![feature(iterator_try_reduce)] // used in instructions/input_switcher.rs for building return type #![feature(try_find)] // used in ir/proc.rs for finding prototype/def blocks #![feature(arbitrary_self_types)] // used in ir/types.rs to take `&mut Rc` as self type for `TypeStack` +#![feature(macro_metavar_expr_concat)] +#![feature(macro_metavar_expr)] +#![feature(impl_restriction)] +#![feature(min_specialization)] + #![doc(html_logo_url = "https://hyperquark.edgecompute.app/logo.png")] #![doc(html_favicon_url = "https://hyperquark.edgecompute.app/favicon.ico")] #![warn(clippy::cargo, clippy::nursery, clippy::pedantic)] diff --git a/src/wasm/project.rs b/src/wasm/project.rs index 3bec2820..51d135ce 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -17,7 +17,7 @@ use crate::wasm::registries::functions::static_functions::{ }; use crate::wasm::registries::types::{ TFunc, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, - TTargetThreadsStruct, TThreadArray, TValType, + TTargetThreadsStruct, TThreadArray, TType, }; use crate::wasm::{StepFunc, StringsTable, WasmFlags}; @@ -603,9 +603,9 @@ impl WasmProject { let mut tick_func = Function::new(vec![ (3, ValType::I32), - (1, >::val_type(&types)?), - (1, >::val_type(&types)?), - (1, >::val_type(&types)?), + (1, >::ty(&types)?), + (1, >::ty(&types)?), + (1, >::ty(&types)?), ]); let stack_struct_type = types.register_comp::()?; diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs index 2ab31b27..0ea0cdea 100644 --- a/src/wasm/registries/functions/dyn_array.rs +++ b/src/wasm/registries/functions/dyn_array.rs @@ -7,7 +7,7 @@ use super::{MaybeStaticFunction, StaticFunction}; use crate::prelude::*; use crate::wasm::registries::TypeRegistry; use crate::wasm::registries::types::{ - TDefaultable, TDynArray, TDynArrayField, TNonNullable, TValType, + TDefaultable, TDynArray, TDynArrayField, TNonNullable, TType, }; #[derive(Clone)] @@ -21,14 +21,14 @@ pub struct DynArrayFuncOverride { /// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// t - the element pub struct DynArrayPush(PhantomData); -impl NamedRegistryItem for DynArrayPush { +impl + TDefaultable> NamedRegistryItem for DynArrayPush { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl +impl + TDefaultable> TryNamedRegistryItemOverride for DynArrayPush { fn try_override( @@ -96,13 +96,13 @@ impl }, ] as &[_]), params: Box::from([ - >>::val_type(&types)?, - T::val_type(&types)?, + >>::ty(&types)?, + T::ty(&types)?, ]), returns: Box::from([]), locals: Box::from([ ValType::I32, - >>::val_type(&types)?, + >>::ty(&types)?, ]), }), maybe_populate: || None, @@ -146,10 +146,10 @@ impl TryNamedRegistryItemOverride>>::val_type(&types)?, + >>::ty(&types)?, ValType::I32, ]), - returns: Box::from([T::val_type(&types)?]), + returns: Box::from([T::ty(&types)?]), locals: Box::from([]), }), maybe_populate: || None, @@ -193,11 +193,11 @@ impl TryNamedRegistryItemOverride>>::val_type(&types)?, + >>::ty(&types)?, ValType::I32, - T::val_type(&types)?, + T::ty(&types)?, ]), - returns: Box::from([T::val_type(&types)?]), + returns: Box::from([T::ty(&types)?]), locals: Box::from([]), }), maybe_populate: || None, @@ -252,8 +252,8 @@ impl TryNamedRegistryItemOverride>>::val_type(&types)?]), - returns: Box::from([T::val_type(&types)?]), + params: Box::from([>>::ty(&types)?]), + returns: Box::from([T::ty(&types)?]), locals: Box::from([ValType::I32]), }), maybe_populate: || None, @@ -293,7 +293,7 @@ impl TryNamedRegistryItemOverride>>::val_type(&types)?]), + returns: Box::from([>>::ty(&types)?]), locals: Box::from([]), }), maybe_populate: || None, @@ -332,7 +332,7 @@ impl TryNamedRegistryItemOverride>>::val_type(&types)?]), + params: Box::from([>>::ty(&types)?]), returns: Box::from([ValType::I32]), locals: Box::from([]), }), @@ -371,7 +371,7 @@ impl TryNamedRegistryItemOverride>>::val_type(&types)?]), + params: Box::from([>>::ty(&types)?]), returns: Box::from([ValType::I32]), locals: Box::from([]), }), diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index 5dc084fa..264ebcc9 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -7,7 +7,7 @@ use crate::wasm::mem_layout; use crate::wasm::registries::functions::dyn_array::{DynArrayNew, DynArrayPop, DynArrayPush}; use crate::wasm::registries::types::{ TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, - TThreadArray, TValType, + TThreadArray, TType, }; use crate::wasm::registries::{GlobalRegistry, StaticFunctionRegistry, TypeRegistry}; @@ -79,10 +79,10 @@ impl TryNamedRegistryItemOverride Call(imported_func_count + dyn_array_push), ] as &[_]), params: Box::from([ - >::val_type(&types)?, - >::val_type(&types)?, - StackStructRef::val_type(&types)?, - >::val_type(&types)?, + >::ty(&types)?, + >::ty(&types)?, + StackStructRef::ty(&types)?, + >::ty(&types)?, ]), returns: Box::from([]), locals: Box::from([]), @@ -126,11 +126,11 @@ impl TryNamedRegistryItemOverride export: None, params: Box::from([ ValType::I32, - >::val_type(&types)?, - StackStructRef::val_type(&types)?, + >::ty(&types)?, + StackStructRef::ty(&types)?, ]), returns: Box::from([]), - locals: Box::from([>::val_type(&types)?]), + locals: Box::from([>::ty(&types)?]), instructions: { (wasm_const![ LocalGet(0), diff --git a/src/wasm/registries/globals.rs b/src/wasm/registries/globals.rs index 4babf3bc..c06dd5e8 100644 --- a/src/wasm/registries/globals.rs +++ b/src/wasm/registries/globals.rs @@ -7,7 +7,7 @@ use wasm_encoder::{ use crate::prelude::*; use crate::registry::MapRegistry; use crate::wasm::registries::TypeRegistry; -use crate::wasm::registries::types::{TNonNullable, TTargetThreadArray, TThreadArray, TValType}; +use crate::wasm::registries::types::{TNonNullable, TTargetThreadArray, TThreadArray, TType}; #[derive(Copy, Clone, Debug)] pub struct GlobalMutable(pub bool); @@ -61,7 +61,7 @@ impl GlobalRegistry { self.register( "threadss".into(), ( - >::val_type(&types)?, + as TType>::ty(&types)?, ConstExpr::extended( (0..=num_sprites) // stage + sprites .map(|i| { diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index 8afd5ba1..046c2f23 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -78,207 +78,622 @@ impl TypeRegistry { } } -pub trait THeapType { - fn heap_type(types: &TypeRegistry) -> HQResult; +trait TypeRegisteringInfo { + fn types(&self) -> &TypeRegistry; } -impl THeapType for T +#[derive(Clone)] +struct RecGroupInfo { + types: Rc, + rec_group_start: u32, +} + +impl<'a> TypeRegisteringInfo for RecGroupInfo { + fn types(&self) -> &TypeRegistry { + &self.types + } +} + +impl TypeRegisteringInfo for TypeRegistry { + fn types(&self) -> &TypeRegistry { + &self + } +} + +pub impl(self) trait TRecGroupType { + fn rec_group_ty(registering_info: &I) -> HQResult; +} + +impl TRecGroupType for T +where + T: TRecGroupType, + I: TypeRegisteringInfo, +{ + default fn rec_group_ty(types: &I) -> HQResult { + Ok(HeapType::Concrete(T::rec_group_ty(types)?)) + } +} + +pub trait TType { + fn ty(types: &TypeRegistry) -> HQResult; +} + +impl TType for U +where + U: TRecGroupType, +{ + fn ty(types: &TypeRegistry) -> HQResult { + U::rec_group_ty(types) + } +} + +impl CompTimeRegistrand for T +where + T: TType, +{ + fn register(types: &TypeRegistry) -> HQResult { + T::ty(types) + } +} + +trait HasTypeDependencies { + type Dependencies: TypeList; + type RecGroupDependencies: TypeList; +} + +trait TypeList { + type Head; + type Tail: TypeList; + + type Concat: TypeList; +} +trait RegTypeList: TypeList { + fn register_each(types: &I) -> HQResult<()>; +} + +impl TypeList for () { + type Head = (); + type Tail = (); + + type Concat = Other; +} + +impl RegTypeList for () { + fn register_each(_types: &I) -> HQResult<()> { + Ok(()) + } +} + +impl TypeList for ((HeadT, Head),) { + type Head = (HeadT, Head); + type Tail = (); + + type Concat = ((HeadT, Head), Other); +} + +impl TypeList for ((HeadT, Head), Tail) +where + Tail: TypeList, +{ + type Head = (HeadT, Head); + type Tail = Tail; + + type Concat = ((HeadT, Head), Tail::Concat); +} + +impl RegTypeList for ((HeadT, Head), Tail) where - T: CompTimeRegistrand, + I: TypeRegisteringInfo, + Head: TRecGroupType, + Tail: RegTypeList, { - fn heap_type(types: &TypeRegistry) -> HQResult { - Ok(HeapType::Concrete(types.register_comp::()?)) + fn register_each(types: &I) -> HQResult<()> { + Head::rec_group_ty(types)?; + Tail::register_each(types) } } +// impl<'a, T, U> TRecGroupType for U +// where +// U: TType, +// { +// fn rec_group_ty(registering_info: &RecGroupInfo) -> HQResult { +// >::ty(registering_info.types) +// } +// } + pub struct TStructRef; -impl THeapType for TStructRef { - fn heap_type(_types: &TypeRegistry) -> HQResult { +impl TRecGroupType for TStructRef { + fn rec_group_ty(_types: &I) -> HQResult { + panic!("this shouldn't be called ever!!! evil!!!") + } +} +impl TRecGroupType for TStructRef { + fn rec_group_ty(_types: &I) -> HQResult { Ok(HeapType::Abstract { shared: false, ty: AbstractHeapType::Struct, }) } } +impl HasTypeDependencies for TStructRef { + type Dependencies = (); + type RecGroupDependencies = (); +} pub trait TRefType { - type HeapType: THeapType; + type HeapType; const NULLABLE: bool; +} - fn ref_type(types: &TypeRegistry) -> HQResult { +impl TRecGroupType for T +where + T: TRefType, + T::HeapType: TRecGroupType, + I: TypeRegisteringInfo, +{ + fn rec_group_ty(types: &I) -> HQResult { Ok(RefType { - nullable: Self::NULLABLE, - heap_type: Self::HeapType::heap_type(types)?, + nullable: T::NULLABLE, + heap_type: T::HeapType::rec_group_ty(types)?, }) } } -pub struct TNullable(PhantomData); -impl TRefType for TNullable +impl HasTypeDependencies for T where - T: THeapType, + T: TRefType, + T::HeapType: HasTypeDependencies, { - type HeapType = T; - const NULLABLE: bool = true; + type Dependencies = >::Dependencies; + type RecGroupDependencies = + >::RecGroupDependencies; } -impl TDefaultable for TNullable {} - -pub struct TNonNullable(PhantomData); -impl TRefType for TNonNullable +impl HasTypeDependencies for T where - T: THeapType, + T: TRefType, + T::HeapType: HasTypeDependencies, { + type Dependencies = >::Dependencies; + type RecGroupDependencies = + >::RecGroupDependencies; +} + +pub struct TNullable(PhantomData); +impl TRefType for TNullable { type HeapType = T; const NULLABLE: bool = true; } +impl TDefaultable for TNullable {} -pub trait TValType { - fn val_type(types: &TypeRegistry) -> HQResult; +pub struct TNonNullable(PhantomData); +impl TRefType for TNonNullable { + type HeapType = T; + const NULLABLE: bool = false; } -impl TValType for T +impl TRecGroupType for T where T: TRefType, + T::HeapType: TRecGroupType, + I: TypeRegisteringInfo, { - fn val_type(types: &TypeRegistry) -> HQResult { - Ok(ValType::Ref(T::ref_type(types)?)) + fn rec_group_ty(types: &I) -> HQResult { + Ok(ValType::Ref( + >::rec_group_ty(types)?, + )) } } pub struct TI32; -impl TValType for TI32 { - fn val_type(_types: &TypeRegistry) -> HQResult { +impl TRecGroupType for TI32 { + fn rec_group_ty(_types: &I) -> HQResult { Ok(ValType::I32) } } impl TDefaultable for TI32 {} +impl HasTypeDependencies for TI32 { + type Dependencies = (); + type RecGroupDependencies = (); +} pub trait TFieldType { - type ValType: TValType; + type ValType; const MUTABLE: bool; +} - fn field_type(types: &TypeRegistry) -> HQResult { +impl TRecGroupType for T +where + T: TFieldType, + I: TypeRegisteringInfo, + T::ValType: TRecGroupType, +{ + fn rec_group_ty(types: &I) -> HQResult { Ok(FieldType { - element_type: StorageType::Val(Self::ValType::val_type(types)?), - mutable: Self::MUTABLE, + element_type: StorageType::Val(T::ValType::rec_group_ty(types)?), + mutable: T::MUTABLE, }) } } +impl HasTypeDependencies for T +where + T: TFieldType, + T::ValType: HasTypeDependencies, +{ + type Dependencies = >::Dependencies; + type RecGroupDependencies = >::RecGroupDependencies; +} + pub struct TMutField(PhantomData); pub struct TConstField(PhantomData); -impl TFieldType for TMutField { +impl TFieldType for TMutField { type ValType = T; const MUTABLE: bool = true; } -impl TFieldType for TConstField { +impl TFieldType for TConstField { type ValType = T; const MUTABLE: bool = false; } -pub trait TDefaultable: TValType {} +pub trait TDefaultable {} -trait TFieldList { - fn fields(types: &TypeRegistry) -> HQResult>; -} - -impl TFieldList for () { - fn fields(_: &TypeRegistry) -> HQResult> { +impl TRecGroupType, I> for () { + fn rec_group_ty(_types: &I) -> HQResult> { Ok(vec![]) } } -impl TFieldList for (Head, Tail) +impl TRecGroupType, I> for (Head, Tail) where - Head: TFieldList, - Tail: TFieldType, + I: TypeRegisteringInfo, + Head: TRecGroupType, + Tail: TRecGroupType, I>, { - fn fields(types: &TypeRegistry) -> HQResult> { - let mut fields = Head::fields(types)?; - fields.push(Tail::field_type(types)?); - Ok(fields) + fn rec_group_ty(types: &I) -> HQResult> { + let mut tys = vec![Head::rec_group_ty(types)?]; + tys.extend(Tail::rec_group_ty(types)?); + Ok(tys) } } pub struct TStruct(PhantomData); -impl CompTimeRegistrand for TStruct +impl TRecGroupType for TStruct where - Fields: TFieldList, + I: TypeRegisteringInfo, + Fields: TRecGroupType, I>, { - fn register(types: &TypeRegistry) -> HQResult { - types.struct_(Fields::fields(types)?) + fn rec_group_ty(types: &I) -> HQResult { + types.types().struct_(Fields::rec_group_ty(types)?) } } +struct TTypeListMarker(PhantomData); + +impl HasTypeDependencies> for () { + type Dependencies = (); + type RecGroupDependencies = (); +} + +impl HasTypeDependencies> for (Head, Tail) +where + Head: HasTypeDependencies, + Head::Dependencies: TypeList, + Head::RecGroupDependencies: TypeList, + Tail: HasTypeDependencies>, + Tail::Dependencies: TypeList, + Tail::RecGroupDependencies: TypeList, +{ + type Dependencies = <>::Dependencies as TypeList>::Concat< + >>::Dependencies, + >; + type RecGroupDependencies = + <>::RecGroupDependencies as TypeList>::Concat< + >>::RecGroupDependencies, + >; +} + +trait CompoundTypeDependencies { + type Dependencies: TypeList; + type RecGroupDependencies: TypeList; +} + +impl CompoundTypeDependencies for TStruct +where + Fields: TRecGroupType, TypeRegistry> + + HasTypeDependencies>, + Fields::Dependencies: TypeList, +{ + type Dependencies = <((HeapType, Self),) as TypeList>::Concat; + + type RecGroupDependencies = (); +} + +impl CompoundTypeDependencies for TStruct +where + Fields: TRecGroupType, RecGroupInfo> + + HasTypeDependencies>, + Fields::RecGroupDependencies: TypeList, +{ + type Dependencies = Fields::Dependencies; + + type RecGroupDependencies = + <((HeapType, Self),) as TypeList>::Concat; +} + +impl HasTypeDependencies for TStruct +where + Fields: TRecGroupType, RecGroupInfo> + + HasTypeDependencies>, + Self: CompoundTypeDependencies< + Fields, + >>::RecGroupDependencies, + >, +{ + type Dependencies = + >::Dependencies; + + type RecGroupDependencies = >::RecGroupDependencies; +} + pub struct TArray(PhantomData); -impl CompTimeRegistrand for TArray { - fn register(types: &TypeRegistry) -> HQResult { - types.array( - StorageType::Val(Field::ValType::val_type(types)?), +impl TRecGroupType for TArray +where + I: TypeRegisteringInfo, + Field: TFieldType, + Field::ValType: TRecGroupType, +{ + fn rec_group_ty(types: &I) -> HQResult { + types.types().array( + StorageType::Val(Field::ValType::rec_group_ty(types)?), Field::MUTABLE, ) } } -trait TValTypeList { - fn val_types(types: &TypeRegistry) -> HQResult>; +impl CompoundTypeDependencies for TArray +where + Field: TFieldType //TRecGroupType + + HasTypeDependencies, + Field::ValType: TType, +{ + type Dependencies = <((HeapType, Self),) as TypeList>::Concat; + + type RecGroupDependencies = (); } -impl TValTypeList for () { - fn val_types(_: &TypeRegistry) -> HQResult> { - Ok(vec![]) - } +impl CompoundTypeDependencies for TArray +where + (Head, Tail): TypeList, + Field: TFieldType + HasTypeDependencies, +{ + type Dependencies = Field::Dependencies; + + type RecGroupDependencies = + <((HeapType, Self),) as TypeList>::Concat; } -impl TValTypeList for (Head, Tail) +impl HasTypeDependencies for TArray where - Head: TValTypeList, - Tail: TValType, + Field: TFieldType + HasTypeDependencies, + Self: CompoundTypeDependencies< + Field, + >::RecGroupDependencies, + >, { - fn val_types(types: &TypeRegistry) -> HQResult> { - let mut val_types = Head::val_types(types)?; - val_types.push(Tail::val_type(types)?); - Ok(val_types) - } + type Dependencies = + >::Dependencies; + + type RecGroupDependencies = >::RecGroupDependencies; } pub struct TFunc(PhantomData, PhantomData); -impl CompTimeRegistrand for TFunc +impl TRecGroupType for TFunc where - Params: TValTypeList, - Result: TValTypeList, + I: TypeRegisteringInfo, + Params: TRecGroupType, I>, + Result: TRecGroupType, I>, { - fn register(types: &TypeRegistry) -> HQResult { - types.function(Params::val_types(types)?, Result::val_types(types)?) + fn rec_group_ty(types: &I) -> HQResult { + types + .types() + .function(Params::rec_group_ty(types)?, Result::rec_group_ty(types)?) + } +} + +impl CompoundTypeDependencies<(Params, Results), ()> for TFunc +where + Params: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Results: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, +{ + type Dependencies = + <<((HeapType, Self),) as TypeList>::Concat as TypeList>::Concat< + Results::Dependencies, + >; + + type RecGroupDependencies = (); +} + +impl CompoundTypeDependencies<(Params, Results), (Head, Tail)> + for TFunc +where + Params: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Results: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, +{ + type Dependencies = ::Concat; + + type RecGroupDependencies = <<((HeapType, Self),) as TypeList>::Concat< + Params::RecGroupDependencies, + > as TypeList>::Concat; +} + +impl HasTypeDependencies for TFunc +where + Params: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Results: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Self: CompoundTypeDependencies< + (Params, Results), + <>>::RecGroupDependencies as TypeList>::Concat<>>::RecGroupDependencies>, + >, +{ + type Dependencies = + >>::RecGroupDependencies as TypeList>::Concat<>>::RecGroupDependencies>, + >>::Dependencies; + type RecGroupDependencies = + >>::RecGroupDependencies as TypeList>::Concat<>>::RecGroupDependencies>, + >>::RecGroupDependencies; +} + +macro_rules! rec_group { + ( + $rec_group_name:ident { + $($name:ident = $typename:ident{$($typeparams:tt)+};)+ + } + ) => { + macro_rules! ${ concat($rec_group_name, _sub_rec_group_types) } { + ( + ${concat($rec_group_name, _sub_rec_group_types)}!($$($$macro_args:tt)+) + ) => { + ${concat($rec_group_name, _sub_rec_group_types)}!($$($$macro_args)+) + }; + ( + $$ty:ident{$$({$$($$params:tt)+}),+} + ) => { + $$ty< + $$( + ${concat($rec_group_name, _sub_rec_group_types)}!( + $$($$params)+ + ) + ),+ + > + }; + $( + ($name) => { + TRecGroupItem<${ index() }> + }; + )+ + ($$ty:ident) => { + $$ty + }; + (()) => {()}; + ( + ({$$($$first:tt)+},) + ) => { + ( + ${concat($rec_group_name, _sub_rec_group_types)}!( + $$($$first)+ + ), + () + ) + }; + ( + ({$$($$first:tt)+}, $$({$$($$rest:tt)+}),+ $$(,)?) + ) => { + ( + ${concat($rec_group_name, _sub_rec_group_types)}!( + $$($$first)+ + ), + ${concat($rec_group_name, _sub_rec_group_types)}!( + ($$({$$($$rest)+},)+) + ) + ) + }; + } + + fn ${ concat($rec_group_name, _register_deps) }(types: &TypeRegistry) -> HQResult<()> { + $( + <${concat($name, Type)} as HasTypeDependencies>::Dependencies::register_each(types)?; + )+ + Ok(()) + } + + $( + type ${concat($name, Type)} = ${ concat($rec_group_name, _sub_rec_group_types) }!( + $typename{$($typeparams)+} + ); + + pub struct $name; + + impl CompTimeRegistrand for $name { + fn register(types: &TypeRegistry) -> HQResult { + ${ concat($rec_group_name, _register_deps) }(types)?; + hq_todo!() + // let rec_group_info = RecGroupInfo { + // types, + // rec_group_start: types.registry().len() as u32, + // }; + // $( + // $name::rec_group_ty(&rec_group_info)?; + // ) + + } + } + )+ } } -pub type TStepFunc = TFunc<(((), TNonNullable), TNullable), ()>; +pub struct TRecGroupItem; + +impl HasTypeDependencies for TRecGroupItem { + type Dependencies = (); + type RecGroupDependencies = ((HeapType, Self), ()); +} + +impl<'a, const I: u32> TRecGroupType for TRecGroupItem { + fn rec_group_ty(registering_info: &RecGroupInfo) -> HQResult { + Ok(HeapType::Concrete(registering_info.rec_group_start + I)) + } +} + +rec_group! { + rec_grp { + TStepFunc = TFunc{ + {( + {TNonNullable{{TStackArray}}}, + {TNullable{{TStructRef}}}, + )}, + {()} + }; + TStackStruct = TStruct{{( + {TMutField{{TNonNullable{{TStepFunc}}}}}, + {TConstField{{TNullable{{TStructRef}}}}}, + )}}; + TStackDynArrayField = TArray{{TMutField{{TNullable{{TStackStruct}}}}}}; + TStackArray = TDynArray{{TNullable{{TStackStruct}}}}; + } +} pub type TDynArrayField = TArray>; pub type TDynArray = TStruct<( - ((), TMutField>>), - TMutField, + TMutField>>, + (TMutField, ()), )>; -pub type TStackStruct = TStruct<( - ((), TMutField>), - TConstField>, -)>; - -pub type TStackArray = TDynArray>; - pub type TThreadArray = TDynArray>; -pub type TTargetThreadsStruct = TStruct<( - ((), TMutField), - TMutField>, -)>; +pub type TTargetThreadsStruct = + TStruct<(TMutField, (TMutField>, ()))>; pub type TTargetThreadArray = TArray>>; From 349d5060d4238b5032e3716606c45689616dd289 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Thu, 10 Sep 2026 19:00:19 +0100 Subject: [PATCH 10/18] get rec types to compile; adapt yield to new type layout --- rust-toolchain.toml | 2 +- .../event/poll_waiting_threads.rs | 14 +- src/instructions/hq/yield.rs | 122 ++-- src/instructions/procedures/argument.rs | 11 +- src/lib.rs | 5 +- src/registry.rs | 6 +- src/wasm/project.rs | 4 +- src/wasm/registries.rs | 2 +- src/wasm/registries/functions/dyn_array.rs | 80 +-- .../registries/functions/spawn_threads.rs | 10 +- src/wasm/registries/globals.rs | 5 +- src/wasm/registries/types.rs | 678 +----------------- src/wasm/registries/types/dependencies.rs | 218 ++++++ src/wasm/registries/types/rec_group.rs | 172 +++++ src/wasm/registries/types/registration.rs | 261 +++++++ src/wasm/registries/types/registry.rs | 118 +++ src/wasm/registries/types/subtypes.rs | 73 ++ src/wasm/registries/types/tyfp.rs | 157 ++++ 18 files changed, 1123 insertions(+), 815 deletions(-) create mode 100644 src/wasm/registries/types/dependencies.rs create mode 100644 src/wasm/registries/types/rec_group.rs create mode 100644 src/wasm/registries/types/registration.rs create mode 100644 src/wasm/registries/types/registry.rs create mode 100644 src/wasm/registries/types/subtypes.rs create mode 100644 src/wasm/registries/types/tyfp.rs diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 42ba26da..7c910d00 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-08-31" +channel = "nightly-2026-09-10" targets = [ "wasm32-unknown-unknown" ] \ No newline at end of file diff --git a/src/instructions/event/poll_waiting_threads.rs b/src/instructions/event/poll_waiting_threads.rs index 0d6df6c4..6769f1f8 100644 --- a/src/instructions/event/poll_waiting_threads.rs +++ b/src/instructions/event/poll_waiting_threads.rs @@ -10,12 +10,12 @@ use super::super::prelude::*; use crate::wasm::StepFunc; use crate::wasm::registries::functions::static_functions::DynArrayLen; use crate::wasm::registries::types::{ - TArray, TConstField, THeapType, TMutField, TNonNullable, TNullable, TStackArray, TStackStruct, - TStruct, TValType, + TArray, TConstField, TMutField, TNonNullable, TNullable, TStackArray, TStackStruct, TStruct, + TType, }; type TWaitingThreadArray = TArray>>; -type TPollStruct = TStruct<((), TConstField>)>; +type TPollStruct = TStruct<(TConstField>, ())>; pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult> { let types = Rc::clone(func.registries().types()); @@ -23,12 +23,12 @@ pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult()?; let poll_struct_type = types.register_comp::()?; - let arr_local = func.local(>::val_type(&types)?)?; + let arr_local = func.local(>::ty(&types)?)?; func.free_local(arr_local)?; let arr_len_local = func.local(ValType::I32)?; let i_local = func.local(ValType::I32)?; - let stack_local = func.local(>::val_type(&types)?)?; + let stack_local = func.local(>::ty(&types)?)?; let wait_local = func.local(ValType::I32)?; func.free_local(arr_len_local)?; func.free_local(stack_local)?; @@ -42,7 +42,7 @@ pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult) -> HQResult, Fields { mode: yield_mode }: &Fields, ) -> HQResult> { - let threads_count = func.registries().globals().threads_count()?; - Ok(match yield_mode { YieldMode::None => { - let threads_table = func - .registries() - .tables() - .threads_table(func.target(), func.registries().types())?; - let thread_struct_ty = func.registries().types().thread_struct_type()?; - let stack_array_ty = func.registries().types().stack_array_type()?; - let stack_struct_ty = func.registries().types().stack_struct_type()?; - let thread_struct_local = func.local(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(thread_struct_ty), - }))?; - let stack_struct_local = func.local(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(stack_struct_ty), - }))?; - let i32_local = func.local(ValType::I32)?; - let step_func_ty = func.registries().types().register_comp::()?; - func.free_local(thread_struct_local)?; - func.free_local(stack_struct_local)?; - func.free_local(i32_local)?; + let static_functions = Rc::clone(func.registries().static_functions()); + let types = Rc::clone(func.registries().types()); + + let pop_stack = + static_functions.register::>, _>()?; + let stack_len = + static_functions.register::>, _>()?; + let stack_get = + static_functions.register::>, _>()?; + + let step_struct_ty = TStackStruct::ty(&types)?; + + let stack_len_local = func.local(ValType::I32)?; + let step_struct_local = func.local(>::ty(&types)?)?; + func.free_local(step_struct_local)?; + func.free_local(stack_len_local)?; wasm![ LocalGet(0), - TableGet(threads_table), - RefAsNonNull, - LocalTee(thread_struct_local), - StructGet { struct_type_index: thread_struct_ty, field_index: 0 }, - I32Const(1), - I32Sub, - LocalTee(i32_local), + #StaticFunctionCall(pop_stack), + LocalGet(0), + #StaticFunctionCall(stack_len), I32Eqz, If(BlockType::Empty), - #LazyGlobalGet(threads_count), - I32Const(1), - I32Sub, - #LazyGlobalSet(threads_count), - LocalGet(0), - RefNull(HeapType::Concrete(thread_struct_ty)), - TableSet(threads_table), + // Empty stack cleanup (if it happens at all) will happen in scheduler, not here. Return, Else, - LocalGet(thread_struct_local), - LocalGet(i32_local), - StructSet { - struct_type_index: thread_struct_ty, - field_index: 0, - }, - LocalGet(thread_struct_local), - StructGet { - struct_type_index: thread_struct_ty, - field_index: 1, - }, - LocalGet(i32_local), + LocalGet(0), + LocalGet(0), + LocalGet(0), + LocalGet(stack_len_local), I32Const(1), I32Sub, - ArrayGet(stack_array_ty), + #StaticFunctionCall(stack_get), RefAsNonNull, - LocalSet(stack_struct_local), - LocalGet((func.params().len() - 2).try_into().map_err(|_| make_hq_bug!("local index out of bounds"))?), - LocalGet(stack_struct_local), + LocalTee(step_struct_local), StructGet { - struct_type_index: stack_struct_ty, + struct_type_index: step_struct_ty, field_index: 1, }, - LocalGet(stack_struct_local), + LocalGet(step_struct_local), StructGet { - struct_type_index: stack_struct_ty, + struct_type_index: step_struct_ty, field_index: 0, }, - ReturnCallRef(step_func_ty), + ReturnCallRef(TStepFunc::ty(&types)?), End, ] } @@ -142,33 +117,24 @@ pub fn wasm( func.compile_inner_step(Rc::clone(step))? } YieldMode::Schedule(step_index) => { - let threads_table = func - .registries() - .tables() - .threads_table(func.target(), func.registries().types())?; - let thread_struct_ty = func.registries().types().thread_struct_type()?; - let local = func.local(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(thread_struct_ty), - }))?; - func.free_local(local)?; - let stack_array_ty = func.registries().types().stack_array_type()?; - let stack_struct_ty = func.registries().types().stack_struct_type()?; + let static_functions = Rc::clone(func.registries().static_functions()); + let types = Rc::clone(func.registries().types()); + + let stack_len = + static_functions.register::>, _>()?; + let stack_get = + static_functions.register::>, _>()?; wasm![ LocalGet(0), - TableGet(threads_table), - RefAsNonNull, - LocalTee(local), - StructGet { struct_type_index: thread_struct_ty, field_index: 1 }, - LocalGet(local), - StructGet { struct_type_index: thread_struct_ty, field_index: 0 }, + LocalGet(0), + #StaticFunctionCall(stack_len), I32Const(1), I32Sub, - ArrayGet(stack_array_ty), + #StaticFunctionCall(stack_get), RefAsNonNull, #LazyStepRef(*step_index), - StructSet { struct_type_index: stack_struct_ty, field_index: 0 }, + StructSet { struct_type_index: TStackStruct::ty(&types)?, field_index: 0 }, Return ] } diff --git a/src/instructions/procedures/argument.rs b/src/instructions/procedures/argument.rs index 375cf37f..da6942ba 100644 --- a/src/instructions/procedures/argument.rs +++ b/src/instructions/procedures/argument.rs @@ -2,7 +2,7 @@ use wasm_encoder::{AbstractHeapType, HeapType}; use super::super::prelude::*; use crate::ir::RcVar; -use crate::wasm::registries::types::CompoundType; +use crate::wasm::registries::types::{CompoundType, RegistryItem}; use crate::wasm::{StepFunc, WasmProject}; #[derive(Clone, Debug)] @@ -72,10 +72,11 @@ pub fn wasm( .proc_arg_struct_type(&(**arg_vars).borrow())?; let registries = func.registries(); let type_registry = registries.types().registry().borrow(); - let CompoundType::Struct(struct_type_fields) = type_registry - .get_index(struct_type_index as usize) - .ok_or_else(|| make_hq_bug!("type index not found in type registry"))? - .0 + let RegistryItem::Type(CompoundType::Struct(struct_type_fields)) = // TODO: do we need to consider the possibility of rec group items? + type_registry + .get_index(struct_type_index as usize) + .ok_or_else(|| make_hq_bug!("type index not found in type registry"))? + .0 else { hq_bug!("struct type was not a struct type") }; diff --git a/src/lib.rs b/src/lib.rs index 6de882e0..d098641a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,9 @@ #![feature(arbitrary_self_types)] // used in ir/types.rs to take `&mut Rc` as self type for `TypeStack` #![feature(macro_metavar_expr_concat)] #![feature(macro_metavar_expr)] -#![feature(impl_restriction)] -#![feature(min_specialization)] +#![feature(specialization)] +#![feature(const_type_name)] +#![feature(generic_const_exprs)] #![doc(html_logo_url = "https://hyperquark.edgecompute.app/logo.png")] #![doc(html_favicon_url = "https://hyperquark.edgecompute.app/favicon.ico")] diff --git a/src/registry.rs b/src/registry.rs index 1b992bc2..3232883d 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -75,7 +75,9 @@ pub trait RegistryType { } pub trait CompTimeRegistrand { - fn register(registry: &R) -> HQResult; + type Receiver: core::ops::Deref; + + fn register(registry: &Self::Receiver) -> HQResult; } pub trait Registry: Sized + RegistryType { @@ -121,7 +123,7 @@ pub trait Registry: Sized + RegistryType { .map_err(|_| make_hq_bug!("registry item index out of bounds")) } - fn register_comp(&self) -> HQResult + fn register_comp(self: &R::Receiver) -> HQResult where R: CompTimeRegistrand, N: RegistryResult, diff --git a/src/wasm/project.rs b/src/wasm/project.rs index 51d135ce..9aaf3925 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -669,13 +669,13 @@ impl WasmProject { .static_functions() .register::>, u32>()? ), - LocalTee(LOCAL_STEP), RefAsNonNull, + LocalTee(LOCAL_STEP), StructGet { struct_type_index: stack_struct_type, field_index: 1, }, - LocalGet(3), + LocalGet(LOCAL_STEP), StructGet { struct_type_index: stack_struct_type, field_index: 0, diff --git a/src/wasm/registries.rs b/src/wasm/registries.rs index 376f6520..0900e046 100644 --- a/src/wasm/registries.rs +++ b/src/wasm/registries.rs @@ -80,7 +80,7 @@ impl Registries { &self.tables } - pub fn globals(&self) -> &Rc { + pub const fn globals(&self) -> &Rc { &self.globals } diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs index 0ea0cdea..fb65aa54 100644 --- a/src/wasm/registries/functions/dyn_array.rs +++ b/src/wasm/registries/functions/dyn_array.rs @@ -18,10 +18,12 @@ pub struct DynArrayFuncOverride { /// Pushes an element to a dynamic (resizeable) array /// /// Takes 2 parameters: -/// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) +/// ref `dynamic_array` - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// t - the element pub struct DynArrayPush(PhantomData); -impl + TDefaultable> NamedRegistryItem for DynArrayPush { +impl + TDefaultable> NamedRegistryItem + for DynArrayPush +{ const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, @@ -95,15 +97,9 @@ impl + TDefaultable> field_index: 1, }, ] as &[_]), - params: Box::from([ - >>::ty(&types)?, - T::ty(&types)?, - ]), + params: Box::from([>>::ty(&types)?, T::ty(&types)?]), returns: Box::from([]), - locals: Box::from([ - ValType::I32, - >>::ty(&types)?, - ]), + locals: Box::from([ValType::I32, >>::ty(&types)?]), }), maybe_populate: || None, }) @@ -113,20 +109,20 @@ impl + TDefaultable> /// Gets an element of a dynamic (resizeable) array /// /// Takes 2 parameters: -/// ref dynamic_array - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) +/// ref `dynamic_array` - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// i32 - the index /// /// Returns t pub struct DynArrayGet(PhantomData); -impl NamedRegistryItem for DynArrayGet { +impl + TDefaultable> NamedRegistryItem for DynArrayGet { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride - for DynArrayGet +impl + TDefaultable> + TryNamedRegistryItemOverride for DynArrayGet { fn try_override( DynArrayFuncOverride { types }: DynArrayFuncOverride, @@ -145,10 +141,7 @@ impl TryNamedRegistryItemOverride>>::ty(&types)?, - ValType::I32, - ]), + params: Box::from([>>::ty(&types)?, ValType::I32]), returns: Box::from([T::ty(&types)?]), locals: Box::from([]), }), @@ -160,19 +153,19 @@ impl TryNamedRegistryItemOverride - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) +/// ref `dynamic_array` - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// i32 - the index /// t - the element pub struct DynArraySet(PhantomData); -impl NamedRegistryItem for DynArraySet { +impl + TDefaultable> NamedRegistryItem for DynArraySet { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride - for DynArraySet +impl + TDefaultable> + TryNamedRegistryItemOverride for DynArraySet { fn try_override( DynArrayFuncOverride { types }: DynArrayFuncOverride, @@ -207,20 +200,20 @@ impl TryNamedRegistryItemOverride - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) +/// Takes 1 parameter: +/// ref `dynamic_array` - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// /// Returns t pub struct DynArrayPop(PhantomData); -impl NamedRegistryItem for DynArrayPop { +impl + TDefaultable> NamedRegistryItem for DynArrayPop { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride - for DynArrayPop +impl + TDefaultable> + TryNamedRegistryItemOverride for DynArrayPop { fn try_override( DynArrayFuncOverride { types }: DynArrayFuncOverride, @@ -263,20 +256,20 @@ impl TryNamedRegistryItemOverride +/// Returns ref `dynamic_array` pub struct DynArrayNew(PhantomData); -impl NamedRegistryItem for DynArrayNew { +impl + TDefaultable> NamedRegistryItem for DynArrayNew { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride - for DynArrayNew +impl + TDefaultable> + TryNamedRegistryItemOverride for DynArrayNew { fn try_override( DynArrayFuncOverride { types }: DynArrayFuncOverride, @@ -303,20 +296,20 @@ impl TryNamedRegistryItemOverride - the dynamic array +/// Takes 1 parameter: +/// ref `dynamic_array` - the dynamic array /// /// Returns i32 pub struct DynArrayLen(PhantomData); -impl NamedRegistryItem for DynArrayLen { +impl + TDefaultable> NamedRegistryItem for DynArrayLen { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride - for DynArrayLen +impl + TDefaultable> + TryNamedRegistryItemOverride for DynArrayLen { fn try_override( DynArrayFuncOverride { types }: DynArrayFuncOverride, @@ -343,18 +336,18 @@ impl TryNamedRegistryItemOverride - the dynamic array +/// Takes 1 parameter: +/// ref `dynamic_array` - the dynamic array pub struct DynArrayClear(PhantomData); -impl NamedRegistryItem for DynArrayClear { +impl + TDefaultable> NamedRegistryItem for DynArrayClear { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, maybe_populate: || None, }; } -impl TryNamedRegistryItemOverride - for DynArrayClear +impl + TDefaultable> + TryNamedRegistryItemOverride for DynArrayClear { fn try_override( DynArrayFuncOverride { types }: DynArrayFuncOverride, @@ -379,6 +372,3 @@ impl TryNamedRegistryItemOverride; /// Spawns a new thread in the same stack (i.e. a thread that yields back to the current -/// thread once it completes.) The step that is provided to return to will be written into +/// thread once it completes). +/// +/// The step that is provided to return to will be written into /// the current stack frame, and the new thread's step is added to the top of the current /// frame with the provided struct argument so that that will run until completion before /// yielding to the provided next step. /// /// Takes 4 parameters: -/// - ref stack_array - the current stack -/// - ref step_func - the step to spawn +/// - ref `stack_array`` - the current stack +/// - ref `step_func`` - the step to spawn /// - structref - the structref to pass to the step being spawned -/// - ref step_func - the step to return to after +/// - ref `step_func`` - the step to return to after pub struct SpawnThreadInStack; impl NamedRegistryItem for SpawnThreadInStack { const VALUE: MaybeStaticFunction = MaybeStaticFunction { diff --git a/src/wasm/registries/globals.rs b/src/wasm/registries/globals.rs index c06dd5e8..434da9ec 100644 --- a/src/wasm/registries/globals.rs +++ b/src/wasm/registries/globals.rs @@ -61,10 +61,10 @@ impl GlobalRegistry { self.register( "threadss".into(), ( - as TType>::ty(&types)?, + as TType>::ty(types)?, ConstExpr::extended( (0..=num_sprites) // stage + sprites - .map(|i| { + .flat_map(|i| { [ Instruction::I32Const(i as i32), Instruction::I32Const(0), @@ -74,7 +74,6 @@ impl GlobalRegistry { }, ] }) - .flatten() .chain([Instruction::ArrayNewFixed { array_type_index: array_array_type, array_size: num_sprites, diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index 046c2f23..16775948 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -1,671 +1,20 @@ -use core::marker::PhantomData; +use wasm_encoder::HeapType; -use wasm_encoder::{ - AbstractHeapType, FieldType, HeapType, RefType, StorageType, TypeSection, ValType, -}; - -use crate::ir::RcVar; use crate::prelude::*; -use crate::registry::{CompTimeRegistrand, RegistryResult, SetRegistry}; -use crate::wasm::WasmProject; - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum CompoundType { - Function(Vec, Vec), - Array(StorageType, bool), - Struct(Vec), -} - -pub type TypeRegistry = SetRegistry; - -impl TypeRegistry { - pub fn function(&self, params: Vec, returns: Vec) -> HQResult - where - N: RegistryResult, - { - self.register_default(CompoundType::Function(params, returns)) - } - - pub fn array(&self, elem_type: StorageType, mutable: bool) -> HQResult - where - N: RegistryResult, - { - self.register_default(CompoundType::Array(elem_type, mutable)) - } - - pub fn struct_(&self, fields: Vec) -> HQResult - where - N: RegistryResult, - { - self.register_default(CompoundType::Struct(fields)) - } - - pub const STRUCT_REF: ValType = ValType::Ref(RefType { - nullable: true, - heap_type: HeapType::Abstract { - shared: false, - ty: AbstractHeapType::Struct, - }, - }); - - pub fn proc_arg_struct_type( - &self, - arg_vars: &core::cell::Ref<'_, Vec>, - ) -> HQResult { - self.struct_( - arg_vars - .iter() - .map(|var| { - Ok(FieldType { - mutable: false, - element_type: StorageType::Val(WasmProject::ir_type_to_wasm( - *var.possible_types(), - )), - }) - }) - .collect::>>()?, - ) - } - - pub fn finish(self, types: &mut TypeSection) { - for ty in self.registry().take().keys().cloned() { - match ty { - CompoundType::Function(params, results) => types.ty().function(params, results), - CompoundType::Array(elem_type, mutable) => types.ty().array(&elem_type, mutable), - CompoundType::Struct(fields) => types.ty().struct_(fields), - } - } - } -} - -trait TypeRegisteringInfo { - fn types(&self) -> &TypeRegistry; -} - -#[derive(Clone)] -struct RecGroupInfo { - types: Rc, - rec_group_start: u32, -} - -impl<'a> TypeRegisteringInfo for RecGroupInfo { - fn types(&self) -> &TypeRegistry { - &self.types - } -} - -impl TypeRegisteringInfo for TypeRegistry { - fn types(&self) -> &TypeRegistry { - &self - } -} - -pub impl(self) trait TRecGroupType { - fn rec_group_ty(registering_info: &I) -> HQResult; -} - -impl TRecGroupType for T -where - T: TRecGroupType, - I: TypeRegisteringInfo, -{ - default fn rec_group_ty(types: &I) -> HQResult { - Ok(HeapType::Concrete(T::rec_group_ty(types)?)) - } -} - -pub trait TType { - fn ty(types: &TypeRegistry) -> HQResult; -} - -impl TType for U -where - U: TRecGroupType, -{ - fn ty(types: &TypeRegistry) -> HQResult { - U::rec_group_ty(types) - } -} - -impl CompTimeRegistrand for T -where - T: TType, -{ - fn register(types: &TypeRegistry) -> HQResult { - T::ty(types) - } -} - -trait HasTypeDependencies { - type Dependencies: TypeList; - type RecGroupDependencies: TypeList; -} - -trait TypeList { - type Head; - type Tail: TypeList; - - type Concat: TypeList; -} -trait RegTypeList: TypeList { - fn register_each(types: &I) -> HQResult<()>; -} - -impl TypeList for () { - type Head = (); - type Tail = (); - - type Concat = Other; -} - -impl RegTypeList for () { - fn register_each(_types: &I) -> HQResult<()> { - Ok(()) - } -} - -impl TypeList for ((HeadT, Head),) { - type Head = (HeadT, Head); - type Tail = (); - - type Concat = ((HeadT, Head), Other); -} - -impl TypeList for ((HeadT, Head), Tail) -where - Tail: TypeList, -{ - type Head = (HeadT, Head); - type Tail = Tail; - - type Concat = ((HeadT, Head), Tail::Concat); -} - -impl RegTypeList for ((HeadT, Head), Tail) -where - I: TypeRegisteringInfo, - Head: TRecGroupType, - Tail: RegTypeList, -{ - fn register_each(types: &I) -> HQResult<()> { - Head::rec_group_ty(types)?; - Tail::register_each(types) - } -} - -// impl<'a, T, U> TRecGroupType for U -// where -// U: TType, -// { -// fn rec_group_ty(registering_info: &RecGroupInfo) -> HQResult { -// >::ty(registering_info.types) -// } -// } - -pub struct TStructRef; -impl TRecGroupType for TStructRef { - fn rec_group_ty(_types: &I) -> HQResult { - panic!("this shouldn't be called ever!!! evil!!!") - } -} -impl TRecGroupType for TStructRef { - fn rec_group_ty(_types: &I) -> HQResult { - Ok(HeapType::Abstract { - shared: false, - ty: AbstractHeapType::Struct, - }) - } -} -impl HasTypeDependencies for TStructRef { - type Dependencies = (); - type RecGroupDependencies = (); -} - -pub trait TRefType { - type HeapType; - const NULLABLE: bool; -} - -impl TRecGroupType for T -where - T: TRefType, - T::HeapType: TRecGroupType, - I: TypeRegisteringInfo, -{ - fn rec_group_ty(types: &I) -> HQResult { - Ok(RefType { - nullable: T::NULLABLE, - heap_type: T::HeapType::rec_group_ty(types)?, - }) - } -} - -impl HasTypeDependencies for T -where - T: TRefType, - T::HeapType: HasTypeDependencies, -{ - type Dependencies = >::Dependencies; - type RecGroupDependencies = - >::RecGroupDependencies; -} -impl HasTypeDependencies for T -where - T: TRefType, - T::HeapType: HasTypeDependencies, -{ - type Dependencies = >::Dependencies; - type RecGroupDependencies = - >::RecGroupDependencies; -} - -pub struct TNullable(PhantomData); -impl TRefType for TNullable { - type HeapType = T; - const NULLABLE: bool = true; -} -impl TDefaultable for TNullable {} - -pub struct TNonNullable(PhantomData); -impl TRefType for TNonNullable { - type HeapType = T; - const NULLABLE: bool = false; -} - -impl TRecGroupType for T -where - T: TRefType, - T::HeapType: TRecGroupType, - I: TypeRegisteringInfo, -{ - fn rec_group_ty(types: &I) -> HQResult { - Ok(ValType::Ref( - >::rec_group_ty(types)?, - )) - } -} -pub struct TI32; +mod dependencies; +mod registration; +#[macro_use] +mod rec_group; +mod registry; +mod tyfp; +mod subtypes; -impl TRecGroupType for TI32 { - fn rec_group_ty(_types: &I) -> HQResult { - Ok(ValType::I32) - } -} -impl TDefaultable for TI32 {} -impl HasTypeDependencies for TI32 { - type Dependencies = (); - type RecGroupDependencies = (); -} - -pub trait TFieldType { - type ValType; - const MUTABLE: bool; -} - -impl TRecGroupType for T -where - T: TFieldType, - I: TypeRegisteringInfo, - T::ValType: TRecGroupType, -{ - fn rec_group_ty(types: &I) -> HQResult { - Ok(FieldType { - element_type: StorageType::Val(T::ValType::rec_group_ty(types)?), - mutable: T::MUTABLE, - }) - } -} - -impl HasTypeDependencies for T -where - T: TFieldType, - T::ValType: HasTypeDependencies, -{ - type Dependencies = >::Dependencies; - type RecGroupDependencies = >::RecGroupDependencies; -} - -pub struct TMutField(PhantomData); -pub struct TConstField(PhantomData); - -impl TFieldType for TMutField { - type ValType = T; - const MUTABLE: bool = true; -} - -impl TFieldType for TConstField { - type ValType = T; - const MUTABLE: bool = false; -} - -pub trait TDefaultable {} - -impl TRecGroupType, I> for () { - fn rec_group_ty(_types: &I) -> HQResult> { - Ok(vec![]) - } -} - -impl TRecGroupType, I> for (Head, Tail) -where - I: TypeRegisteringInfo, - Head: TRecGroupType, - Tail: TRecGroupType, I>, -{ - fn rec_group_ty(types: &I) -> HQResult> { - let mut tys = vec![Head::rec_group_ty(types)?]; - tys.extend(Tail::rec_group_ty(types)?); - Ok(tys) - } -} - -pub struct TStruct(PhantomData); - -impl TRecGroupType for TStruct -where - I: TypeRegisteringInfo, - Fields: TRecGroupType, I>, -{ - fn rec_group_ty(types: &I) -> HQResult { - types.types().struct_(Fields::rec_group_ty(types)?) - } -} - -struct TTypeListMarker(PhantomData); - -impl HasTypeDependencies> for () { - type Dependencies = (); - type RecGroupDependencies = (); -} - -impl HasTypeDependencies> for (Head, Tail) -where - Head: HasTypeDependencies, - Head::Dependencies: TypeList, - Head::RecGroupDependencies: TypeList, - Tail: HasTypeDependencies>, - Tail::Dependencies: TypeList, - Tail::RecGroupDependencies: TypeList, -{ - type Dependencies = <>::Dependencies as TypeList>::Concat< - >>::Dependencies, - >; - type RecGroupDependencies = - <>::RecGroupDependencies as TypeList>::Concat< - >>::RecGroupDependencies, - >; -} - -trait CompoundTypeDependencies { - type Dependencies: TypeList; - type RecGroupDependencies: TypeList; -} - -impl CompoundTypeDependencies for TStruct -where - Fields: TRecGroupType, TypeRegistry> - + HasTypeDependencies>, - Fields::Dependencies: TypeList, -{ - type Dependencies = <((HeapType, Self),) as TypeList>::Concat; - - type RecGroupDependencies = (); -} - -impl CompoundTypeDependencies for TStruct -where - Fields: TRecGroupType, RecGroupInfo> - + HasTypeDependencies>, - Fields::RecGroupDependencies: TypeList, -{ - type Dependencies = Fields::Dependencies; - - type RecGroupDependencies = - <((HeapType, Self),) as TypeList>::Concat; -} - -impl HasTypeDependencies for TStruct -where - Fields: TRecGroupType, RecGroupInfo> - + HasTypeDependencies>, - Self: CompoundTypeDependencies< - Fields, - >>::RecGroupDependencies, - >, -{ - type Dependencies = - >::Dependencies; - - type RecGroupDependencies = >::RecGroupDependencies; -} - -pub struct TArray(PhantomData); - -impl TRecGroupType for TArray -where - I: TypeRegisteringInfo, - Field: TFieldType, - Field::ValType: TRecGroupType, -{ - fn rec_group_ty(types: &I) -> HQResult { - types.types().array( - StorageType::Val(Field::ValType::rec_group_ty(types)?), - Field::MUTABLE, - ) - } -} - -impl CompoundTypeDependencies for TArray -where - Field: TFieldType //TRecGroupType - + HasTypeDependencies, - Field::ValType: TType, -{ - type Dependencies = <((HeapType, Self),) as TypeList>::Concat; - - type RecGroupDependencies = (); -} - -impl CompoundTypeDependencies for TArray -where - (Head, Tail): TypeList, - Field: TFieldType + HasTypeDependencies, -{ - type Dependencies = Field::Dependencies; - - type RecGroupDependencies = - <((HeapType, Self),) as TypeList>::Concat; -} - -impl HasTypeDependencies for TArray -where - Field: TFieldType + HasTypeDependencies, - Self: CompoundTypeDependencies< - Field, - >::RecGroupDependencies, - >, -{ - type Dependencies = - >::Dependencies; - - type RecGroupDependencies = >::RecGroupDependencies; -} - -pub struct TFunc(PhantomData, PhantomData); - -impl TRecGroupType for TFunc -where - I: TypeRegisteringInfo, - Params: TRecGroupType, I>, - Result: TRecGroupType, I>, -{ - fn rec_group_ty(types: &I) -> HQResult { - types - .types() - .function(Params::rec_group_ty(types)?, Result::rec_group_ty(types)?) - } -} - -impl CompoundTypeDependencies<(Params, Results), ()> for TFunc -where - Params: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, - Results: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, -{ - type Dependencies = - <<((HeapType, Self),) as TypeList>::Concat as TypeList>::Concat< - Results::Dependencies, - >; - - type RecGroupDependencies = (); -} - -impl CompoundTypeDependencies<(Params, Results), (Head, Tail)> - for TFunc -where - Params: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, - Results: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, -{ - type Dependencies = ::Concat; - - type RecGroupDependencies = <<((HeapType, Self),) as TypeList>::Concat< - Params::RecGroupDependencies, - > as TypeList>::Concat; -} - -impl HasTypeDependencies for TFunc -where - Params: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, - Results: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, - Self: CompoundTypeDependencies< - (Params, Results), - <>>::RecGroupDependencies as TypeList>::Concat<>>::RecGroupDependencies>, - >, -{ - type Dependencies = - >>::RecGroupDependencies as TypeList>::Concat<>>::RecGroupDependencies>, - >>::Dependencies; - type RecGroupDependencies = - >>::RecGroupDependencies as TypeList>::Concat<>>::RecGroupDependencies>, - >>::RecGroupDependencies; -} - -macro_rules! rec_group { - ( - $rec_group_name:ident { - $($name:ident = $typename:ident{$($typeparams:tt)+};)+ - } - ) => { - macro_rules! ${ concat($rec_group_name, _sub_rec_group_types) } { - ( - ${concat($rec_group_name, _sub_rec_group_types)}!($$($$macro_args:tt)+) - ) => { - ${concat($rec_group_name, _sub_rec_group_types)}!($$($$macro_args)+) - }; - ( - $$ty:ident{$$({$$($$params:tt)+}),+} - ) => { - $$ty< - $$( - ${concat($rec_group_name, _sub_rec_group_types)}!( - $$($$params)+ - ) - ),+ - > - }; - $( - ($name) => { - TRecGroupItem<${ index() }> - }; - )+ - ($$ty:ident) => { - $$ty - }; - (()) => {()}; - ( - ({$$($$first:tt)+},) - ) => { - ( - ${concat($rec_group_name, _sub_rec_group_types)}!( - $$($$first)+ - ), - () - ) - }; - ( - ({$$($$first:tt)+}, $$({$$($$rest:tt)+}),+ $$(,)?) - ) => { - ( - ${concat($rec_group_name, _sub_rec_group_types)}!( - $$($$first)+ - ), - ${concat($rec_group_name, _sub_rec_group_types)}!( - ($$({$$($$rest)+},)+) - ) - ) - }; - } - - fn ${ concat($rec_group_name, _register_deps) }(types: &TypeRegistry) -> HQResult<()> { - $( - <${concat($name, Type)} as HasTypeDependencies>::Dependencies::register_each(types)?; - )+ - Ok(()) - } - - $( - type ${concat($name, Type)} = ${ concat($rec_group_name, _sub_rec_group_types) }!( - $typename{$($typeparams)+} - ); - - pub struct $name; - - impl CompTimeRegistrand for $name { - fn register(types: &TypeRegistry) -> HQResult { - ${ concat($rec_group_name, _register_deps) }(types)?; - hq_todo!() - // let rec_group_info = RecGroupInfo { - // types, - // rec_group_start: types.registry().len() as u32, - // }; - // $( - // $name::rec_group_ty(&rec_group_info)?; - // ) - - } - } - )+ - } -} - -pub struct TRecGroupItem; - -impl HasTypeDependencies for TRecGroupItem { - type Dependencies = (); - type RecGroupDependencies = ((HeapType, Self), ()); -} - -impl<'a, const I: u32> TRecGroupType for TRecGroupItem { - fn rec_group_ty(registering_info: &RecGroupInfo) -> HQResult { - Ok(HeapType::Concrete(registering_info.rec_group_start + I)) - } -} +pub use rec_group::*; +pub use registration::*; +pub use registry::{CompoundType, RecGroup, RegistryItem, TypeRegistry}; +pub use tyfp::*; +pub use subtypes::*; rec_group! { rec_grp { @@ -680,7 +29,6 @@ rec_group! { {TMutField{{TNonNullable{{TStepFunc}}}}}, {TConstField{{TNullable{{TStructRef}}}}}, )}}; - TStackDynArrayField = TArray{{TMutField{{TNullable{{TStackStruct}}}}}}; TStackArray = TDynArray{{TNullable{{TStackStruct}}}}; } } diff --git a/src/wasm/registries/types/dependencies.rs b/src/wasm/registries/types/dependencies.rs new file mode 100644 index 00000000..fd52f639 --- /dev/null +++ b/src/wasm/registries/types/dependencies.rs @@ -0,0 +1,218 @@ +use core::marker::PhantomData; + +use wasm_encoder::{FieldType, HeapType, RefType, ValType}; + +use super::TypeRegistry; +use super::rec_group::RecGroupInfo; +use super::registration::{ + TArray, TFieldType, TFunc, TI32, TRecGroupType, TRefType, TStruct, TStructRef, TType, +}; +use super::tyfp::List; +use crate::prelude::*; + +pub trait HasTypeDependencies { + type Dependencies: List; + type RecGroupDependencies: List; +} + +impl HasTypeDependencies for TStructRef { + type Dependencies = (); + type RecGroupDependencies = (); +} + +impl HasTypeDependencies for T +where + T: TRefType, + T::HeapType: HasTypeDependencies, +{ + type Dependencies = >::Dependencies; + type RecGroupDependencies = + >::RecGroupDependencies; +} + +impl HasTypeDependencies for T +where + T: TRefType, + T::HeapType: HasTypeDependencies, +{ + type Dependencies = >::Dependencies; + type RecGroupDependencies = + >::RecGroupDependencies; +} + +impl HasTypeDependencies for TI32 { + type Dependencies = (); + type RecGroupDependencies = (); +} + +impl HasTypeDependencies for T +where + T: TFieldType, + T::ValType: HasTypeDependencies, +{ + type Dependencies = >::Dependencies; + type RecGroupDependencies = >::RecGroupDependencies; +} + +pub struct TTypeListMarker(PhantomData); + +impl HasTypeDependencies> for () { + type Dependencies = (); + type RecGroupDependencies = (); +} + +impl HasTypeDependencies> for (Head, Tail) +where + Head: HasTypeDependencies, + Head::Dependencies: List, + Head::RecGroupDependencies: List, + Tail: HasTypeDependencies>, + Tail::Dependencies: List, + Tail::RecGroupDependencies: List, +{ + type Dependencies = <>::Dependencies as List>::Concat< + >>::Dependencies, + >; + type RecGroupDependencies = + <>::RecGroupDependencies as List>::Concat< + >>::RecGroupDependencies, + >; +} + +pub trait CompoundTypeDependencies { + type Dependencies: List; + type RecGroupDependencies: List; +} + +impl CompoundTypeDependencies for TStruct +where + Fields: TRecGroupType, Rc> + + HasTypeDependencies>, + Fields::Dependencies: List, +{ + type Dependencies = <((HeapType, Self), ()) as List>::Concat; + + type RecGroupDependencies = (); +} + +impl CompoundTypeDependencies for TStruct +where + Fields: TRecGroupType, RecGroupInfo> + + HasTypeDependencies>, + Fields::RecGroupDependencies: List, +{ + type Dependencies = Fields::Dependencies; + + type RecGroupDependencies = + <((HeapType, Self), ()) as List>::Concat; +} + +impl HasTypeDependencies for TStruct +where + Fields: TRecGroupType, RecGroupInfo> + + HasTypeDependencies>, + Self: CompoundTypeDependencies< + Fields, + >>::RecGroupDependencies, + >, +{ + type Dependencies = + >::Dependencies; + + type RecGroupDependencies = >::RecGroupDependencies; +} + +impl CompoundTypeDependencies for TArray +where + Field: TFieldType //TRecGroupType + + HasTypeDependencies, + Field::ValType: TType, +{ + type Dependencies = <((HeapType, Self), ()) as List>::Concat; + + type RecGroupDependencies = (); +} + +impl CompoundTypeDependencies for TArray +where + (Head, Tail): List, + Field: TFieldType + HasTypeDependencies, +{ + type Dependencies = Field::Dependencies; + + type RecGroupDependencies = + <((HeapType, Self), ()) as List>::Concat; +} + +impl HasTypeDependencies for TArray +where + Field: TFieldType + HasTypeDependencies, + Self: CompoundTypeDependencies< + Field, + >::RecGroupDependencies, + >, +{ + type Dependencies = + >::Dependencies; + + type RecGroupDependencies = >::RecGroupDependencies; +} + +impl CompoundTypeDependencies<(Params, Results), ()> for TFunc +where + Params: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Results: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, +{ + type Dependencies = + <<((HeapType, Self), ()) as List>::Concat as List>::Concat< + Results::Dependencies, + >; + + type RecGroupDependencies = (); +} + +impl CompoundTypeDependencies<(Params, Results), (Head, Tail)> + for TFunc +where + Params: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Results: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, +{ + type Dependencies = ::Concat; + + type RecGroupDependencies = <<((HeapType, Self), ()) as List>::Concat< + Params::RecGroupDependencies, + > as List>::Concat; +} + +impl HasTypeDependencies for TFunc +where + Params: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Results: + TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Self: CompoundTypeDependencies< + (Params, Results), + <>>::RecGroupDependencies as List>::Concat<>>::RecGroupDependencies>, + >, +{ + type Dependencies = + >>::RecGroupDependencies as List>::Concat<>>::RecGroupDependencies>, + >>::Dependencies; + type RecGroupDependencies = + >>::RecGroupDependencies as List>::Concat<>>::RecGroupDependencies>, + >>::RecGroupDependencies; +} diff --git a/src/wasm/registries/types/rec_group.rs b/src/wasm/registries/types/rec_group.rs new file mode 100644 index 00000000..564d1144 --- /dev/null +++ b/src/wasm/registries/types/rec_group.rs @@ -0,0 +1,172 @@ +use core::marker::PhantomData; + +use wasm_encoder::HeapType; + +use super::dependencies::HasTypeDependencies; +use super::registration::TRecGroupType; +use super::tyfp::{Func, Bool}; +use super::{TypeRegisteringInfo, TypeRegistry}; +use crate::prelude::*; +use crate::wasm::registries::types::CompoundType; + +#[derive(Clone)] +pub struct RecGroupInfo { + pub types: Rc, + pub rec_group_start: u32, +} + +impl TypeRegisteringInfo for RecGroupInfo { + fn types(&self) -> &TypeRegistry { + &self.types + } +} + +#[macro_export] +macro_rules! rec_group { + ( + $rec_group_name:ident { + $($name:ident = $typename:ident{$($typeparams:tt)+};)+ + } + ) => { + macro_rules! ${ concat($rec_group_name, _sub_rec_group_types) } { + ( + ${concat($rec_group_name, _sub_rec_group_types)}!($$($$macro_args:tt)+) + ) => { + ${concat($rec_group_name, _sub_rec_group_types)}!($$($$macro_args)+) + }; + ( + $$ty:ident{$$({$$($$params:tt)+}),+} + ) => { + $$ty< + $$( + ${concat($rec_group_name, _sub_rec_group_types)}!( + $$($$params)+ + ) + ),+ + > + }; + $( + ($name) => { + TRecGroupItem<${ index() }> + }; + )+ + ($$ty:ident) => { + $$ty + }; + (()) => {()}; + ( + ({$$($$first:tt)+},) + ) => { + ( + ${concat($rec_group_name, _sub_rec_group_types)}!( + $$($$first)+ + ), + () + ) + }; + ( + ({$$($$first:tt)+}, $$({$$($$rest:tt)+}),+ $$(,)?) + ) => { + ( + ${concat($rec_group_name, _sub_rec_group_types)}!( + $$($$first)+ + ), + ${concat($rec_group_name, _sub_rec_group_types)}!( + ($$({$$($$rest)+},)+) + ) + ) + }; + } + + fn ${concat($rec_group_name, _construct_rec_group)}() -> Rc { + Rc::new(RecGroup { + types: vec![ + $( + ( + core::any::type_name::<$name>(), + RefCell::new(CompoundType::Struct(vec![])), + ) + ),+ + ] + }) + } + + fn ${ concat($rec_group_name, _register_rec_group) }(types: &Rc) -> HQResult<()> { + use $crate::wasm::registries::types::dependencies::*; + let rec_group_types = ${concat($rec_group_name, _construct_rec_group)}(); + if types.registry().borrow().contains_key(&RegistryItem::RecGroupItem(Rc::clone(&rec_group_types), 0)) { + return Ok(()); + } + $( + <$name as HasTypeDependencies>::Dependencies::register_each(types)?; + )+ + for i in 0u32..(rec_group_types.types.len() as u32) { + types.register_default::(RegistryItem::RecGroupItem(Rc::clone(&rec_group_types), i))?; + } + let start_index = types.register_default::(RegistryItem::RecGroupItem(Rc::clone(&rec_group_types), 0))?; + let rec_group_info = RecGroupInfo { + types: Rc::clone(types), + rec_group_start: start_index, + }; + $( + *rec_group_types.types[${index()}].1.borrow_mut() = + $name::rec_group_ty( + &rec_group_info + )?; + )+ + Ok(()) + } + + $( + pub type $name = ${ concat($rec_group_name, _sub_rec_group_types) }!( + $typename{$($typeparams)+} + ); + + // type ${concat($name, CompoundTypeRecGroupDependencies)} = < + // << + // $name as $crate::wasm::registries::types::dependencies::HasTypeDependencies + // >::RecGroupDependencies as List>::Tail + // as $crate::wasm::registries::types::tyfp::Filter<$crate::wasm::registries::types::rec_group::HasCompoundTypeRegistration> + // >::Filtered; + + impl TRecGroupType> for $name { + fn rec_group_ty(types: &Rc) -> HQResult { + ${ concat($rec_group_name, _register_rec_group) }(types)?; + let rec_group_types = ${concat($rec_group_name, _construct_rec_group)}(); + types.register_default(RegistryItem::RecGroupItem(rec_group_types, ${index()})) + } + } + )+ + } +} + +pub struct TRecGroupItem; + +impl HasTypeDependencies for TRecGroupItem { + type Dependencies = (); + type RecGroupDependencies = ((HeapType, Self), ()); +} + +impl TRecGroupType for TRecGroupItem { + fn rec_group_ty(registering_info: &RecGroupInfo) -> HQResult { + Ok(HeapType::Concrete(registering_info.rec_group_start + I)) + } +} + +pub struct HasCompoundTypeRegistration; +impl Func for HasCompoundTypeRegistration { + type Func = CompoundTypeRegistrationTester; +} + +pub struct CompoundTypeRegistrationTester(PhantomData); + +impl Bool for CompoundTypeRegistrationTester { + default const BOOL: bool = false; +} + +impl Bool for CompoundTypeRegistrationTester<(HeadT, Head)> +where + Head: TRecGroupType, +{ + const BOOL: bool = true; +} diff --git a/src/wasm/registries/types/registration.rs b/src/wasm/registries/types/registration.rs new file mode 100644 index 00000000..f75cc97d --- /dev/null +++ b/src/wasm/registries/types/registration.rs @@ -0,0 +1,261 @@ +use core::marker::PhantomData; + +use wasm_encoder::{AbstractHeapType, FieldType, HeapType, RefType, StorageType, ValType}; + +use super::tyfp::List; +use super::{CompoundType, RegistryItem, TypeRegistry}; +use crate::prelude::*; +use crate::registry::CompTimeRegistrand; + +pub trait TypeRegisteringInfo { + fn types(&self) -> &TypeRegistry; +} + +impl TypeRegisteringInfo for Rc { + fn types(&self) -> &TypeRegistry { + self + } +} + +pub trait TRecGroupType { + fn rec_group_ty(registering_info: &I) -> HQResult; +} + +impl TRecGroupType for T +where + T: TRecGroupType, + I: TypeRegisteringInfo, +{ + default fn rec_group_ty(types: &I) -> HQResult { + types + .types() + .register_default(RegistryItem::Type(T::rec_group_ty(types)?)) + } +} + +impl TRecGroupType for T +where + T: TRecGroupType, + I: TypeRegisteringInfo, +{ + default fn rec_group_ty(types: &I) -> HQResult { + Ok(HeapType::Concrete(T::rec_group_ty(types)?)) + } +} + +pub trait TType: TRecGroupType> { + fn ty(types: &Rc) -> HQResult; +} + +impl TType for U +where + U: TRecGroupType>, +{ + fn ty(types: &Rc) -> HQResult { + U::rec_group_ty(types) + } +} + +impl CompTimeRegistrand for T +where + T: TType, +{ + type Receiver = Rc; + + fn register(types: &Rc) -> HQResult { + T::ty(types) + } +} + +pub trait TDefaultable {} + +pub trait RegTypeList: List { + fn register_each(types: &I) -> HQResult<()>; +} + +impl RegTypeList for () { + fn register_each(_types: &I) -> HQResult<()> { + Ok(()) + } +} + +impl RegTypeList for ((HeadT, Head), Tail) +where + I: TypeRegisteringInfo, + Head: TRecGroupType, + Tail: RegTypeList, +{ + fn register_each(types: &I) -> HQResult<()> { + Head::rec_group_ty(types)?; + Tail::register_each(types) + } +} + +pub struct TStructRef; +impl TRecGroupType for TStructRef { + fn rec_group_ty(_types: &I) -> HQResult { + panic!("this shouldn't be called ever!!! evil!!!") + } +} +impl TRecGroupType for TStructRef { + fn rec_group_ty(_types: &I) -> HQResult { + panic!("this shouldn't be called ever!!! evil!!!") + } +} +impl TRecGroupType for TStructRef { + fn rec_group_ty(_types: &I) -> HQResult { + Ok(HeapType::Abstract { + shared: false, + ty: AbstractHeapType::Struct, + }) + } +} + +pub trait TRefType { + type HeapType; + const NULLABLE: bool; +} + +impl TRecGroupType for T +where + T: TRefType, + T::HeapType: TRecGroupType, + I: TypeRegisteringInfo, +{ + fn rec_group_ty(types: &I) -> HQResult { + Ok(RefType { + nullable: T::NULLABLE, + heap_type: T::HeapType::rec_group_ty(types)?, + }) + } +} + +pub struct TNullable(PhantomData); +impl TRefType for TNullable { + type HeapType = T; + const NULLABLE: bool = true; +} +impl TDefaultable for TNullable {} + +pub struct TNonNullable(PhantomData); +impl TRefType for TNonNullable { + type HeapType = T; + const NULLABLE: bool = false; +} + +impl TRecGroupType for T +where + T: TRefType, + T::HeapType: TRecGroupType, + I: TypeRegisteringInfo, +{ + fn rec_group_ty(types: &I) -> HQResult { + Ok(ValType::Ref( + >::rec_group_ty(types)?, + )) + } +} + +pub struct TI32; + +impl TRecGroupType for TI32 { + fn rec_group_ty(_types: &I) -> HQResult { + Ok(ValType::I32) + } +} +impl TDefaultable for TI32 {} + +pub trait TFieldType { + type ValType; + const MUTABLE: bool; +} + +impl TRecGroupType for T +where + T: TFieldType, + I: TypeRegisteringInfo, + T::ValType: TRecGroupType, +{ + fn rec_group_ty(types: &I) -> HQResult { + Ok(FieldType { + element_type: StorageType::Val(T::ValType::rec_group_ty(types)?), + mutable: T::MUTABLE, + }) + } +} + +pub struct TMutField(PhantomData); +pub struct TConstField(PhantomData); + +impl TFieldType for TMutField { + type ValType = T; + const MUTABLE: bool = true; +} + +impl TFieldType for TConstField { + type ValType = T; + const MUTABLE: bool = false; +} + +impl TRecGroupType, I> for () { + fn rec_group_ty(_types: &I) -> HQResult> { + Ok(vec![]) + } +} + +impl TRecGroupType, I> for (Head, Tail) +where + I: TypeRegisteringInfo, + Head: TRecGroupType, + Tail: TRecGroupType, I>, +{ + fn rec_group_ty(types: &I) -> HQResult> { + let mut tys = vec![Head::rec_group_ty(types)?]; + tys.extend(Tail::rec_group_ty(types)?); + Ok(tys) + } +} + +pub struct TStruct(PhantomData); + +impl TRecGroupType for TStruct +where + I: TypeRegisteringInfo, + Fields: TRecGroupType, I>, +{ + fn rec_group_ty(types: &I) -> HQResult { + Ok(CompoundType::Struct(Fields::rec_group_ty(types)?)) + } +} + +pub struct TArray(PhantomData); + +impl TRecGroupType for TArray +where + I: TypeRegisteringInfo, + Field: TFieldType, + Field::ValType: TRecGroupType, +{ + fn rec_group_ty(types: &I) -> HQResult { + Ok(CompoundType::Array( + StorageType::Val(Field::ValType::rec_group_ty(types)?), + Field::MUTABLE, + )) + } +} + +pub struct TFunc(PhantomData, PhantomData); + +impl TRecGroupType for TFunc +where + I: TypeRegisteringInfo, + Params: TRecGroupType, I>, + Result: TRecGroupType, I>, +{ + fn rec_group_ty(types: &I) -> HQResult { + Ok(CompoundType::Function( + Params::rec_group_ty(types)?, + Result::rec_group_ty(types)?, + )) + } +} \ No newline at end of file diff --git a/src/wasm/registries/types/registry.rs b/src/wasm/registries/types/registry.rs new file mode 100644 index 00000000..0ff3662e --- /dev/null +++ b/src/wasm/registries/types/registry.rs @@ -0,0 +1,118 @@ +use wasm_encoder::{ + AbstractHeapType, FieldType, HeapType, RefType, StorageType, TypeSection, ValType, +}; + +use crate::ir::RcVar; +use crate::prelude::*; +use crate::registry::{RegistryResult, SetRegistry}; +use crate::wasm::WasmProject; + +#[derive(Clone, Debug, Eq)] +pub struct RecGroup { + pub types: Vec<(&'static str, RefCell)>, +} + +impl PartialEq for RecGroup { + fn eq(&self, other: &Self) -> bool { + self.types.len() == other.types.len() + && self + .types + .iter() + .zip(&other.types) + .all(|((fst, _), (snd, _))| fst == snd) + } +} + +impl core::hash::Hash for RecGroup { + fn hash(&self, state: &mut H) { + self.types + .iter() + .map(|(tystr, _)| tystr) + .collect::>() + .hash(state); + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum CompoundType { + Function(Vec, Vec), + Array(StorageType, bool), + Struct(Vec), +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum RegistryItem { + Type(CompoundType), + RecGroupItem(Rc, u32), +} + +pub type TypeRegistry = SetRegistry; + +impl TypeRegistry { + pub fn function(&self, params: Vec, returns: Vec) -> HQResult + where + N: RegistryResult, + { + self.register_default(RegistryItem::Type(CompoundType::Function(params, returns))) + } + + pub fn array(&self, elem_type: StorageType, mutable: bool) -> HQResult + where + N: RegistryResult, + { + self.register_default(RegistryItem::Type(CompoundType::Array(elem_type, mutable))) + } + + pub fn struct_(&self, fields: Vec) -> HQResult + where + N: RegistryResult, + { + self.register_default(RegistryItem::Type(CompoundType::Struct(fields))) + } + + pub const STRUCT_REF: ValType = ValType::Ref(RefType { + nullable: true, + heap_type: HeapType::Abstract { + shared: false, + ty: AbstractHeapType::Struct, + }, + }); + + pub fn proc_arg_struct_type( + &self, + arg_vars: &core::cell::Ref<'_, Vec>, + ) -> HQResult { + self.struct_( + arg_vars + .iter() + .map(|var| { + Ok(FieldType { + mutable: false, + element_type: StorageType::Val(WasmProject::ir_type_to_wasm( + *var.possible_types(), + )), + }) + }) + .collect::>>()?, + ) + } + + fn finish_type(ty: CompoundType, types: &mut TypeSection) { + match ty { + CompoundType::Function(params, results) => types.ty().function(params, results), + CompoundType::Array(elem_type, mutable) => types.ty().array(&elem_type, mutable), + CompoundType::Struct(fields) => types.ty().struct_(fields), + } + } + + pub fn finish(self, types: &mut TypeSection) { + for ty in self.registry().take().keys().cloned() { + match ty { + RegistryItem::Type(ty) => Self::finish_type(ty, types), + RegistryItem::RecGroupItem(rec_group, index) => { + Self::finish_type(rec_group.types[index as usize].1.borrow().clone(), types); + } + } + } + } +} \ No newline at end of file diff --git a/src/wasm/registries/types/subtypes.rs b/src/wasm/registries/types/subtypes.rs new file mode 100644 index 00000000..c4361958 --- /dev/null +++ b/src/wasm/registries/types/subtypes.rs @@ -0,0 +1,73 @@ +use core::marker::PhantomData; + +use crate::wasm::registries::types::{Bool, Func, List, Map, TFieldType, TFunc, TStruct}; + +pub trait FuncSubTypes { + type Params: List; + type Results: List; +} + +pub struct IsFieldType; +impl Func for IsFieldType { + type Func = FieldTypeTester; +} + +pub struct FieldTypeTester(PhantomData); + +impl Bool for FieldTypeTester { + default const BOOL: bool = false; +} + +impl Bool for FieldTypeTester<(HeadT, Head)> +where + Head: TFieldType, +{ + const BOOL: bool = true; +} + +pub struct ExtractValFromField; + +pub struct FieldValExtractor(PhantomData); + +pub trait HasValType { + type ValType; +} + +impl HasValType for FieldValExtractor { + default type ValType = !; +} + +impl HasValType for FieldValExtractor +where + T: TFieldType, +{ + type ValType = T::ValType; +} + +impl Func for ExtractValFromField { + type Func = as HasValType>::ValType; +} + +impl FuncSubTypes for TFunc +where + Params: List, + Results: List, +{ + type Params = Params; + type Results = Results; +} + +pub trait StructSubTypes { + type Fields: List; +} + +impl StructSubTypes for TStruct +where + Fields: List + Map, +{ + type Fields = Fields::Mapped; +} + +pub trait ArraySubType { + type Field; +} diff --git a/src/wasm/registries/types/tyfp.rs b/src/wasm/registries/types/tyfp.rs new file mode 100644 index 00000000..61834145 --- /dev/null +++ b/src/wasm/registries/types/tyfp.rs @@ -0,0 +1,157 @@ +//! Functional programming in the type system. Or something like that. + +pub trait List { + type Head; + type Tail: List; + + type Concat: List; +} + +impl List for () { + type Head = !; + type Tail = (); + + type Concat = Other; +} + +impl List for (Head, Tail) +where + Tail: List, +{ + type Head = Head; + type Tail = Tail; + + type Concat = (Head, Tail::Concat); +} + +pub trait ListLen { + const LEN: usize; +} + +impl ListLen for () { + const LEN: usize = 0; +} + +impl ListLen for (Head, Tail) +where + Tail: ListLen, +{ + const LEN: usize = Tail::LEN + 1; +} + +pub trait Reverse: List { + type Reversed: List; +} + +impl Reverse for () { + type Reversed = (); +} + +impl Reverse for (Head, Tail) +where + Tail: Reverse, +{ + type Reversed = ::Concat<(Head, ())>; +} + +pub trait Bool { + const BOOL: bool; +} + +pub trait Func { + type Func; +} + +pub trait Filter: List { + type Filtered: List; +} + +impl Filter for () { + type Filtered = (); +} + +pub trait FilterResult { + type FilterResult: List; +} + +impl FilterResult for (Head, Tail) +where + Tail: Filter, + Cond: Func, +{ + type FilterResult = (Head, Tail::Filtered); +} + +impl FilterResult for (Head, Tail) +where + Tail: Filter, + Cond: Func, +{ + type FilterResult = Tail::Filtered; +} + +impl Filter for (Head, Tail) +where + Tail: Filter, + Cond: Func, + Cond::Func: Bool, + (Head, Tail): FilterResult as Bool>::BOOL }>, +{ + type Filtered = + <(Head, Tail) as FilterResult as Bool>::BOOL }>>::FilterResult; +} + +pub trait All: List { + const ALL: bool; +} + +impl All for () { + const ALL: bool = true; +} + +impl All for (Head, Tail) +where + Cond: Func, + Cond::Func: Bool, + Tail: All, +{ + const ALL: bool = as Bool>::BOOL && >::ALL; +} + +pub trait Map: List { + type Mapped: List; +} + +impl Map for () { + type Mapped = (); +} + +impl> Map for (Head, Tail) { + type Mapped = (F::Func, Tail::Mapped); +} + +pub trait ListItem { + type Get; +} + +impl ListItem for () { + type Get = !; +} + +impl ListItem<0> for (Head, Tail) { + type Get = Head; +} + +pub struct ConstSat; + +pub trait True {} + +impl True for ConstSat {} + +impl ListItem for (Head, Tail) +where + ConstSat<{ I > 0 }>: True, + Tail: ListItem<{ I - 1 }>, +{ + type Get = Tail::Get; +} \ No newline at end of file From a5dac89623d696e7118a18ff4467451681bc02cb Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Fri, 11 Sep 2026 14:41:02 +0100 Subject: [PATCH 11/18] static functions declare their own overrides; encode rec groups in actual rec groups --- src/instructions/procedures/argument.rs | 2 +- src/ir/types.rs | 1 - src/lib.rs | 1 - src/wasm/project.rs | 54 ++--- src/wasm/registries/functions.rs | 31 ++- src/wasm/registries/functions/dyn_array.rs | 189 ++++++------------ .../registries/functions/mark_waiting_flag.rs | 24 +-- src/wasm/registries/functions/pen_colour.rs | 14 +- .../registries/functions/spawn_threads.rs | 145 +++++++------- src/wasm/registries/types.rs | 4 +- src/wasm/registries/types/rec_group.rs | 2 +- src/wasm/registries/types/registration.rs | 4 +- src/wasm/registries/types/registry.rs | 52 ++++- src/wasm/registries/types/tyfp.rs | 2 +- 14 files changed, 245 insertions(+), 280 deletions(-) diff --git a/src/instructions/procedures/argument.rs b/src/instructions/procedures/argument.rs index da6942ba..f794ba5e 100644 --- a/src/instructions/procedures/argument.rs +++ b/src/instructions/procedures/argument.rs @@ -73,7 +73,7 @@ pub fn wasm( let registries = func.registries(); let type_registry = registries.types().registry().borrow(); let RegistryItem::Type(CompoundType::Struct(struct_type_fields)) = // TODO: do we need to consider the possibility of rec group items? - type_registry + type_registry .get_index(struct_type_index as usize) .ok_or_else(|| make_hq_bug!("type index not found in type registry"))? .0 diff --git a/src/ir/types.rs b/src/ir/types.rs index b8cb5230..38027307 100644 --- a/src/ir/types.rs +++ b/src/ir/types.rs @@ -105,7 +105,6 @@ impl Type { .find(|&ty| ty.contains(self)) } - #[must_use] pub fn base_types(self) -> Box> { if self.is_none() { return Box::new(core::iter::empty()); diff --git a/src/lib.rs b/src/lib.rs index d098641a..208d1a43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,6 @@ #![feature(specialization)] #![feature(const_type_name)] #![feature(generic_const_exprs)] - #![doc(html_logo_url = "https://hyperquark.edgecompute.app/logo.png")] #![doc(html_favicon_url = "https://hyperquark.edgecompute.app/favicon.ico")] #![warn(clippy::cargo, clippy::nursery, clippy::pedantic)] diff --git a/src/wasm/project.rs b/src/wasm/project.rs index 9aaf3925..9e5718b7 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -2,9 +2,9 @@ use itertools::Itertools; use wasm_bindgen::prelude::*; use wasm_encoder::{ AbstractHeapType, BlockType as WasmBlockType, CodeSection, ConstExpr, DataCountSection, - DataSection, ElementSection, Elements, ExportKind, ExportSection, FieldType, Function, - FunctionSection, GlobalSection, HeapType, ImportSection, Instruction, MemorySection, - MemoryType, Module, RefType, StartSection, StorageType, TableSection, TypeSection, ValType, + DataSection, ElementSection, Elements, ExportKind, ExportSection, Function, FunctionSection, + GlobalSection, HeapType, ImportSection, Instruction, MemorySection, MemoryType, Module, + RefType, StartSection, TableSection, TypeSection, ValType, }; use wasm_gen::wasm; @@ -12,8 +12,7 @@ use super::{ExternalEnvironment, Registries}; use crate::ir::{Event, IrProject, IrType, StepIndex}; use crate::prelude::*; use crate::wasm::registries::functions::static_functions::{ - DynArrayGet, DynArrayLen, MarkWaitingFlag, SpawnNewThread, SpawnThreadFuncOverride, - SpawnThreadInStack, + DynArrayGet, DynArrayLen, SpawnNewThread, SpawnThreadInStack, }; use crate::wasm::registries::types::{ TFunc, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, @@ -141,35 +140,8 @@ impl WasmProject { .clone() .finish(&mut imports, self.registries().types())?; - let spawn_thread_func_override = SpawnThreadFuncOverride { - types: Rc::clone(self.registries().types()), - static_functions: Rc::clone(self.registries().static_functions()), - globals: Rc::clone(self.registries().globals()), - num_sprites: self.costume_names().len() as u32, - imported_func_count: self.imported_func_count()?, - imported_global_count: self.imported_global_count()?, - }; - - self.registries() - .static_functions() - .try_register_override::( - spawn_thread_func_override.clone(), - )?; - - self.registries() - .static_functions() - .try_register_override::(spawn_thread_func_override)?; - - self.registries() - .static_functions() - .register_override::(self.registries().types().struct_( - vec![FieldType { - element_type: StorageType::I8, - mutable: true, - }], - )?)?; - Rc::unwrap_or_clone(self.registries().static_functions().clone()).finish( + &self, &mut functions, &mut exports, &mut codes, @@ -322,7 +294,7 @@ impl WasmProject { }) } - fn imported_func_count(&self) -> HQResult { + pub fn imported_func_count(&self) -> HQResult { self.registries() .external_functions() .registry() @@ -332,7 +304,7 @@ impl WasmProject { .map_err(|_| make_hq_bug!("external function map len out of bounds")) } - fn static_func_count(&self) -> HQResult { + pub fn static_func_count(&self) -> HQResult { self.registries() .static_functions() .registry() @@ -342,7 +314,7 @@ impl WasmProject { .map_err(|_| make_hq_bug!("static function map len out of bounds")) } - fn imported_global_count(&self) -> HQResult { + pub fn imported_global_count(&self) -> HQResult { self.registries() .strings() .registry() @@ -352,7 +324,7 @@ impl WasmProject { .map_err(|_| make_hq_bug!("string registry len out of bounds")) } - fn unreachable_dbg_func( + pub fn unreachable_dbg_func( &self, functions: &mut FunctionSection, codes: &mut CodeSection, @@ -372,7 +344,7 @@ impl WasmProject { Ok(()) } - fn spawn_new_thread_func(&self) -> HQResult + pub fn spawn_new_thread_func(&self) -> HQResult where N: TryFrom, >::Error: fmt::Debug, @@ -382,7 +354,7 @@ impl WasmProject { .register::() } - fn spawn_thread_in_stack_func(&self) -> HQResult + pub fn spawn_thread_in_stack_func(&self) -> HQResult where N: TryFrom, >::Error: fmt::Debug, @@ -392,7 +364,7 @@ impl WasmProject { .register::() } - fn threads_count_global(&self) -> HQResult + pub fn threads_count_global(&self) -> HQResult where N: TryFrom, >::Error: fmt::Debug, @@ -400,7 +372,7 @@ impl WasmProject { self.registries().globals().threads_count() } - fn threadss_global(&self) -> HQResult + pub fn threadss_global(&self) -> HQResult where N: TryFrom, >::Error: fmt::Debug, diff --git a/src/wasm/registries/functions.rs b/src/wasm/registries/functions.rs index 15940774..bc4750b6 100644 --- a/src/wasm/registries/functions.rs +++ b/src/wasm/registries/functions.rs @@ -10,6 +10,7 @@ use wasm_encoder::{ Instruction as WInstruction, ValType, }; +use super::super::WasmProject; use super::TypeRegistry; use crate::prelude::*; use crate::registry::{MapRegistry, Registry}; @@ -48,7 +49,11 @@ pub struct StaticFunction { #[derive(Clone)] pub struct MaybeStaticFunction { pub static_function: Option, - pub maybe_populate: fn() -> Option, + pub maybe_populate: fn( + &WasmProject, + &IndexMap, MaybeStaticFunction>, + ) -> HQResult>, + pub register_deps: fn(&StaticFunctionRegistry) -> HQResult<()>, } pub struct StaticFunctionRegistrar; @@ -60,19 +65,35 @@ pub type StaticFunctionRegistry = NamedRegistry; impl StaticFunctionRegistry { pub fn finish( self, + wasm_proj: &WasmProject, functions: &mut FunctionSection, exports: &mut ExportSection, codes: &mut CodeSection, type_registry: &TypeRegistry, imported_func_count: u32, ) -> HQResult<()> { + let mut num_funcs = self.registry().borrow().len(); + loop { + for (_name, MaybeStaticFunction { register_deps, .. }) in + self.registry().borrow().iter() + { + register_deps(&self)?; + } + let new_num_funcs = self.registry().borrow().len(); + if new_num_funcs == num_funcs { + break; + } + num_funcs = new_num_funcs; + } + let registry = self.registry().take(); for ( _name, MaybeStaticFunction { static_function, maybe_populate, + .. }, - ) in self.registry().take() + ) in ®istry { let Some(StaticFunction { instructions, @@ -80,7 +101,9 @@ impl StaticFunctionRegistry { returns, locals, export, - }) = static_function.map_or_else(maybe_populate, Some) + }) = static_function + .clone() + .map_or_else(|| maybe_populate(wasm_proj, ®istry), |sf| Ok(Some(sf)))? else { hq_bug!( "static functions must either be overriden, or have a non-None maybe_populate \ @@ -113,5 +136,5 @@ pub mod static_functions { }; pub use super::mark_waiting_flag::MarkWaitingFlag; pub use super::pen_colour::{UpdatePenColorFromHSV, UpdatePenColorFromRGB}; - pub use super::spawn_threads::{SpawnNewThread, SpawnThreadFuncOverride, SpawnThreadInStack}; + pub use super::spawn_threads::{SpawnNewThread, SpawnThreadInStack}; } diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs index fb65aa54..ef530377 100644 --- a/src/wasm/registries/functions/dyn_array.rs +++ b/src/wasm/registries/functions/dyn_array.rs @@ -21,25 +21,15 @@ pub struct DynArrayFuncOverride { /// ref `dynamic_array` - the dynamic array struct (obtained from `TDynArray` for `T: TDefaultable`) /// t - the element pub struct DynArrayPush(PhantomData); -impl + TDefaultable> NamedRegistryItem - for DynArrayPush -{ +impl + TDefaultable> NamedRegistryItem for DynArrayPush { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} - -impl + TDefaultable> - TryNamedRegistryItemOverride for DynArrayPush -{ - fn try_override( - DynArrayFuncOverride { types }: DynArrayFuncOverride, - ) -> HQResult { - let struct_type = types.register_comp::, u32>()?; - let array_type = types.register_comp::, u32>()?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |proj, _| { + let types = Rc::clone(proj.registries().types()); + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), @@ -100,10 +90,9 @@ impl + TDefaultable> params: Box::from([>>::ty(&types)?, T::ty(&types)?]), returns: Box::from([]), locals: Box::from([ValType::I32, >>::ty(&types)?]), - }), - maybe_populate: || None, - }) - } + })) + }, + }; } /// Gets an element of a dynamic (resizeable) array @@ -117,20 +106,12 @@ pub struct DynArrayGet(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayGet { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} - -impl + TDefaultable> - TryNamedRegistryItemOverride for DynArrayGet -{ - fn try_override( - DynArrayFuncOverride { types }: DynArrayFuncOverride, - ) -> HQResult { - let struct_type = types.register_comp::, u32>()?; - let array_type = types.register_comp::, u32>()?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |proj, _| { + let types = Rc::clone(proj.registries().types()); + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), @@ -144,10 +125,9 @@ impl + TDefaultable> params: Box::from([>>::ty(&types)?, ValType::I32]), returns: Box::from([T::ty(&types)?]), locals: Box::from([]), - }), - maybe_populate: || None, - }) - } + })) + }, + }; } /// Sets an element of a dynamic (resizeable) array @@ -160,20 +140,12 @@ pub struct DynArraySet(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArraySet { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} - -impl + TDefaultable> - TryNamedRegistryItemOverride for DynArraySet -{ - fn try_override( - DynArrayFuncOverride { types }: DynArrayFuncOverride, - ) -> HQResult { - let struct_type = types.register_comp::, u32>()?; - let array_type = types.register_comp::, u32>()?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |proj, _| { + let types = Rc::clone(proj.registries().types()); + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), @@ -192,10 +164,9 @@ impl + TDefaultable> ]), returns: Box::from([T::ty(&types)?]), locals: Box::from([]), - }), - maybe_populate: || None, - }) - } + })) + }, + }; } /// Pops the last element from a dynamic (resizeable) array @@ -208,20 +179,12 @@ pub struct DynArrayPop(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayPop { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} - -impl + TDefaultable> - TryNamedRegistryItemOverride for DynArrayPop -{ - fn try_override( - DynArrayFuncOverride { types }: DynArrayFuncOverride, - ) -> HQResult { - let struct_type = types.register_comp::, u32>()?; - let array_type = types.register_comp::, u32>()?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |proj, _| { + let types = Rc::clone(proj.registries().types()); + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), @@ -248,10 +211,9 @@ impl + TDefaultable> params: Box::from([>>::ty(&types)?]), returns: Box::from([T::ty(&types)?]), locals: Box::from([ValType::I32]), - }), - maybe_populate: || None, - }) - } + })) + }, + }; } /// Creates a new dynamic (resizeable) array of the given capacity @@ -264,20 +226,12 @@ pub struct DynArrayNew(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayNew { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} - -impl + TDefaultable> - TryNamedRegistryItemOverride for DynArrayNew -{ - fn try_override( - DynArrayFuncOverride { types }: DynArrayFuncOverride, - ) -> HQResult { - let struct_type = types.register_comp::, u32>()?; - let array_type = types.register_comp::, u32>()?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |proj, _| { + let types = Rc::clone(proj.registries().types()); + let struct_type = types.register_comp::, u32>()?; + let array_type = types.register_comp::, u32>()?; + Ok(Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), @@ -288,10 +242,9 @@ impl + TDefaultable> params: Box::from([ValType::I32]), returns: Box::from([>>::ty(&types)?]), locals: Box::from([]), - }), - maybe_populate: || None, - }) - } + })) + }, + }; } /// Returns the length (not capacity) of the given dynamic array @@ -304,19 +257,11 @@ pub struct DynArrayLen(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayLen { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} - -impl + TDefaultable> - TryNamedRegistryItemOverride for DynArrayLen -{ - fn try_override( - DynArrayFuncOverride { types }: DynArrayFuncOverride, - ) -> HQResult { - let struct_type = types.register_comp::, u32>()?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |proj, _| { + let types = Rc::clone(proj.registries().types()); + let struct_type = types.register_comp::, u32>()?; + Ok(Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), @@ -328,10 +273,9 @@ impl + TDefaultable> params: Box::from([>>::ty(&types)?]), returns: Box::from([ValType::I32]), locals: Box::from([]), - }), - maybe_populate: || None, - }) - } + })) + }, + }; } /// Clears the given dynamic array to length 0 (but doesn't actually drop any of the elements) @@ -342,19 +286,11 @@ pub struct DynArrayClear(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayClear { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} - -impl + TDefaultable> - TryNamedRegistryItemOverride for DynArrayClear -{ - fn try_override( - DynArrayFuncOverride { types }: DynArrayFuncOverride, - ) -> HQResult { - let struct_type = types.register_comp::, u32>()?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |proj, _| { + let types = Rc::clone(proj.registries().types()); + let struct_type = types.register_comp::, u32>()?; + Ok(Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), @@ -367,8 +303,7 @@ impl + TDefaultable> params: Box::from([>>::ty(&types)?]), returns: Box::from([ValType::I32]), locals: Box::from([]), - }), - maybe_populate: || None, - }) - } + })) + }, + }; } diff --git a/src/wasm/registries/functions/mark_waiting_flag.rs b/src/wasm/registries/functions/mark_waiting_flag.rs index f2e3751c..0220e6c5 100644 --- a/src/wasm/registries/functions/mark_waiting_flag.rs +++ b/src/wasm/registries/functions/mark_waiting_flag.rs @@ -1,4 +1,4 @@ -use wasm_encoder::{HeapType, RefType, ValType}; +use wasm_encoder::{FieldType, HeapType, RefType, StorageType, ValType}; use wasm_gen::wasm_const; use super::{MaybeStaticFunction, StaticFunction}; @@ -16,14 +16,13 @@ pub struct MarkWaitingFlag; impl NamedRegistryItem for MarkWaitingFlag { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} -pub type MarkWaitingFlagOverride = u32; -impl NamedRegistryItemOverride for MarkWaitingFlag { - fn r#override(i8_struct_ty: u32) -> MaybeStaticFunction { - MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |proj, _| { + let i8_struct_ty = proj.registries().types().struct_(vec![FieldType { + element_type: StorageType::I8, + mutable: true, + }])?; + Ok(Some(StaticFunction { export: Some("mark_waiting_flag".into()), instructions: Box::from(wasm_const![ LocalGet(0), @@ -40,8 +39,7 @@ impl NamedRegistryItemOverride for })]), returns: Box::new([]), locals: Box::new([]), - }), - maybe_populate: || None, - } - } + })) + }, + }; } diff --git a/src/wasm/registries/functions/pen_colour.rs b/src/wasm/registries/functions/pen_colour.rs index 82e448df..e5a2443b 100644 --- a/src/wasm/registries/functions/pen_colour.rs +++ b/src/wasm/registries/functions/pen_colour.rs @@ -27,8 +27,9 @@ pub struct UpdatePenColorFromHSV; impl NamedRegistryItem for UpdatePenColorFromHSV { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || { - Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |_, _| { + Ok(Some(StaticFunction { export: None, params: Box::from([ValType::I32]), returns: Box::from([]), @@ -283,7 +284,7 @@ impl NamedRegistryItem for UpdatePenColorFromHSV { End, ] as &[_]) .into(), - }) + })) }, }; } @@ -306,8 +307,9 @@ pub struct UpdatePenColorFromRGB; impl NamedRegistryItem for UpdatePenColorFromRGB { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || { - Some(StaticFunction { + register_deps: |_| Ok(()), + maybe_populate: |_, _| { + Ok(Some(StaticFunction { export: None, params: Box::from([ValType::I32]), returns: Box::from([]), @@ -520,7 +522,7 @@ impl NamedRegistryItem for UpdatePenColorFromRGB { End, ] as &[_]) .into(), - }) + })) }, }; } diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index eecb24b9..0aec05fd 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -4,67 +4,57 @@ use wasm_gen::wasm_const; use super::{MaybeStaticFunction, StaticFunction}; use crate::prelude::*; use crate::wasm::mem_layout; +use crate::wasm::registries::functions::StaticFunctionRegistrar; use crate::wasm::registries::functions::dyn_array::{DynArrayNew, DynArrayPop, DynArrayPush}; use crate::wasm::registries::types::{ TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, TThreadArray, TType, }; -use crate::wasm::registries::{GlobalRegistry, StaticFunctionRegistry, TypeRegistry}; - -#[derive(Clone)] -pub struct SpawnThreadFuncOverride { - pub types: Rc, - pub globals: Rc, - pub static_functions: Rc, - pub num_sprites: u32, - pub imported_func_count: u32, - pub imported_global_count: u32, -} type StackStructRef = TNullable; /// Spawns a new thread in the same stack (i.e. a thread that yields back to the current /// thread once it completes). -/// +/// /// The step that is provided to return to will be written into /// the current stack frame, and the new thread's step is added to the top of the current /// frame with the provided struct argument so that that will run until completion before /// yielding to the provided next step. /// /// Takes 4 parameters: -/// - ref `stack_array`` - the current stack -/// - ref `step_func`` - the step to spawn +/// - ref `stack_array` - the current stack +/// - ref `step_func` - the step to spawn /// - structref - the structref to pass to the step being spawned -/// - ref `step_func`` - the step to return to after +/// - ref `step_func` - the step to return to after pub struct SpawnThreadInStack; impl NamedRegistryItem for SpawnThreadInStack { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} -impl TryNamedRegistryItemOverride - for SpawnThreadInStack -{ - fn try_override( - SpawnThreadFuncOverride { - types, - static_functions, - imported_func_count, - .. - }: SpawnThreadFuncOverride, - ) -> HQResult { - let stack_struct_type = types.register_comp::()?; - let dyn_array_push = static_functions.register::, u32>()?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + register_deps: |static_funcs| { + static_funcs.register::, usize>()?; + Ok(()) + }, + maybe_populate: |proj, static_funcs| { + let imported_func_count = proj.imported_func_count()?; + + let types = Rc::clone(proj.registries().types()); + + let stack_struct_type = TStackStruct::ty(&types)?; + + let dyn_array_pop = static_funcs + .get_index_of(&StaticFunctionRegistrar::name::>()) + .ok_or_else(|| make_hq_bug!("static function dependency not registered"))? + as u32; + let dyn_array_push = static_funcs + .get_index_of(&StaticFunctionRegistrar::name::>()) + .ok_or_else(|| make_hq_bug!("static function dependency not registered"))? + as u32; + + Ok(Some(StaticFunction { export: None, instructions: Box::from(wasm_const![ LocalGet(0), - Call( - imported_func_count - + static_functions.register::, u32>()? - ), + Call(imported_func_count + dyn_array_pop), Drop, LocalGet(0), LocalGet(3), @@ -88,10 +78,9 @@ impl TryNamedRegistryItemOverride ]), returns: Box::from([]), locals: Box::from([]), - }), - maybe_populate: || None, - }) - } + })) + }, + }; } /// Spawn a new thread with the provided step function. This does not call it @@ -105,26 +94,26 @@ pub struct SpawnNewThread; impl NamedRegistryItem for SpawnNewThread { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - maybe_populate: || None, - }; -} + register_deps: |static_funcs| { + static_funcs.register::, usize>()?; + static_funcs.register::, usize>()?; + static_funcs.register::>, usize>()?; + Ok(()) + }, + maybe_populate: |proj, static_funcs| { + let types = Rc::clone(proj.registries().types()); -impl TryNamedRegistryItemOverride for SpawnNewThread { - fn try_override( - SpawnThreadFuncOverride { - types, - globals, - static_functions, - num_sprites, - imported_func_count, - imported_global_count, - }: SpawnThreadFuncOverride, - ) -> HQResult { - let stack_struct_type = types.register_comp::()?; - let target_threads_type = types.register_comp::()?; - let target_threads_global: u32 = globals.threadss(&types, num_sprites)?; - Ok(MaybeStaticFunction { - static_function: Some(StaticFunction { + let stack_struct_type = types.register_comp::()?; + let target_threads_type = types.register_comp::()?; + let target_threads_global: u32 = proj + .registries() + .globals + .threadss(&types, proj.costume_names().len() as u32)?; + + let imported_global_count = proj.imported_global_count()?; + let imported_func_count = proj.imported_func_count()?; + + Ok(Some(StaticFunction { export: None, params: Box::from([ ValType::I32, @@ -143,7 +132,7 @@ impl TryNamedRegistryItemOverride I32Mul, I32Load16U(MemArg { offset: (mem_layout::stage::BLOCK_SIZE + mem_layout::sprite::LAYER) - as u64, + .into(), align: 1, memory_index: 0, }), @@ -155,8 +144,13 @@ impl TryNamedRegistryItemOverride I32Const(8), Call( imported_func_count - + static_functions - .register::, u32>()? + + (static_funcs + .get_index_of(&StaticFunctionRegistrar::name::< + DynArrayNew, + >()) + .ok_or_else(|| make_hq_bug!( + "static function dependency not registered" + ))? as u32) ), LocalTee(3), LocalGet(1), @@ -164,21 +158,30 @@ impl TryNamedRegistryItemOverride StructNew(stack_struct_type), Call( imported_func_count - + static_functions - .register::, u32>()? + + (static_funcs + .get_index_of(&StaticFunctionRegistrar::name::< + DynArrayPush, + >()) + .ok_or_else(|| make_hq_bug!( + "static function dependency not registered" + ))? as u32) ), LocalGet(3), Call( imported_func_count - + static_functions - .register::>, u32>()? + + (static_funcs + .get_index_of(&StaticFunctionRegistrar::name::< + DynArrayPush>, + >()) + .ok_or_else(|| make_hq_bug!( + "static function dependency not registered" + ))? as u32) ), End, ] as &[_]) .into() }, - }), - maybe_populate: || None, - }) - } + })) + }, + }; } diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index 16775948..b4d8b392 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -7,14 +7,14 @@ mod registration; #[macro_use] mod rec_group; mod registry; -mod tyfp; mod subtypes; +mod tyfp; pub use rec_group::*; pub use registration::*; pub use registry::{CompoundType, RecGroup, RegistryItem, TypeRegistry}; -pub use tyfp::*; pub use subtypes::*; +pub use tyfp::*; rec_group! { rec_grp { diff --git a/src/wasm/registries/types/rec_group.rs b/src/wasm/registries/types/rec_group.rs index 564d1144..5aa172a7 100644 --- a/src/wasm/registries/types/rec_group.rs +++ b/src/wasm/registries/types/rec_group.rs @@ -4,7 +4,7 @@ use wasm_encoder::HeapType; use super::dependencies::HasTypeDependencies; use super::registration::TRecGroupType; -use super::tyfp::{Func, Bool}; +use super::tyfp::{Bool, Func}; use super::{TypeRegisteringInfo, TypeRegistry}; use crate::prelude::*; use crate::wasm::registries::types::CompoundType; diff --git a/src/wasm/registries/types/registration.rs b/src/wasm/registries/types/registration.rs index f75cc97d..26028b36 100644 --- a/src/wasm/registries/types/registration.rs +++ b/src/wasm/registries/types/registration.rs @@ -61,7 +61,7 @@ where T: TType, { type Receiver = Rc; - + fn register(types: &Rc) -> HQResult { T::ty(types) } @@ -258,4 +258,4 @@ where Result::rec_group_ty(types)?, )) } -} \ No newline at end of file +} diff --git a/src/wasm/registries/types/registry.rs b/src/wasm/registries/types/registry.rs index 0ff3662e..e0de3530 100644 --- a/src/wasm/registries/types/registry.rs +++ b/src/wasm/registries/types/registry.rs @@ -1,5 +1,6 @@ use wasm_encoder::{ - AbstractHeapType, FieldType, HeapType, RefType, StorageType, TypeSection, ValType, + AbstractHeapType, ArrayType, CompositeInnerType, CompositeType, FieldType, FuncType, HeapType, + RefType, StorageType, StructType, SubType, TypeSection, ValType, }; use crate::ir::RcVar; @@ -97,22 +98,55 @@ impl TypeRegistry { ) } - fn finish_type(ty: CompoundType, types: &mut TypeSection) { + fn type_to_composite_inner(ty: CompoundType) -> CompositeInnerType { match ty { - CompoundType::Function(params, results) => types.ty().function(params, results), - CompoundType::Array(elem_type, mutable) => types.ty().array(&elem_type, mutable), - CompoundType::Struct(fields) => types.ty().struct_(fields), + CompoundType::Function(params, results) => { + CompositeInnerType::Func(FuncType::new(params, results)) + } + CompoundType::Struct(fields) => CompositeInnerType::Struct(StructType { + fields: fields.into(), + }), + CompoundType::Array(element_type, mutable) => { + CompositeInnerType::Array(ArrayType(FieldType { + element_type, + mutable, + })) + } + } + } + + fn type_to_composite(ty: CompoundType) -> CompositeType { + CompositeType { + inner: Self::type_to_composite_inner(ty), + shared: false, + describes: None, + descriptor: None, + } + } + + fn type_to_subtype(ty: CompoundType) -> SubType { + SubType { + is_final: true, + supertype_idx: None, + composite_type: Self::type_to_composite(ty), } } pub fn finish(self, types: &mut TypeSection) { for ty in self.registry().take().keys().cloned() { match ty { - RegistryItem::Type(ty) => Self::finish_type(ty, types), - RegistryItem::RecGroupItem(rec_group, index) => { - Self::finish_type(rec_group.types[index as usize].1.borrow().clone(), types); + RegistryItem::Type(ty) => types.ty().subtype(&Self::type_to_subtype(ty)), + RegistryItem::RecGroupItem(rec_group, 0) => { + types.ty().rec( + rec_group + .types + .iter() + .map(|(_, compound_ty)| compound_ty.borrow().clone()) + .map(Self::type_to_subtype), + ); } + RegistryItem::RecGroupItem(_, _) => (), } } } -} \ No newline at end of file +} diff --git a/src/wasm/registries/types/tyfp.rs b/src/wasm/registries/types/tyfp.rs index 61834145..d70b0d25 100644 --- a/src/wasm/registries/types/tyfp.rs +++ b/src/wasm/registries/types/tyfp.rs @@ -154,4 +154,4 @@ where Tail: ListItem<{ I - 1 }>, { type Get = Tail::Get; -} \ No newline at end of file +} From ff6b82340e46bfc3fda0387d7e7bffe5a14517fd Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Fri, 11 Sep 2026 21:05:35 +0100 Subject: [PATCH 12/18] fix static function dependency resolution --- src/instructions/tests.rs | 2 + src/registry.rs | 10 +- src/wasm/project.rs | 173 ++---------------- src/wasm/registries/functions.rs | 17 +- src/wasm/registries/functions/dyn_array.rs | 21 ++- .../registries/functions/mark_waiting_flag.rs | 2 +- src/wasm/registries/functions/pen_colour.rs | 4 +- .../registries/functions/spawn_threads.rs | 20 +- src/wasm/registries/functions/tick.rs | 161 ++++++++++++++++ .../registries/functions/unreachable_dbg.rs | 23 +++ src/wasm/registries/globals.rs | 24 ++- src/wasm/registries/types/dependencies.rs | 26 +-- src/wasm/registries/types/rec_group.rs | 93 ++++++---- src/wasm/registries/types/registration.rs | 63 ++++--- src/wasm/registries/types/registry.rs | 26 +-- 15 files changed, 386 insertions(+), 279 deletions(-) create mode 100644 src/wasm/registries/functions/tick.rs create mode 100644 src/wasm/registries/functions/unreachable_dbg.rs diff --git a/src/instructions/tests.rs b/src/instructions/tests.rs index 00cd5a7d..9d7a7861 100644 --- a/src/instructions/tests.rs +++ b/src/instructions/tests.rs @@ -324,6 +324,8 @@ mod test_util { let wasm_bytes = proj.finish().unwrap().wasm_bytes; + std::fs::write("./wasm.wasm", &wasm_bytes); + println!("{}", wasmprinter::print_bytes(wasm_bytes.clone()).unwrap()); wasmparser::validate(&wasm_bytes).map_err(|err| { diff --git a/src/registry.rs b/src/registry.rs index 3232883d..e81c78d2 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -252,7 +252,15 @@ where N: RegistryResult, T: NamedRegistryItem, { - self.0.register(R::name::(), T::VALUE) + let (key, value) = Self::registration::(); + self.0.register(key, value) + } + + pub fn registration() -> (R::Key, R::Value) + where + T: NamedRegistryItem, + { + (R::name::(), T::VALUE) } /// Registers a runtime key-value pair; just calls `register` on the underlying diff --git a/src/wasm/project.rs b/src/wasm/project.rs index 9e5718b7..73fbaeda 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -12,7 +12,7 @@ use super::{ExternalEnvironment, Registries}; use crate::ir::{Event, IrProject, IrType, StepIndex}; use crate::prelude::*; use crate::wasm::registries::functions::static_functions::{ - DynArrayGet, DynArrayLen, SpawnNewThread, SpawnThreadInStack, + DynArrayGet, DynArrayLen, SpawnNewThread, SpawnThreadInStack, Tick, UnreachableDbg, }; use crate::wasm::registries::types::{ TFunc, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, @@ -140,7 +140,17 @@ impl WasmProject { .clone() .finish(&mut imports, self.registries().types())?; - Rc::unwrap_or_clone(self.registries().static_functions().clone()).finish( + self.registries() + .static_functions() + .register::()?; + self.registries() + .static_functions() + .register::()?; + self.registries() + .static_functions() + .register::()?; // required for events finishing + + Rc::unwrap_or_clone(Rc::clone(self.registries().static_functions())).finish( &self, &mut functions, &mut exports, @@ -165,12 +175,8 @@ impl WasmProject { )?; } - self.tick_func(&mut functions, &mut codes, &mut exports)?; - self.finish_events(&mut functions, &mut codes, &mut exports)?; - self.unreachable_dbg_func(&mut functions, &mut codes, &mut exports)?; - codes.function(&start_func); functions.function(self.registries().types().function(vec![], vec![])?); @@ -180,8 +186,8 @@ impl WasmProject { elements.declared(Elements::Functions( (self.imported_func_count()? + self.static_func_count()? - ..self.imported_func_count()? - + self.static_func_count()? + ..dbg!(self.imported_func_count()?) + + dbg!(self.static_func_count()?) + u32::try_from(self.steps().try_borrow()?.len()) .map_err(|_| make_hq_bug!("steps len out of bounds"))?) .collect(), @@ -324,26 +330,6 @@ impl WasmProject { .map_err(|_| make_hq_bug!("string registry len out of bounds")) } - pub fn unreachable_dbg_func( - &self, - functions: &mut FunctionSection, - codes: &mut CodeSection, - exports: &mut ExportSection, - ) -> HQResult<()> { - let mut func = Function::new(vec![]); - func.instruction(&Instruction::Unreachable); - func.instruction(&Instruction::End); - codes.function(&func); - functions.function(self.registries().types().function(vec![], vec![])?); - exports.export( - "unreachable_dbg", - ExportKind::Func, - self.imported_func_count()? + functions.len() - 1, - ); - - Ok(()) - } - pub fn spawn_new_thread_func(&self) -> HQResult where N: TryFrom, @@ -565,137 +551,6 @@ impl WasmProject { Ok(()) } - fn tick_func( - &self, - funcs: &mut FunctionSection, - codes: &mut CodeSection, - exports: &mut ExportSection, - ) -> HQResult<()> { - let types = Rc::clone(self.registries().types()); - - let mut tick_func = Function::new(vec![ - (3, ValType::I32), - (1, >::ty(&types)?), - (1, >::ty(&types)?), - (1, >::ty(&types)?), - ]); - - let stack_struct_type = types.register_comp::()?; - let target_thread_struct_type = types.register_comp::()?; - let target_threads_array_type = types.register_comp::()?; - let step_func_ty = types.register_comp::()?; - - let threadss_global = self.threadss_global()?; - - let targets_num = 1 + self.costume_names().len() as i32; - - hq_assert!(targets_num > 0); - - const LOCAL_TARGET_INDEX: u32 = 0; - const LOCAL_STACK_INDEX: u32 = 1; - const LOCAL_THREADS_NUM: u32 = 2; - const LOCAL_THREAD_LIST: u32 = 3; - const LOCAL_THREAD: u32 = 4; - const LOCAL_STEP: u32 = 5; - - let instructions = wasm![ - Loop(WasmBlockType::Empty), - #LazyGlobalGet(threadss_global), - LocalGet(LOCAL_TARGET_INDEX), - ArrayGet(target_threads_array_type), - StructGet { - struct_type_index: target_thread_struct_type, - field_index: 1, - }, - LocalTee(LOCAL_THREAD_LIST), - #StaticFunctionCall( - self.registries() - .static_functions() - .register::>, u32>()? - ), - LocalTee(LOCAL_THREADS_NUM), - I32Eqz, - BrIf(0), - I32Const(0), - LocalSet(LOCAL_STACK_INDEX), - Loop(WasmBlockType::Empty), - LocalGet(LOCAL_THREAD_LIST), - LocalGet(LOCAL_STACK_INDEX), - #StaticFunctionCall( - self.registries() - .static_functions() - .register::>, u32>()? - ), - RefAsNonNull, - LocalTee(LOCAL_THREAD), - LocalGet(LOCAL_THREAD), - #StaticFunctionCall( - self.registries() - .static_functions() - .register::>, u32>()? - ), - I32Const(1), - I32Sub, - #StaticFunctionCall( - self.registries() - .static_functions() - .register::>, u32>()? - ), - RefAsNonNull, - LocalTee(LOCAL_STEP), - StructGet { - struct_type_index: stack_struct_type, - field_index: 1, - }, - LocalGet(LOCAL_STEP), - StructGet { - struct_type_index: stack_struct_type, - field_index: 0, - }, - CallRef(step_func_ty), - LocalGet(LOCAL_STACK_INDEX), - I32Const(1), - I32Add, - LocalTee(LOCAL_STACK_INDEX), - LocalGet(LOCAL_THREADS_NUM), - I32LtS, - BrIf(0), - End, - LocalGet(LOCAL_TARGET_INDEX), - I32Const(1), - I32Add, - LocalTee(LOCAL_TARGET_INDEX), - I32Const(targets_num), - I32LtS, - BrIf(0), - End, - ]; - for instr in instructions { - for real_instruction in instr.eval( - &self.events, - self.registries().types(), - self.threads_count_global()?, - self.spawn_new_thread_func()?, - self.spawn_thread_in_stack_func()?, - self.threadss_global()?, - self.imported_func_count()?, - self.static_func_count()?, - self.imported_global_count()?, - )? { - tick_func.instruction(&real_instruction); - } - } - tick_func.instruction(&Instruction::End); - funcs.function(types.register_comp::, _>()?); - codes.function(&tick_func); - exports.export( - "tick", - ExportKind::Func, - funcs.len() + self.imported_func_count()? - 1, - ); - Ok(()) - } - pub fn from_ir( ir_project: &Rc, _ssa_token: crate::optimisation::SSAToken, diff --git a/src/wasm/registries/functions.rs b/src/wasm/registries/functions.rs index bc4750b6..3ef18f4c 100644 --- a/src/wasm/registries/functions.rs +++ b/src/wasm/registries/functions.rs @@ -4,6 +4,8 @@ mod dyn_array; mod mark_waiting_flag; mod pen_colour; mod spawn_threads; +mod tick; +mod unreachable_dbg; use wasm_encoder::{ CodeSection, EntityType, ExportKind, ExportSection, Function, FunctionSection, ImportSection, @@ -53,7 +55,7 @@ pub struct MaybeStaticFunction { &WasmProject, &IndexMap, MaybeStaticFunction>, ) -> HQResult>, - pub register_deps: fn(&StaticFunctionRegistry) -> HQResult<()>, + pub register_deps: fn() -> Vec<(Box, MaybeStaticFunction)>, } pub struct StaticFunctionRegistrar; @@ -72,14 +74,18 @@ impl StaticFunctionRegistry { type_registry: &TypeRegistry, imported_func_count: u32, ) -> HQResult<()> { - let mut num_funcs = self.registry().borrow().len(); + let mut num_funcs = dbg!(self.registry().borrow().len()); + let mut to_register = vec![]; loop { for (_name, MaybeStaticFunction { register_deps, .. }) in self.registry().borrow().iter() { - register_deps(&self)?; + to_register.extend(register_deps()); } - let new_num_funcs = self.registry().borrow().len(); + for (key, val) in core::mem::take(&mut to_register) { + self.register_dyn::(key, val)?; + } + let new_num_funcs = dbg!(self.registry().borrow().len()); if new_num_funcs == num_funcs { break; } @@ -95,6 +101,7 @@ impl StaticFunctionRegistry { }, ) in ®istry { + dbg!(_name); let Some(StaticFunction { instructions, params, @@ -137,4 +144,6 @@ pub mod static_functions { pub use super::mark_waiting_flag::MarkWaitingFlag; pub use super::pen_colour::{UpdatePenColorFromHSV, UpdatePenColorFromRGB}; pub use super::spawn_threads::{SpawnNewThread, SpawnThreadInStack}; + pub use super::tick::Tick; + pub use super::unreachable_dbg::UnreachableDbg; } diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs index ef530377..aa6ef701 100644 --- a/src/wasm/registries/functions/dyn_array.rs +++ b/src/wasm/registries/functions/dyn_array.rs @@ -24,7 +24,7 @@ pub struct DynArrayPush(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayPush { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |proj, _| { let types = Rc::clone(proj.registries().types()); let struct_type = types.register_comp::, u32>()?; @@ -86,6 +86,7 @@ impl + TDefaultable> NamedRegistryItem fo struct_type_index: struct_type, field_index: 1, }, + End ] as &[_]), params: Box::from([>>::ty(&types)?, T::ty(&types)?]), returns: Box::from([]), @@ -106,7 +107,7 @@ pub struct DynArrayGet(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayGet { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |proj, _| { let types = Rc::clone(proj.registries().types()); let struct_type = types.register_comp::, u32>()?; @@ -121,6 +122,7 @@ impl + TDefaultable> NamedRegistryItem fo }, LocalGet(1), ArrayGet(array_type), + End, ] as &[_]), params: Box::from([>>::ty(&types)?, ValType::I32]), returns: Box::from([T::ty(&types)?]), @@ -140,7 +142,7 @@ pub struct DynArraySet(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArraySet { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |proj, _| { let types = Rc::clone(proj.registries().types()); let struct_type = types.register_comp::, u32>()?; @@ -156,6 +158,7 @@ impl + TDefaultable> NamedRegistryItem fo LocalGet(1), LocalGet(2), ArrayGet(array_type), + End, ] as &[_]), params: Box::from([ >>::ty(&types)?, @@ -179,7 +182,7 @@ pub struct DynArrayPop(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayPop { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |proj, _| { let types = Rc::clone(proj.registries().types()); let struct_type = types.register_comp::, u32>()?; @@ -207,6 +210,7 @@ impl + TDefaultable> NamedRegistryItem fo struct_type_index: struct_type, field_index: 1, }, + End, ] as &[_]), params: Box::from([>>::ty(&types)?]), returns: Box::from([T::ty(&types)?]), @@ -226,7 +230,7 @@ pub struct DynArrayNew(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayNew { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |proj, _| { let types = Rc::clone(proj.registries().types()); let struct_type = types.register_comp::, u32>()?; @@ -238,6 +242,7 @@ impl + TDefaultable> NamedRegistryItem fo ArrayNewDefault(array_type), I32Const(0), StructNew(struct_type), + End, ] as &[_]), params: Box::from([ValType::I32]), returns: Box::from([>>::ty(&types)?]), @@ -257,7 +262,7 @@ pub struct DynArrayLen(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayLen { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |proj, _| { let types = Rc::clone(proj.registries().types()); let struct_type = types.register_comp::, u32>()?; @@ -269,6 +274,7 @@ impl + TDefaultable> NamedRegistryItem fo struct_type_index: struct_type, field_index: 1 }, + End, ] as &[_]), params: Box::from([>>::ty(&types)?]), returns: Box::from([ValType::I32]), @@ -286,7 +292,7 @@ pub struct DynArrayClear(PhantomData); impl + TDefaultable> NamedRegistryItem for DynArrayClear { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |proj, _| { let types = Rc::clone(proj.registries().types()); let struct_type = types.register_comp::, u32>()?; @@ -299,6 +305,7 @@ impl + TDefaultable> NamedRegistryItem fo struct_type_index: struct_type, field_index: 1 }, + End, ] as &[_]), params: Box::from([>>::ty(&types)?]), returns: Box::from([ValType::I32]), diff --git a/src/wasm/registries/functions/mark_waiting_flag.rs b/src/wasm/registries/functions/mark_waiting_flag.rs index 0220e6c5..58a97d7f 100644 --- a/src/wasm/registries/functions/mark_waiting_flag.rs +++ b/src/wasm/registries/functions/mark_waiting_flag.rs @@ -16,7 +16,7 @@ pub struct MarkWaitingFlag; impl NamedRegistryItem for MarkWaitingFlag { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |proj, _| { let i8_struct_ty = proj.registries().types().struct_(vec![FieldType { element_type: StorageType::I8, diff --git a/src/wasm/registries/functions/pen_colour.rs b/src/wasm/registries/functions/pen_colour.rs index e5a2443b..dced8156 100644 --- a/src/wasm/registries/functions/pen_colour.rs +++ b/src/wasm/registries/functions/pen_colour.rs @@ -27,7 +27,7 @@ pub struct UpdatePenColorFromHSV; impl NamedRegistryItem for UpdatePenColorFromHSV { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |_, _| { Ok(Some(StaticFunction { export: None, @@ -307,7 +307,7 @@ pub struct UpdatePenColorFromRGB; impl NamedRegistryItem for UpdatePenColorFromRGB { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |_| Ok(()), + register_deps: || vec![], maybe_populate: |_, _| { Ok(Some(StaticFunction { export: None, diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index 0aec05fd..fd6a4970 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -4,6 +4,7 @@ use wasm_gen::wasm_const; use super::{MaybeStaticFunction, StaticFunction}; use crate::prelude::*; use crate::wasm::mem_layout; +use crate::wasm::registries::StaticFunctionRegistry; use crate::wasm::registries::functions::StaticFunctionRegistrar; use crate::wasm::registries::functions::dyn_array::{DynArrayNew, DynArrayPop, DynArrayPush}; use crate::wasm::registries::types::{ @@ -30,9 +31,10 @@ pub struct SpawnThreadInStack; impl NamedRegistryItem for SpawnThreadInStack { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |static_funcs| { - static_funcs.register::, usize>()?; - Ok(()) + register_deps: || { + vec![StaticFunctionRegistry::registration::< + DynArrayPop, + >()] }, maybe_populate: |proj, static_funcs| { let imported_func_count = proj.imported_func_count()?; @@ -69,6 +71,7 @@ impl NamedRegistryItem for SpawnThreadInStack { LocalGet(2), StructNew(stack_struct_type), Call(imported_func_count + dyn_array_push), + End, ] as &[_]), params: Box::from([ >::ty(&types)?, @@ -94,11 +97,12 @@ pub struct SpawnNewThread; impl NamedRegistryItem for SpawnNewThread { const VALUE: MaybeStaticFunction = MaybeStaticFunction { static_function: None, - register_deps: |static_funcs| { - static_funcs.register::, usize>()?; - static_funcs.register::, usize>()?; - static_funcs.register::>, usize>()?; - Ok(()) + register_deps: || { + vec![ + StaticFunctionRegistry::registration::>(), + StaticFunctionRegistry::registration::>(), + StaticFunctionRegistry::registration::>>(), + ] }, maybe_populate: |proj, static_funcs| { let types = Rc::clone(proj.registries().types()); diff --git a/src/wasm/registries/functions/tick.rs b/src/wasm/registries/functions/tick.rs new file mode 100644 index 00000000..3c500ced --- /dev/null +++ b/src/wasm/registries/functions/tick.rs @@ -0,0 +1,161 @@ +use wasm_encoder::{BlockType as WasmBlockType, ValType}; +use wasm_gen::wasm_const; + +use super::{MaybeStaticFunction, StaticFunction}; +use crate::prelude::*; +use crate::wasm::registries::StaticFunctionRegistry; +use crate::wasm::registries::functions::StaticFunctionRegistrar; +use crate::wasm::registries::functions::dyn_array::{DynArrayGet, DynArrayLen}; +use crate::wasm::registries::types::{ + TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, + TTargetThreadsStruct, TThreadArray, TType, +}; + +pub struct Tick; +impl NamedRegistryItem for Tick { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + register_deps: || { + vec![ + StaticFunctionRegistry::registration::>>(), + StaticFunctionRegistry::registration::>>(), + StaticFunctionRegistry::registration::>>(), + StaticFunctionRegistry::registration::>>(), + ] + }, + maybe_populate: |proj, static_functions| { + let types = Rc::clone(proj.registries().types()); + + let stack_struct_type = types.register_comp::()?; + let target_thread_struct_type = types.register_comp::()?; + let target_threads_array_type = types.register_comp::()?; + let step_func_ty = types.register_comp::()?; + + // this is fine to use here because strings are finished before static funcs, + // and strings are the only imported globals. + let imported_globals = proj.imported_global_count()?; + + let threadss_global = proj.threadss_global::()? + imported_globals; + + let targets_num = 1 + proj.costume_names().len() as i32; + + let imported_func_count = proj.imported_func_count()?; + + hq_assert!(targets_num > 0); + + const LOCAL_TARGET_INDEX: u32 = 0; + const LOCAL_STACK_INDEX: u32 = 1; + const LOCAL_THREADS_NUM: u32 = 2; + const LOCAL_THREAD_LIST: u32 = 3; + const LOCAL_THREAD: u32 = 4; + const LOCAL_STEP: u32 = 5; + + Ok(Some(StaticFunction { + export: Some("tick".into()), + instructions: Box::from(wasm_const![ + Loop(WasmBlockType::Empty), + GlobalGet(threadss_global), + LocalGet(LOCAL_TARGET_INDEX), + ArrayGet(target_threads_array_type), + StructGet { + struct_type_index: target_thread_struct_type, + field_index: 1, + }, + LocalTee(LOCAL_THREAD_LIST), + Call( + imported_func_count + + static_functions + .get_index_of(&StaticFunctionRegistrar::name::< + DynArrayLen>, + >()) + .ok_or_else(|| make_hq_bug!( + "static function dependency not registered" + ))? as u32 + ), + LocalTee(LOCAL_THREADS_NUM), + I32Eqz, + BrIf(0), + I32Const(0), + LocalSet(LOCAL_STACK_INDEX), + Loop(WasmBlockType::Empty), + LocalGet(LOCAL_THREAD_LIST), + LocalGet(LOCAL_STACK_INDEX), + Call( + imported_func_count + + static_functions + .get_index_of(&StaticFunctionRegistrar::name::< + DynArrayGet>, + >()) + .ok_or_else(|| make_hq_bug!( + "static function dependency not registered" + ))? as u32 + ), + RefAsNonNull, + LocalTee(LOCAL_THREAD), + LocalGet(LOCAL_THREAD), + Call( + imported_func_count + + static_functions + .get_index_of(&StaticFunctionRegistrar::name::< + DynArrayLen>, + >()) + .ok_or_else(|| make_hq_bug!( + "static function dependency not registered" + ))? as u32 + ), + I32Const(1), + I32Sub, + Call( + imported_func_count + + static_functions + .get_index_of(&StaticFunctionRegistrar::name::< + DynArrayGet>, + >()) + .ok_or_else(|| make_hq_bug!( + "static function dependency not registered" + ))? as u32 + ), + RefAsNonNull, + LocalTee(LOCAL_STEP), + StructGet { + struct_type_index: stack_struct_type, + field_index: 1, + }, + LocalGet(LOCAL_STEP), + StructGet { + struct_type_index: stack_struct_type, + field_index: 0, + }, + CallRef(step_func_ty), + LocalGet(LOCAL_STACK_INDEX), + I32Const(1), + I32Add, + LocalTee(LOCAL_STACK_INDEX), + LocalGet(LOCAL_THREADS_NUM), + I32LtS, + BrIf(0), + End, + LocalGet(LOCAL_TARGET_INDEX), + I32Const(1), + I32Add, + LocalTee(LOCAL_TARGET_INDEX), + I32Const(targets_num), + I32LtS, + BrIf(0), + End, + End, + ] as &[_]), + params: Box::new([]), + returns: Box::new([]), + locals: Box::new([ + ValType::I32, + ValType::I32, + ValType::I32, + >::ty(&types)?, + >::ty(&types)?, + >::ty(&types)?, + ]), + })) + }, + }; +} diff --git a/src/wasm/registries/functions/unreachable_dbg.rs b/src/wasm/registries/functions/unreachable_dbg.rs new file mode 100644 index 00000000..f43a2881 --- /dev/null +++ b/src/wasm/registries/functions/unreachable_dbg.rs @@ -0,0 +1,23 @@ +use wasm_encoder::{FieldType, HeapType, RefType, StorageType, ValType}; +use wasm_gen::wasm_const; + +use super::{MaybeStaticFunction, StaticFunction}; +use crate::prelude::*; + +/// Traps. Used for exposing the wasm module in devtools. +pub struct UnreachableDbg; +impl NamedRegistryItem for UnreachableDbg { + const VALUE: MaybeStaticFunction = MaybeStaticFunction { + static_function: None, + register_deps: || vec![], + maybe_populate: |_, _| { + Ok(Some(StaticFunction { + export: Some("unreachable_dbg".into()), + instructions: Box::from(wasm_const![Unreachable, End] as &[_]), + params: Box::new([]), + returns: Box::new([]), + locals: Box::new([]), + })) + }, + }; +} diff --git a/src/wasm/registries/globals.rs b/src/wasm/registries/globals.rs index 434da9ec..cc08ae5b 100644 --- a/src/wasm/registries/globals.rs +++ b/src/wasm/registries/globals.rs @@ -7,7 +7,10 @@ use wasm_encoder::{ use crate::prelude::*; use crate::registry::MapRegistry; use crate::wasm::registries::TypeRegistry; -use crate::wasm::registries::types::{TNonNullable, TTargetThreadArray, TThreadArray, TType}; +use crate::wasm::registries::types::{ + ListItem, StructSubTypes, TNonNullable, TRefType, TTargetThreadArray, TTargetThreadsStruct, + TThreadArray, TType, +}; #[derive(Copy, Clone, Debug)] pub struct GlobalMutable(pub bool); @@ -56,8 +59,11 @@ impl GlobalRegistry { N: TryFrom, >::Error: fmt::Debug, { - let array_array_type = types.register_comp::()?; - let array_type = types.register_comp::()?; + let array_array_type = TTargetThreadArray::ty(types)?; + let target_threads_struct_type = TTargetThreadsStruct::ty(types)?; + let dyn_array_type = types.register_comp::()?; + let array_type = <<::Fields as ListItem<0>>::Get as TRefType>::HeapType::ty(types)?; + self.register( "threadss".into(), ( @@ -67,16 +73,16 @@ impl GlobalRegistry { .flat_map(|i| { [ Instruction::I32Const(i as i32), - Instruction::I32Const(0), - Instruction::ArrayNewFixed { - array_type_index: array_type, - array_size: 0, - }, + Instruction::I32Const(8), + Instruction::ArrayNewDefault(array_type), + Instruction::I32Const(8), + Instruction::StructNew(dyn_array_type), + Instruction::StructNew(target_threads_struct_type), ] }) .chain([Instruction::ArrayNewFixed { array_type_index: array_array_type, - array_size: num_sprites, + array_size: num_sprites + 1, }]), ), // TODO: initialise properly GlobalMutable(true), diff --git a/src/wasm/registries/types/dependencies.rs b/src/wasm/registries/types/dependencies.rs index fd52f639..7e090b2b 100644 --- a/src/wasm/registries/types/dependencies.rs +++ b/src/wasm/registries/types/dependencies.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use wasm_encoder::{FieldType, HeapType, RefType, ValType}; use super::TypeRegistry; -use super::rec_group::RecGroupInfo; +use super::rec_group::RecGroupRegistry; use super::registration::{ TArray, TFieldType, TFunc, TI32, TRecGroupType, TRefType, TStruct, TStructRef, TType, }; @@ -97,7 +97,7 @@ where impl CompoundTypeDependencies for TStruct where - Fields: TRecGroupType, RecGroupInfo> + Fields: TRecGroupType, RecGroupRegistry> + HasTypeDependencies>, Fields::RecGroupDependencies: List, { @@ -109,7 +109,7 @@ where impl HasTypeDependencies for TStruct where - Fields: TRecGroupType, RecGroupInfo> + Fields: TRecGroupType, RecGroupRegistry> + HasTypeDependencies>, Self: CompoundTypeDependencies< Fields, @@ -166,10 +166,10 @@ where impl CompoundTypeDependencies<(Params, Results), ()> for TFunc where - Params: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, - Results: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Params: TRecGroupType, RecGroupRegistry> + + HasTypeDependencies>, + Results: TRecGroupType, RecGroupRegistry> + + HasTypeDependencies>, { type Dependencies = <<((HeapType, Self), ()) as List>::Concat as List>::Concat< @@ -182,10 +182,10 @@ where impl CompoundTypeDependencies<(Params, Results), (Head, Tail)> for TFunc where - Params: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, - Results: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + Params: TRecGroupType, RecGroupRegistry> + + HasTypeDependencies>, + Results: TRecGroupType, RecGroupRegistry> + + HasTypeDependencies>, { type Dependencies = ::Concat; @@ -197,9 +197,9 @@ where impl HasTypeDependencies for TFunc where Params: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + TRecGroupType, RecGroupRegistry> + HasTypeDependencies>, Results: - TRecGroupType, RecGroupInfo> + HasTypeDependencies>, + TRecGroupType, RecGroupRegistry> + HasTypeDependencies>, Self: CompoundTypeDependencies< (Params, Results), <>>::RecGroupDependencies as List>::Concat<>>::RecGroupDependencies>, diff --git a/src/wasm/registries/types/rec_group.rs b/src/wasm/registries/types/rec_group.rs index 5aa172a7..12b8558b 100644 --- a/src/wasm/registries/types/rec_group.rs +++ b/src/wasm/registries/types/rec_group.rs @@ -2,22 +2,46 @@ use core::marker::PhantomData; use wasm_encoder::HeapType; +use super::TypeRegistry; use super::dependencies::HasTypeDependencies; use super::registration::TRecGroupType; use super::tyfp::{Bool, Func}; -use super::{TypeRegisteringInfo, TypeRegistry}; use crate::prelude::*; -use crate::wasm::registries::types::CompoundType; +use crate::wasm::registries::types::{CompoundType, RegistryItem, TypeRegistryLike}; -#[derive(Clone)] -pub struct RecGroupInfo { +pub struct RecGroupRegistry { pub types: Rc, pub rec_group_start: u32, + pub main_rec_types_num: u32, + pub rec_type_deps: RefCell>, } -impl TypeRegisteringInfo for RecGroupInfo { - fn types(&self) -> &TypeRegistry { - &self.types +impl TypeRegistryLike for RecGroupRegistry { + fn register(&self, ty: CompoundType) -> HQResult + where + N: crate::registry::RegistryResult, + { + let idx = if let Some(idx) = self + .types + .registry() + .borrow() + .get_index_of(&RegistryItem::Type(ty.clone())) + { + idx + } else if let Some((idx, _)) = self + .rec_type_deps + .borrow() + .iter() + .find_position(|other| other == &&ty) + { + idx + } else { + let deps_len = self.rec_type_deps.borrow().len(); + self.rec_type_deps.borrow_mut().push(ty); + deps_len + (self.main_rec_types_num + self.rec_group_start) as usize + }; + idx.try_into() + .map_err(|_| make_hq_bug!("registry index out of bounds")) } } @@ -78,42 +102,49 @@ macro_rules! rec_group { }; } - fn ${concat($rec_group_name, _construct_rec_group)}() -> Rc { + fn ${concat($rec_group_name, _dummy_rec_group)}() -> Rc { Rc::new(RecGroup { - types: vec![ - $( - ( - core::any::type_name::<$name>(), - RefCell::new(CompoundType::Struct(vec![])), - ) - ),+ - ] + name: stringify!($rec_group_name).into(), + types: vec![] }) } fn ${ concat($rec_group_name, _register_rec_group) }(types: &Rc) -> HQResult<()> { use $crate::wasm::registries::types::dependencies::*; - let rec_group_types = ${concat($rec_group_name, _construct_rec_group)}(); - if types.registry().borrow().contains_key(&RegistryItem::RecGroupItem(Rc::clone(&rec_group_types), 0)) { + use $crate::wasm::registries::types::rec_group::RecGroupRegistry; + // let rec_group_types = ${concat($rec_group_name, _construct_rec_group)}(); + if types.registry().borrow().contains_key(&RegistryItem::RecGroupItem(${concat($rec_group_name, _dummy_rec_group)}(), 0)) { return Ok(()); } $( <$name as HasTypeDependencies>::Dependencies::register_each(types)?; )+ - for i in 0u32..(rec_group_types.types.len() as u32) { - types.register_default::(RegistryItem::RecGroupItem(Rc::clone(&rec_group_types), i))?; - } - let start_index = types.register_default::(RegistryItem::RecGroupItem(Rc::clone(&rec_group_types), 0))?; - let rec_group_info = RecGroupInfo { + // for i in 0u32..(rec_group_types.types.len() as u32) { + // types.register_default::(RegistryItem::RecGroupItem(Rc::clone(&rec_group_types), i))?; + // } + let start_index = types.registry().borrow().len() as u32; + let rec_group_info = RecGroupRegistry { types: Rc::clone(types), rec_group_start: start_index, + main_rec_types_num: ${count($name)}, + rec_type_deps: RefCell::new(vec![]), }; + let mut compound_types: Vec = vec![]; $( - *rec_group_types.types[${index()}].1.borrow_mut() = - $name::rec_group_ty( - &rec_group_info - )?; + compound_types.push($name::rec_group_ty(&rec_group_info)?); )+ + compound_types.extend(rec_group_info.rec_type_deps.take()); + let num_types = compound_types.len() as u32; + let rec_group = Rc::new(RecGroup { + name: stringify!($rec_group_name).into(), + types: compound_types, + }); + for i in 0..num_types { + types.register_default::(RegistryItem::RecGroupItem( + Rc::clone(&rec_group), + i + ))?; + } Ok(()) } @@ -132,7 +163,7 @@ macro_rules! rec_group { impl TRecGroupType> for $name { fn rec_group_ty(types: &Rc) -> HQResult { ${ concat($rec_group_name, _register_rec_group) }(types)?; - let rec_group_types = ${concat($rec_group_name, _construct_rec_group)}(); + let rec_group_types = ${concat($rec_group_name, _dummy_rec_group)}(); types.register_default(RegistryItem::RecGroupItem(rec_group_types, ${index()})) } } @@ -147,8 +178,8 @@ impl HasTypeDependencies for TRecGroupItem { type RecGroupDependencies = ((HeapType, Self), ()); } -impl TRecGroupType for TRecGroupItem { - fn rec_group_ty(registering_info: &RecGroupInfo) -> HQResult { +impl TRecGroupType for TRecGroupItem { + fn rec_group_ty(registering_info: &RecGroupRegistry) -> HQResult { Ok(HeapType::Concrete(registering_info.rec_group_start + I)) } } @@ -166,7 +197,7 @@ impl Bool for CompoundTypeRegistrationTester { impl Bool for CompoundTypeRegistrationTester<(HeadT, Head)> where - Head: TRecGroupType, + Head: TRecGroupType, { const BOOL: bool = true; } diff --git a/src/wasm/registries/types/registration.rs b/src/wasm/registries/types/registration.rs index 26028b36..a4a17e10 100644 --- a/src/wasm/registries/types/registration.rs +++ b/src/wasm/registries/types/registration.rs @@ -5,38 +5,51 @@ use wasm_encoder::{AbstractHeapType, FieldType, HeapType, RefType, StorageType, use super::tyfp::List; use super::{CompoundType, RegistryItem, TypeRegistry}; use crate::prelude::*; -use crate::registry::CompTimeRegistrand; +use crate::registry::{CompTimeRegistrand, RegistryResult}; -pub trait TypeRegisteringInfo { - fn types(&self) -> &TypeRegistry; +pub trait TypeRegistryLike { + fn register(&self, ty: CompoundType) -> HQResult + where + N: RegistryResult; } -impl TypeRegisteringInfo for Rc { - fn types(&self) -> &TypeRegistry { - self +impl TypeRegistryLike for Rc { + fn register(&self, ty: CompoundType) -> HQResult + where + N: RegistryResult, + { + self.register_default(RegistryItem::Type(ty)) } } -pub trait TRecGroupType { +// pub trait TypeRegisteringInfo { +// fn types(&self) -> &impl TypeRegistryLike; +// } + +// impl TypeRegisteringInfo for Rc { +// fn types(&self) -> &impl TypeRegistryLike { +// self +// } +// } + +pub trait TRecGroupType { fn rec_group_ty(registering_info: &I) -> HQResult; } impl TRecGroupType for T where T: TRecGroupType, - I: TypeRegisteringInfo, + I: TypeRegistryLike, { default fn rec_group_ty(types: &I) -> HQResult { - types - .types() - .register_default(RegistryItem::Type(T::rec_group_ty(types)?)) + types.register(T::rec_group_ty(types)?) } } impl TRecGroupType for T where T: TRecGroupType, - I: TypeRegisteringInfo, + I: TypeRegistryLike, { default fn rec_group_ty(types: &I) -> HQResult { Ok(HeapType::Concrete(T::rec_group_ty(types)?)) @@ -81,7 +94,7 @@ impl RegTypeList for () { impl RegTypeList for ((HeadT, Head), Tail) where - I: TypeRegisteringInfo, + I: TypeRegistryLike, Head: TRecGroupType, Tail: RegTypeList, { @@ -92,17 +105,17 @@ where } pub struct TStructRef; -impl TRecGroupType for TStructRef { +impl TRecGroupType for TStructRef { fn rec_group_ty(_types: &I) -> HQResult { panic!("this shouldn't be called ever!!! evil!!!") } } -impl TRecGroupType for TStructRef { +impl TRecGroupType for TStructRef { fn rec_group_ty(_types: &I) -> HQResult { panic!("this shouldn't be called ever!!! evil!!!") } } -impl TRecGroupType for TStructRef { +impl TRecGroupType for TStructRef { fn rec_group_ty(_types: &I) -> HQResult { Ok(HeapType::Abstract { shared: false, @@ -120,7 +133,7 @@ impl TRecGroupType for T where T: TRefType, T::HeapType: TRecGroupType, - I: TypeRegisteringInfo, + I: TypeRegistryLike, { fn rec_group_ty(types: &I) -> HQResult { Ok(RefType { @@ -147,7 +160,7 @@ impl TRecGroupType for T where T: TRefType, T::HeapType: TRecGroupType, - I: TypeRegisteringInfo, + I: TypeRegistryLike, { fn rec_group_ty(types: &I) -> HQResult { Ok(ValType::Ref( @@ -158,7 +171,7 @@ where pub struct TI32; -impl TRecGroupType for TI32 { +impl TRecGroupType for TI32 { fn rec_group_ty(_types: &I) -> HQResult { Ok(ValType::I32) } @@ -173,7 +186,7 @@ pub trait TFieldType { impl TRecGroupType for T where T: TFieldType, - I: TypeRegisteringInfo, + I: TypeRegistryLike, T::ValType: TRecGroupType, { fn rec_group_ty(types: &I) -> HQResult { @@ -197,7 +210,7 @@ impl TFieldType for TConstField { const MUTABLE: bool = false; } -impl TRecGroupType, I> for () { +impl TRecGroupType, I> for () { fn rec_group_ty(_types: &I) -> HQResult> { Ok(vec![]) } @@ -205,7 +218,7 @@ impl TRecGroupType, I> for () { impl TRecGroupType, I> for (Head, Tail) where - I: TypeRegisteringInfo, + I: TypeRegistryLike, Head: TRecGroupType, Tail: TRecGroupType, I>, { @@ -220,7 +233,7 @@ pub struct TStruct(PhantomData); impl TRecGroupType for TStruct where - I: TypeRegisteringInfo, + I: TypeRegistryLike, Fields: TRecGroupType, I>, { fn rec_group_ty(types: &I) -> HQResult { @@ -232,7 +245,7 @@ pub struct TArray(PhantomData); impl TRecGroupType for TArray where - I: TypeRegisteringInfo, + I: TypeRegistryLike, Field: TFieldType, Field::ValType: TRecGroupType, { @@ -248,7 +261,7 @@ pub struct TFunc(PhantomData, PhantomData); impl TRecGroupType for TFunc where - I: TypeRegisteringInfo, + I: TypeRegistryLike, Params: TRecGroupType, I>, Result: TRecGroupType, I>, { diff --git a/src/wasm/registries/types/registry.rs b/src/wasm/registries/types/registry.rs index e0de3530..16ace4a3 100644 --- a/src/wasm/registries/types/registry.rs +++ b/src/wasm/registries/types/registry.rs @@ -10,27 +10,19 @@ use crate::wasm::WasmProject; #[derive(Clone, Debug, Eq)] pub struct RecGroup { - pub types: Vec<(&'static str, RefCell)>, + pub name: Box, + pub types: Vec, } impl PartialEq for RecGroup { fn eq(&self, other: &Self) -> bool { - self.types.len() == other.types.len() - && self - .types - .iter() - .zip(&other.types) - .all(|((fst, _), (snd, _))| fst == snd) + self.name == other.name } } impl core::hash::Hash for RecGroup { fn hash(&self, state: &mut H) { - self.types - .iter() - .map(|(tystr, _)| tystr) - .collect::>() - .hash(state); + self.name.hash(state); } } @@ -137,13 +129,9 @@ impl TypeRegistry { match ty { RegistryItem::Type(ty) => types.ty().subtype(&Self::type_to_subtype(ty)), RegistryItem::RecGroupItem(rec_group, 0) => { - types.ty().rec( - rec_group - .types - .iter() - .map(|(_, compound_ty)| compound_ty.borrow().clone()) - .map(Self::type_to_subtype), - ); + types + .ty() + .rec(rec_group.types.iter().cloned().map(Self::type_to_subtype)); } RegistryItem::RecGroupItem(_, _) => (), } From e96f04b65e5a0071b3a6e96c90ba7a30b028eff2 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Fri, 11 Sep 2026 23:10:11 +0100 Subject: [PATCH 13/18] fixup some mistyped functions (incl casts between matching types) --- src/instructions/tests.rs | 5 +++-- src/wasm/registries/functions/spawn_threads.rs | 13 +++++++++---- src/wasm/registries/functions/tick.rs | 9 ++++++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/instructions/tests.rs b/src/instructions/tests.rs index 9d7a7861..ebd08bda 100644 --- a/src/instructions/tests.rs +++ b/src/instructions/tests.rs @@ -330,9 +330,10 @@ mod test_util { wasmparser::validate(&wasm_bytes).map_err(|err| { make_hq_bug!( - "invalid wasm module with types {:?}. Original error message: {}", + "invalid wasm module with types {:?}. Original error message: {}. At offset {}", types, - err.message() + err.message(), + err.offset() ) })?; diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index fd6a4970..ef473e4f 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -8,8 +8,8 @@ use crate::wasm::registries::StaticFunctionRegistry; use crate::wasm::registries::functions::StaticFunctionRegistrar; use crate::wasm::registries::functions::dyn_array::{DynArrayNew, DynArrayPop, DynArrayPush}; use crate::wasm::registries::types::{ - TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, - TThreadArray, TType, + TDynArray, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TStructRef, + TTargetThreadArray, TTargetThreadsStruct, TThreadArray, TType, }; type StackStructRef = TNullable; @@ -122,10 +122,10 @@ impl NamedRegistryItem for SpawnNewThread { params: Box::from([ ValType::I32, >::ty(&types)?, - StackStructRef::ty(&types)?, + >::ty(&types)?, ]), returns: Box::from([]), - locals: Box::from([>::ty(&types)?]), + locals: Box::from([>>::ty(&types)?]), instructions: { (wasm_const![ LocalGet(0), @@ -145,6 +145,10 @@ impl NamedRegistryItem for SpawnNewThread { GlobalGet(imported_global_count + target_threads_global), LocalGet(0), ArrayGet(target_threads_type), + StructGet { + struct_type_index: TTargetThreadsStruct::ty(&types)?, + field_index: 1, + }, I32Const(8), Call( imported_func_count @@ -171,6 +175,7 @@ impl NamedRegistryItem for SpawnNewThread { ))? as u32) ), LocalGet(3), + RefCastNonNull(TStackArray::ty(&types)?), Call( imported_func_count + (static_funcs diff --git a/src/wasm/registries/functions/tick.rs b/src/wasm/registries/functions/tick.rs index 3c500ced..39128850 100644 --- a/src/wasm/registries/functions/tick.rs +++ b/src/wasm/registries/functions/tick.rs @@ -7,7 +7,7 @@ use crate::wasm::registries::StaticFunctionRegistry; use crate::wasm::registries::functions::StaticFunctionRegistrar; use crate::wasm::registries::functions::dyn_array::{DynArrayGet, DynArrayLen}; use crate::wasm::registries::types::{ - TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, + TDynArray, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, TTargetThreadsStruct, TThreadArray, TType, }; @@ -17,7 +17,7 @@ impl NamedRegistryItem for Tick { static_function: None, register_deps: || { vec![ - StaticFunctionRegistry::registration::>>(), + StaticFunctionRegistry::registration::>>(), StaticFunctionRegistry::registration::>>(), StaticFunctionRegistry::registration::>>(), StaticFunctionRegistry::registration::>>(), @@ -66,7 +66,7 @@ impl NamedRegistryItem for Tick { imported_func_count + static_functions .get_index_of(&StaticFunctionRegistrar::name::< - DynArrayLen>, + DynArrayLen>, >()) .ok_or_else(|| make_hq_bug!( "static function dependency not registered" @@ -93,6 +93,9 @@ impl NamedRegistryItem for Tick { RefAsNonNull, LocalTee(LOCAL_THREAD), LocalGet(LOCAL_THREAD), + RefCastNonNull(>>::ty(&types)?), + LocalGet(LOCAL_THREAD), + RefCastNonNull(>>::ty(&types)?), Call( imported_func_count + static_functions From b3bb95f2c47fc3dbcc59a8890d2aa249ea3a6784 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Sat, 12 Sep 2026 15:24:06 +0100 Subject: [PATCH 14/18] more typecasting fixes --- Cargo.toml | 6 +-- src/instructions/hq/yield.rs | 34 +++++++++++---- src/instructions/procedures/call_nonwarp.rs | 10 ++++- src/instructions/procedures/call_warp.rs | 3 +- src/instructions/tests.rs | 12 +++--- src/wasm/func.rs | 24 +++++------ src/wasm/project.rs | 43 ++++++++++--------- src/wasm/registries/functions.rs | 10 ++--- .../registries/functions/spawn_threads.rs | 6 ++- 9 files changed, 90 insertions(+), 58 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b351c1ec..d4232684 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ publish = false serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } serde_json = { version = "1.0.150", default-features = false, features = ["alloc"] } enum-field-getter = { path = "enum-field-getter" } -wasm-encoder = "0.258.0" +wasm-encoder = "0.259.0" indexmap = { version = "2.14.0", default-features = false } hashers = "1.0.1" uuid = { version = "1.23.3", default-features = false, features = ["v4", "js"] } @@ -22,8 +22,8 @@ wasm-gen = { path = "wasm-gen", version = "0.2.0" } petgraph = { version = "0.8.1", default-features = false, features = ["stable_graph"] } [dev-dependencies] -wasmparser = "0.258.0" -wasmprinter = "0.258.0" +wasmparser = { git = "https://github.com/pufferfish101007/wasm-tools.git", rev = "184f8f5" } +wasmprinter = "0.259.0" [target.'cfg(not(target_family = "wasm"))'.dev-dependencies] # ezno-checker = { git = "https://github.com/kaleidawave/ezno.git", rev = "96d5058bdbb0cde924be008ca1e5a67fe39f46b9" } diff --git a/src/instructions/hq/yield.rs b/src/instructions/hq/yield.rs index d49c6a62..1a61686b 100644 --- a/src/instructions/hq/yield.rs +++ b/src/instructions/hq/yield.rs @@ -5,7 +5,9 @@ use crate::instructions_test; use crate::ir::{Step, StepIndex}; use crate::wasm::StepFunc; use crate::wasm::registries::functions::static_functions::{DynArrayGet, DynArrayLen, DynArrayPop}; -use crate::wasm::registries::types::{TNonNullable, TNullable, TStackStruct, TStepFunc, TType}; +use crate::wasm::registries::types::{ + TDynArray, TNonNullable, TNullable, TStackStruct, TStepFunc, TType, +}; #[derive(Debug, Clone)] pub enum YieldMode { @@ -69,26 +71,34 @@ pub fn wasm( let stack_get = static_functions.register::>, _>()?; + let stack_array_ty = >>::ty(&types)?; let step_struct_ty = TStackStruct::ty(&types)?; + let stack_local = (func.params().len() - 2) as u32; + let stack_len_local = func.local(ValType::I32)?; let step_struct_local = func.local(>::ty(&types)?)?; func.free_local(step_struct_local)?; func.free_local(stack_len_local)?; wasm![ - LocalGet(0), + LocalGet(stack_local), + RefCastNonNull(stack_array_ty), #StaticFunctionCall(pop_stack), - LocalGet(0), + Drop, + LocalGet(stack_local), + RefCastNonNull(stack_array_ty), #StaticFunctionCall(stack_len), + LocalTee(stack_len_local), I32Eqz, If(BlockType::Empty), // Empty stack cleanup (if it happens at all) will happen in scheduler, not here. Return, Else, - LocalGet(0), - LocalGet(0), - LocalGet(0), + LocalGet(stack_local), + LocalGet(stack_local), + LocalGet(stack_local), + RefCastNonNull(stack_array_ty), LocalGet(stack_len_local), I32Const(1), I32Sub, @@ -120,20 +130,28 @@ pub fn wasm( let static_functions = Rc::clone(func.registries().static_functions()); let types = Rc::clone(func.registries().types()); + let stack_array_ty = >>::ty(&types)?; + let step_func_ty = TStepFunc::ty(&types)?; + + let stack_local = (func.params().len() - 2) as u32; + let stack_len = static_functions.register::>, _>()?; let stack_get = static_functions.register::>, _>()?; wasm![ - LocalGet(0), - LocalGet(0), + LocalGet(stack_local), + RefCastNonNull(stack_array_ty), + LocalGet(stack_local), + RefCastNonNull(stack_array_ty), #StaticFunctionCall(stack_len), I32Const(1), I32Sub, #StaticFunctionCall(stack_get), RefAsNonNull, #LazyStepRef(*step_index), + RefCastNonNull(step_func_ty), StructSet { struct_type_index: TStackStruct::ty(&types)?, field_index: 0 }, Return ] diff --git a/src/instructions/procedures/call_nonwarp.rs b/src/instructions/procedures/call_nonwarp.rs index 231d7f90..abbc3038 100644 --- a/src/instructions/procedures/call_nonwarp.rs +++ b/src/instructions/procedures/call_nonwarp.rs @@ -4,7 +4,7 @@ use super::super::prelude::*; use crate::instructions_test; use crate::ir::{Proc, StepIndex}; use crate::wasm::registries::functions::static_functions::SpawnThreadInStack; -use crate::wasm::registries::types::TStepFunc; +use crate::wasm::registries::types::{TStepFunc, TType}; use crate::wasm::{StepFunc, WasmProject}; #[derive(Clone, Debug)] @@ -36,6 +36,8 @@ pub fn wasm( hq_bug!("nonwarped_specific_proc didn't exist for call_nonwarp") }; + let step_func_ty = TStepFunc::ty(func.registries().types())?; + let arg_struct_type = func.registries().types().struct_( (*nonwarped_specific_proc.arg_vars()) .borrow() @@ -97,12 +99,15 @@ pub fn wasm( LocalSet(arg_struct_local), LocalGet((func.params().len() - 2).try_into().map_err(|_| make_hq_bug!("local index out of bounds"))?), #LazyNonWarpedProcRef(Rc::clone(proc)), + RefCastNonNull(step_func_ty), LocalGet(arg_struct_local), #LazyStepRef(*next_step), + RefCastNonNull(step_func_ty), #StaticFunctionCall(spawn_thread_in_stack), LocalGet((func.params().len() - 2).try_into().map_err(|_| make_hq_bug!("local index out of bounds"))?), LocalGet(arg_struct_local), #LazyNonWarpedProcRef(Rc::clone(proc)), + RefCastNonNull(step_func_ty), ReturnCallRef(func.registries().types().register_comp::()?) ]); @@ -141,6 +146,7 @@ mod test { use super::super::super::tests::*; use super::*; use crate::ir::{PartialStep, StepIndex}; + use crate::wasm::registries::types::{TNonNullable, TStackArray, TType}; #[test] fn fields_display_is_valid_json() { @@ -151,7 +157,7 @@ mod test { pub fn test_project_setup(wasm_proj: &WasmProject, flags: crate::wasm::WasmFlags) { let proc_step_func = StepFunc::new_with_types( Box::from([ - ValType::I32, + >::ty(wasm_proj.registries().types()).unwrap(), crate::wasm::registries::TypeRegistry::STRUCT_REF, ]), vec![].into(), diff --git a/src/instructions/procedures/call_warp.rs b/src/instructions/procedures/call_warp.rs index d5579f8f..ac4866a0 100644 --- a/src/instructions/procedures/call_warp.rs +++ b/src/instructions/procedures/call_warp.rs @@ -112,6 +112,7 @@ mod test { use super::super::super::tests::*; use super::*; use crate::ir::{PartialStep, StepIndex}; + use crate::wasm::registries::types::{TNonNullable, TStackArray, TType}; #[test] fn fields_display_is_valid_json() { @@ -129,7 +130,7 @@ mod test { .iter() .map(|ty| WasmProject::ir_type_to_wasm(*ty)) .chain([ - ValType::I32, + >::ty(wasm_proj.registries().types()).unwrap(), crate::wasm::registries::TypeRegistry::STRUCT_REF, ]) .collect(), diff --git a/src/instructions/tests.rs b/src/instructions/tests.rs index ebd08bda..12922588 100644 --- a/src/instructions/tests.rs +++ b/src/instructions/tests.rs @@ -81,7 +81,7 @@ macro_rules! instructions_test { $($setup(&mut proj, flags());)? let output_type_result = output_type(types.clone().into(), $(&$fields)?); let registries = Rc::new(Registries::default()); - let step_func = StepFunc::new(Rc::clone(®istries), flags(), StepTarget::Sprite(0), 0, Rc::clone(proj.costume_names())); + let step_func = StepFunc::new(Rc::clone(®istries), flags(), StepTarget::Sprite(0), 0, Rc::clone(proj.costume_names())).unwrap(); let wasm_result = wasm(&step_func, types); match (output_type_result.clone(), wasm_result.clone()) { (Err(..), Ok(..)) | (Ok(..), Err(..)) => panic!("output_type result doesn't match wasm result for type(s) {:?}:\noutput_type: {:?},\nwasm: {:?}", ($($($type_arg,)*)?), output_type_result, wasm_result), @@ -228,12 +228,11 @@ pub use test_util::*; #[cfg(test)] mod test_util { - use wasm_encoder::ValType; - use crate::instructions::IrOpcode; use crate::ir::{IrType, ReturnType, Step, StepContext, Target}; use crate::prelude::*; use crate::wasm::registries::TypeRegistry; + use crate::wasm::registries::types::{TNonNullable, TStackArray, TType}; use crate::wasm::{InternalInstruction, StepFunc, StepTarget, WasmFlags, WasmProject}; pub fn make_target() -> Rc { @@ -289,7 +288,7 @@ mod test_util { .iter() .copied() .map(WasmProject::ir_type_to_wasm) - .chain([ValType::I32, TypeRegistry::STRUCT_REF]) + .chain([>::ty(registries.types())?, TypeRegistry::STRUCT_REF]) .collect::>(); let result = match output_type { ReturnType::Singleton(output) => vec![WasmProject::ir_type_to_wasm(output)], @@ -362,7 +361,10 @@ mod test_util { .iter() .copied() .map(WasmProject::ir_type_to_wasm) - .chain([ValType::I32, TypeRegistry::STRUCT_REF]) + .chain([ + >::ty(registries.types())?, + TypeRegistry::STRUCT_REF, + ]) .collect::>(); let result = vec![]; let step_func = StepFunc::new_with_types( diff --git a/src/wasm/func.rs b/src/wasm/func.rs index c248edda..ff43b372 100644 --- a/src/wasm/func.rs +++ b/src/wasm/func.rs @@ -12,6 +12,7 @@ use crate::instructions::{IrOpcode, wrap_instructions}; use crate::ir::{Event, PartialStep, Proc, RcVar, Step, StepIndex}; use crate::prelude::*; use crate::wasm::registries::TypeRegistry; +use crate::wasm::registries::types::{TNonNullable, TStackArray, TType}; #[derive(Clone, Debug)] pub enum Instruction { @@ -41,11 +42,6 @@ impl Instruction { ) -> HQResult]>> { Ok(match self { Self::Immediate(instr) => Box::from([instr.clone()]), - #[cfg(test)] - Self::LazyStepRef(_step) => Box::from([WInstruction::RefFunc( - imported_func_count + static_func_count, - )]), - #[cfg(not(test))] Self::LazyStepRef(step_index) => Box::from([WInstruction::RefFunc( imported_func_count + static_func_count @@ -274,19 +270,21 @@ impl StepFunc { } /// creates a new step function, with one paramter - #[must_use] pub fn new( registries: Rc, flags: WasmFlags, target: StepTarget, target_index: u32, costume_names: Rc>>>, - ) -> Self { - Self { + ) -> HQResult { + Ok(Self { locals: RefCell::new(vec![]), available_locals: RefCell::new(BTreeMap::new()), instructions: RefCell::new(vec![]), - params: Box::new([ValType::I32, TypeRegistry::STRUCT_REF]), + params: Box::new([ + >::ty(registries.types())?, + TypeRegistry::STRUCT_REF, + ]), output: Box::new([]), registries, flags, @@ -294,7 +292,7 @@ impl StepFunc { target, target_index, costume_names, - } + }) } /// creates a new step function with the specified amount of paramters. @@ -477,10 +475,10 @@ impl StepFunc { .borrow() .iter() .map(|var| WasmProject::ir_type_to_wasm(*var.possible_types())) - .chain([ValType::I32, TypeRegistry::STRUCT_REF]) + .chain([>::ty(registries.types())?, TypeRegistry::STRUCT_REF]) .collect() } else { - Box::from([ValType::I32, TypeRegistry::STRUCT_REF]) + Box::from([>::ty(registries.types())?, TypeRegistry::STRUCT_REF]) }; let outputs = if step.try_borrow()?.context().warp { (*proc_context.ret_vars) @@ -501,7 +499,7 @@ impl StepFunc { costume_names, ) } else { - Self::new(registries, flags, target, target_index, costume_names) + Self::new(registries, flags, target, target_index, costume_names)? }; if let Some(ref proc_context) = step.try_borrow()?.context().proc_context && !step.try_borrow()?.context().warp diff --git a/src/wasm/project.rs b/src/wasm/project.rs index 73fbaeda..cf70f936 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -150,7 +150,7 @@ impl WasmProject { .static_functions() .register::()?; // required for events finishing - Rc::unwrap_or_clone(Rc::clone(self.registries().static_functions())).finish( + let static_func_count = Rc::unwrap_or_clone(Rc::clone(self.registries().static_functions())).finish( &self, &mut functions, &mut exports, @@ -170,12 +170,12 @@ impl WasmProject { self.spawn_thread_in_stack_func()?, self.threadss_global()?, self.imported_func_count()?, - self.static_func_count()?, + static_func_count, self.imported_global_count()?, )?; } - self.finish_events(&mut functions, &mut codes, &mut exports)?; + self.finish_events(&mut functions, &mut codes, &mut exports, static_func_count)?; codes.function(&start_func); functions.function(self.registries().types().function(vec![], vec![])?); @@ -185,9 +185,9 @@ impl WasmProject { }; elements.declared(Elements::Functions( - (self.imported_func_count()? + self.static_func_count()? - ..dbg!(self.imported_func_count()?) - + dbg!(self.static_func_count()?) + (self.imported_func_count()? + static_func_count + ..self.imported_func_count()? + + static_func_count + u32::try_from(self.steps().try_borrow()?.len()) .map_err(|_| make_hq_bug!("steps len out of bounds"))?) .collect(), @@ -262,7 +262,7 @@ impl WasmProject { &mut exports, self.imported_global_count()?, self.imported_func_count()?, - self.static_func_count()?, + static_func_count, ); module @@ -310,15 +310,15 @@ impl WasmProject { .map_err(|_| make_hq_bug!("external function map len out of bounds")) } - pub fn static_func_count(&self) -> HQResult { - self.registries() - .static_functions() - .registry() - .try_borrow()? - .len() - .try_into() - .map_err(|_| make_hq_bug!("static function map len out of bounds")) - } + // pub fn static_func_count(&self) -> HQResult { + // self.registries() + // .static_functions() + // .registry() + // .try_borrow()? + // .len() + // .try_into() + // .map_err(|_| make_hq_bug!("static function map len out of bounds")) + // } pub fn imported_global_count(&self) -> HQResult { self.registries() @@ -376,6 +376,7 @@ impl WasmProject { funcs: &mut FunctionSection, codes: &mut CodeSection, exports: &mut ExportSection, + static_func_count: u32, ) -> HQResult { let mut func = Function::new(vec![]); @@ -387,7 +388,7 @@ impl WasmProject { .iter() .map(|&i| { Ok(wasm![ - RefFunc(i + self.imported_func_count()? + self.static_func_count()?), + RefFunc(i + self.imported_func_count()? + static_func_count), RefNull(HeapType::Abstract { shared: false, ty: AbstractHeapType::Struct @@ -407,7 +408,7 @@ impl WasmProject { self.spawn_thread_in_stack_func()?, self.threadss_global()?, self.imported_func_count()?, - self.static_func_count()?, + static_func_count, self.imported_global_count()?, )? { func.instruction(&real_instruction); @@ -430,7 +431,7 @@ impl WasmProject { self.spawn_thread_in_stack_func()?, self.threadss_global()?, self.imported_func_count()?, - self.static_func_count()?, + static_func_count, self.imported_global_count()?, )? { func.instruction(&real_instruction); @@ -454,6 +455,7 @@ impl WasmProject { funcs: &mut FunctionSection, codes: &mut CodeSection, exports: &mut ExportSection, + static_func_count: u32, ) -> HQResult<()> { let event_funcs = self .events @@ -473,6 +475,7 @@ impl WasmProject { funcs, codes, exports, + static_func_count, )?, ))) }) @@ -529,7 +532,7 @@ impl WasmProject { self.spawn_thread_in_stack_func()?, self.threadss_global()?, self.imported_func_count()?, - self.static_func_count()?, + static_func_count, self.imported_global_count()?, )? { sprite_clicked_func.instruction(&real_instruction); diff --git a/src/wasm/registries/functions.rs b/src/wasm/registries/functions.rs index 3ef18f4c..7ba31d63 100644 --- a/src/wasm/registries/functions.rs +++ b/src/wasm/registries/functions.rs @@ -65,6 +65,7 @@ impl RegistryType for StaticFunctionRegistrar { pub type StaticFunctionRegistry = NamedRegistry; impl StaticFunctionRegistry { + /// Finishes the registry. Returns the final size of the registry. pub fn finish( self, wasm_proj: &WasmProject, @@ -73,8 +74,8 @@ impl StaticFunctionRegistry { codes: &mut CodeSection, type_registry: &TypeRegistry, imported_func_count: u32, - ) -> HQResult<()> { - let mut num_funcs = dbg!(self.registry().borrow().len()); + ) -> HQResult { + let mut num_funcs = self.registry().borrow().len(); let mut to_register = vec![]; loop { for (_name, MaybeStaticFunction { register_deps, .. }) in @@ -85,7 +86,7 @@ impl StaticFunctionRegistry { for (key, val) in core::mem::take(&mut to_register) { self.register_dyn::(key, val)?; } - let new_num_funcs = dbg!(self.registry().borrow().len()); + let new_num_funcs = self.registry().borrow().len(); if new_num_funcs == num_funcs { break; } @@ -101,7 +102,6 @@ impl StaticFunctionRegistry { }, ) in ®istry { - dbg!(_name); let Some(StaticFunction { instructions, params, @@ -132,7 +132,7 @@ impl StaticFunctionRegistry { ); } } - Ok(()) + Ok(num_funcs as u32) } } diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index ef473e4f..b5be2fc2 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -42,6 +42,7 @@ impl NamedRegistryItem for SpawnThreadInStack { let types = Rc::clone(proj.registries().types()); let stack_struct_type = TStackStruct::ty(&types)?; + let stack_array_ty = >::ty(&types)?; let dyn_array_pop = static_funcs .get_index_of(&StaticFunctionRegistrar::name::>()) @@ -56,9 +57,11 @@ impl NamedRegistryItem for SpawnThreadInStack { export: None, instructions: Box::from(wasm_const![ LocalGet(0), + RefCastNonNull(stack_array_ty), Call(imported_func_count + dyn_array_pop), Drop, LocalGet(0), + RefCastNonNull(stack_array_ty), LocalGet(3), RefNull(HeapType::Abstract { shared: false, @@ -67,6 +70,7 @@ impl NamedRegistryItem for SpawnThreadInStack { StructNew(stack_struct_type), Call(imported_func_count + dyn_array_push), // TODO: this will do unnecessary bounds checks. Just mutate the last element. LocalGet(0), + RefCastNonNull(stack_array_ty), LocalGet(1), LocalGet(2), StructNew(stack_struct_type), @@ -76,7 +80,7 @@ impl NamedRegistryItem for SpawnThreadInStack { params: Box::from([ >::ty(&types)?, >::ty(&types)?, - StackStructRef::ty(&types)?, + >::ty(&types)?, >::ty(&types)?, ]), returns: Box::from([]), From e3487397af176eafc297bc45cb8f0ca7dca854b4 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Sat, 12 Sep 2026 15:51:26 +0100 Subject: [PATCH 15/18] ...and some more typecasting fixes --- src/instructions/control/stop_all.rs | 10 ++++++++-- src/instructions/control/wait.rs | 13 +++++++++++-- src/instructions/event/broadcast_and_wait.rs | 6 +++++- src/instructions/sensing/askandwait.rs | 14 ++++++++++++-- src/wasm/registries/functions/dyn_array.rs | 2 +- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/instructions/control/stop_all.rs b/src/instructions/control/stop_all.rs index 441d2547..502ba4dd 100644 --- a/src/instructions/control/stop_all.rs +++ b/src/instructions/control/stop_all.rs @@ -3,7 +3,9 @@ use wasm_encoder::HeapType; use super::super::prelude::*; use crate::instructions_test; use crate::wasm::registries::functions::static_functions::DynArrayClear; -use crate::wasm::registries::types::{TNullable, TTargetThreadArray, TThreadArray}; +use crate::wasm::registries::types::{ + TNullable, TStackArray, TTargetThreadArray, TTargetThreadsStruct, TThreadArray, TType, +}; fn clear_thread( threads_count: u32, @@ -36,7 +38,7 @@ pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult>, _>()?; + .register::>, _>()?; Ok(wasm![ I32Const(0), @@ -47,6 +49,10 @@ pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult Fields { Fields { poll_step: StepIndex(0), - next_step: StepIndex(1), + next_step: StepIndex(0), } } pub fn setup_project(wasm_proj: &WasmProject, flags: WasmFlags) { let step_func = StepFunc::new_with_types( - Box::from([ValType::I32, TypeRegistry::STRUCT_REF]), + Box::from([ + >::ty(wasm_proj.registries().types()).unwrap(), + TypeRegistry::STRUCT_REF, + ]), Box::from([]), wasm_proj.registries(), flags, diff --git a/src/instructions/event/broadcast_and_wait.rs b/src/instructions/event/broadcast_and_wait.rs index 3923b3fc..462d063a 100644 --- a/src/instructions/event/broadcast_and_wait.rs +++ b/src/instructions/event/broadcast_and_wait.rs @@ -74,6 +74,7 @@ mod test { use super::*; use crate::instructions::tests::assert_valid_json; use crate::wasm::registries::TypeRegistry; + use crate::wasm::registries::types::{TNonNullable, TStackArray, TType}; use crate::wasm::{StepTarget, WasmFlags, WasmProject}; #[test] @@ -92,7 +93,10 @@ mod test { pub fn setup_project(wasm_proj: &WasmProject, flags: WasmFlags) { let step_func = StepFunc::new_with_types( - Box::from([ValType::I32, TypeRegistry::STRUCT_REF]), + Box::from([ + >::ty(wasm_proj.registries().types()).unwrap(), + TypeRegistry::STRUCT_REF, + ]), Box::from([]), wasm_proj.registries(), flags, diff --git a/src/instructions/sensing/askandwait.rs b/src/instructions/sensing/askandwait.rs index 5c2f4a95..17b41e87 100644 --- a/src/instructions/sensing/askandwait.rs +++ b/src/instructions/sensing/askandwait.rs @@ -4,6 +4,7 @@ use super::super::prelude::*; use crate::ir::StepIndex; use crate::wasm::StepFunc; use crate::wasm::registries::functions::static_functions::{MarkWaitingFlag, SpawnThreadInStack}; +use crate::wasm::registries::types::{TStepFunc, TType}; #[derive(Clone, Debug)] pub struct Fields { @@ -39,7 +40,10 @@ pub fn wasm( let struct_valtype = ValType::Ref(RefType { nullable: false, heap_type: HeapType::Concrete(i8_struct_type), - }); + }); // TODO: rust-type-ify these types + + let step_func_ty = TStepFunc::ty(func.registries().types())?; + let struct_local = func.local(struct_valtype)?; func.free_local(struct_local)?; @@ -66,9 +70,11 @@ pub fn wasm( .map_err(|_| make_hq_bug!("local index out of bounds"))? ), #LazyStepRef(*poll_step), + RefCastNonNull(step_func_ty), StructNewDefault(i8_struct_type), LocalTee(struct_local), #LazyStepRef(*next_step), + RefCastNonNull(step_func_ty), #StaticFunctionCall(spawn_thread_func), LocalGet(struct_local), Call(queue_ask), @@ -98,6 +104,7 @@ mod test { use super::super::super::tests::*; use super::*; use crate::wasm::registries::TypeRegistry; + use crate::wasm::registries::types::{TNonNullable, TStackArray, TType}; use crate::wasm::{StepTarget, WasmFlags, WasmProject}; #[test] @@ -115,7 +122,10 @@ mod test { pub fn setup_project(wasm_proj: &WasmProject, flags: WasmFlags) { let step_func = StepFunc::new_with_types( - Box::from([ValType::I32, TypeRegistry::STRUCT_REF]), + Box::from([ + >::ty(wasm_proj.registries().types()).unwrap(), + TypeRegistry::STRUCT_REF, + ]), Box::from([]), wasm_proj.registries(), flags, diff --git a/src/wasm/registries/functions/dyn_array.rs b/src/wasm/registries/functions/dyn_array.rs index aa6ef701..d0a558e1 100644 --- a/src/wasm/registries/functions/dyn_array.rs +++ b/src/wasm/registries/functions/dyn_array.rs @@ -308,7 +308,7 @@ impl + TDefaultable> NamedRegistryItem fo End, ] as &[_]), params: Box::from([>>::ty(&types)?]), - returns: Box::from([ValType::I32]), + returns: Box::from([]), locals: Box::from([]), })) }, From 2bfbde497dcbda639bef02746a9cd61065573c8d Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Sun, 13 Sep 2026 16:24:11 +0100 Subject: [PATCH 16/18] fix broadcast & wait --- src/instructions.rs | 2 + src/instructions/event/broadcast_and_wait.rs | 15 ++-- .../event/poll_waiting_threads.rs | 4 +- src/wasm/func.rs | 87 ++++++++++++------- src/wasm/project.rs | 56 +++++++++--- .../registries/functions/spawn_threads.rs | 8 +- 6 files changed, 116 insertions(+), 56 deletions(-) diff --git a/src/instructions.rs b/src/instructions.rs index b3afad52..d3bb44dc 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -26,6 +26,8 @@ mod pen; mod procedures; mod sensing; +pub use event::poll_waiting_threads::{TPollStruct, TWaitingThreadArray}; + #[macro_use] mod tests; diff --git a/src/instructions/event/broadcast_and_wait.rs b/src/instructions/event/broadcast_and_wait.rs index 462d063a..b7f18f23 100644 --- a/src/instructions/event/broadcast_and_wait.rs +++ b/src/instructions/event/broadcast_and_wait.rs @@ -1,9 +1,9 @@ -use wasm_encoder::{HeapType, StorageType}; - use super::super::prelude::*; +use crate::instructions::TWaitingThreadArray; use crate::instructions_test; use crate::ir::StepIndex; use crate::wasm::StepFunc; +use crate::wasm::registries::types::{TNonNullable, TType}; #[derive(Clone, Debug)] pub struct Fields { @@ -35,14 +35,9 @@ pub fn wasm( next_step, }: &Fields, ) -> HQResult> { - let i32_array_type = func - .registries() - .types() - .array(StorageType::Val(ValType::I32), true)?; - let arr_local = func.local(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(i32_array_type), - }))?; + let arr_local = func.local(>::ty( + func.registries().types(), + )?)?; func.free_local(arr_local)?; Ok(wasm![ diff --git a/src/instructions/event/poll_waiting_threads.rs b/src/instructions/event/poll_waiting_threads.rs index 6769f1f8..07c20d9a 100644 --- a/src/instructions/event/poll_waiting_threads.rs +++ b/src/instructions/event/poll_waiting_threads.rs @@ -14,8 +14,8 @@ use crate::wasm::registries::types::{ TType, }; -type TWaitingThreadArray = TArray>>; -type TPollStruct = TStruct<(TConstField>, ())>; +pub type TWaitingThreadArray = TArray>>; +pub type TPollStruct = TStruct<(TConstField>, ())>; pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult> { let types = Rc::clone(func.registries().types()); diff --git a/src/wasm/func.rs b/src/wasm/func.rs index ff43b372..79b34576 100644 --- a/src/wasm/func.rs +++ b/src/wasm/func.rs @@ -8,11 +8,13 @@ use wasm_encoder::{ use wasm_gen::wasm; use super::{Registries, WasmFlags, WasmProject}; -use crate::instructions::{IrOpcode, wrap_instructions}; +use crate::instructions::{IrOpcode, TPollStruct, TWaitingThreadArray, wrap_instructions}; use crate::ir::{Event, PartialStep, Proc, RcVar, Step, StepIndex}; use crate::prelude::*; use crate::wasm::registries::TypeRegistry; -use crate::wasm::registries::types::{TNonNullable, TStackArray, TType}; +use crate::wasm::registries::types::{ + TArray, TConstField, TMutField, TNonNullable, TStackArray, TStepFunc, TStruct, TType, +}; #[derive(Clone, Debug)] pub enum Instruction { @@ -39,6 +41,7 @@ impl Instruction { imported_func_count: u32, static_func_count: u32, imported_global_count: u32, + steps: &Rc>>, ) -> HQResult]>> { Ok(match self { Self::Immediate(instr) => Box::from([instr.clone()]), @@ -52,20 +55,34 @@ impl Instruction { let broadcast_indices = events .get(&Event::Broadcast(broadcast.clone())) .cloned() - .unwrap_or_default(); + .unwrap_or_default() + .into_iter() + .map(|i| { + HQResult::Ok(( + i, + steps + .try_borrow()? + .get(i as usize) + .ok_or_else(|| make_hq_bug!("step index out of bounds"))? + .target_index() as i32, + )) + }) + .collect::>>()?; // todo: these should begin execution in the same step, I think, possibly immediately? broadcast_indices .iter() - .flat_map(|&i| { + .flat_map(|&(i, target)| { [ + WInstruction::I32Const(target), WInstruction::RefFunc(i + imported_func_count + static_func_count), WInstruction::RefNull(HeapType::Abstract { shared: false, ty: AbstractHeapType::Struct, }), WInstruction::Call(spawn_new_thread_func + imported_func_count), + WInstruction::Drop, ] }) .chain([ @@ -80,19 +97,25 @@ impl Instruction { .collect() } Self::LazyBroadcastSpawnAndWait((broadcast, poll_step, next_step, arr_local)) => { - let broadcast_indices = events + let broadcast_and_target_indices = events .get(&Event::Broadcast(broadcast.clone())) .cloned() - .unwrap_or_default(); - - let i32_array_type = types.array(StorageType::Val(ValType::I32), true)?; - let thread_poll_struct = types.struct_(vec![FieldType { - element_type: StorageType::Val(ValType::Ref(RefType { - nullable: false, - heap_type: HeapType::Concrete(i32_array_type), - })), - mutable: false, - }])?; + .unwrap_or_default() + .into_iter() + .map(|i| { + HQResult::Ok(( + i, + steps + .try_borrow()? + .get(i as usize) + .ok_or_else(|| make_hq_bug!("step index out of bounds"))? + .target_index(), + )) + }) + .collect::>>()?; + let waiting_thread_array_type = TWaitingThreadArray::ty(types)?; + let poll_struct_type = TPollStruct::ty(types)?; + let step_func_type = TStepFunc::ty(types)?; let poll_step_index: u32 = poll_step .0 @@ -104,35 +127,31 @@ impl Instruction { .try_into() .map_err(|_| make_hq_bug!("next_step index out of bounds"))?; - let broadcast_num = i32::try_from(broadcast_indices.len()) + let broadcast_num = i32::try_from(broadcast_and_target_indices.len()) .map_err(|_| make_hq_bug!("indices len out of bounds"))?; [ WInstruction::I32Const(broadcast_num), - WInstruction::ArrayNewDefault(i32_array_type), + WInstruction::ArrayNewDefault(waiting_thread_array_type), WInstruction::LocalSet(*arr_local), ] .into_iter() .chain( - broadcast_indices + broadcast_and_target_indices .iter() - .enumerate() - .map(|(j, &i)| { + .map(|&(i, target)| { // todo: should these should begin execution in the same step? Ok([ WInstruction::LocalGet(*arr_local), - WInstruction::I32Const( - j.try_into() - .map_err(|_| make_hq_bug!("index out of bounds"))?, - ), - // WInstruction::TableSize(threads_table), - WInstruction::ArraySet(i32_array_type), + WInstruction::I32Const(target as i32), WInstruction::RefFunc(i + imported_func_count + static_func_count), + WInstruction::RefCastNonNull(step_func_type), WInstruction::RefNull(HeapType::Abstract { shared: false, ty: AbstractHeapType::Struct, }), WInstruction::Call(spawn_new_thread_func + imported_func_count), + WInstruction::ArraySet(waiting_thread_array_type), ]) }) .collect::>>()? @@ -147,11 +166,13 @@ impl Instruction { WInstruction::RefFunc( poll_step_index + imported_func_count + static_func_count, ), + WInstruction::RefCastNonNull(step_func_type), WInstruction::LocalGet(*arr_local), - WInstruction::StructNew(thread_poll_struct), + WInstruction::StructNew(poll_struct_type), WInstruction::RefFunc( next_step_index + imported_func_count + static_func_count, ), + WInstruction::RefCastNonNull(step_func_type), WInstruction::Call(spawn_thread_in_stack_func + imported_func_count), ]) .collect() @@ -407,6 +428,7 @@ impl StepFunc { imported_func_count: u32, static_func_count: u32, imported_global_count: u32, + steps: &Rc>>, ) -> HQResult<()> { let mut func = Function::new_with_locals_types(self.locals.take()); for instruction in self.instructions().take() { @@ -420,6 +442,7 @@ impl StepFunc { imported_func_count, static_func_count, imported_global_count, + steps, )? { func.instruction(&real_instruction); } @@ -475,10 +498,16 @@ impl StepFunc { .borrow() .iter() .map(|var| WasmProject::ir_type_to_wasm(*var.possible_types())) - .chain([>::ty(registries.types())?, TypeRegistry::STRUCT_REF]) + .chain([ + >::ty(registries.types())?, + TypeRegistry::STRUCT_REF, + ]) .collect() } else { - Box::from([>::ty(registries.types())?, TypeRegistry::STRUCT_REF]) + Box::from([ + >::ty(registries.types())?, + TypeRegistry::STRUCT_REF, + ]) }; let outputs = if step.try_borrow()?.context().warp { (*proc_context.ret_vars) diff --git a/src/wasm/project.rs b/src/wasm/project.rs index cf70f936..ec6d248c 100644 --- a/src/wasm/project.rs +++ b/src/wasm/project.rs @@ -11,13 +11,11 @@ use wasm_gen::wasm; use super::{ExternalEnvironment, Registries}; use crate::ir::{Event, IrProject, IrType, StepIndex}; use crate::prelude::*; +use crate::wasm::registries::TypeRegistry; use crate::wasm::registries::functions::static_functions::{ - DynArrayGet, DynArrayLen, SpawnNewThread, SpawnThreadInStack, Tick, UnreachableDbg, -}; -use crate::wasm::registries::types::{ - TFunc, TNonNullable, TNullable, TStackArray, TStackStruct, TStepFunc, TTargetThreadArray, - TTargetThreadsStruct, TThreadArray, TType, + SpawnNewThread, SpawnThreadInStack, Tick, UnreachableDbg, }; +use crate::wasm::registries::types::{TStepFunc, TType}; use crate::wasm::{StepFunc, StringsTable, WasmFlags}; /// A respresentation of a WASM representation of a project. Cannot be created directly; @@ -149,15 +147,19 @@ impl WasmProject { self.registries() .static_functions() .register::()?; // required for events finishing + self.registries() + .static_functions() + .register::()?; // required for broadcasts - let static_func_count = Rc::unwrap_or_clone(Rc::clone(self.registries().static_functions())).finish( - &self, - &mut functions, - &mut exports, - &mut codes, - self.registries.types(), - self.imported_func_count()?, - )?; + let static_func_count = + Rc::unwrap_or_clone(Rc::clone(self.registries().static_functions())).finish( + &self, + &mut functions, + &mut exports, + &mut codes, + self.registries.types(), + self.imported_func_count()?, + )?; for step_func in self.steps().try_borrow()?.iter().cloned() { step_func.finish( @@ -172,10 +174,18 @@ impl WasmProject { self.imported_func_count()?, static_func_count, self.imported_global_count()?, + self.steps(), )?; } - self.finish_events(&mut functions, &mut codes, &mut exports, static_func_count)?; + self.finish_events( + &mut functions, + &mut codes, + &mut exports, + static_func_count, + self.steps(), + self.registries().types(), + )?; codes.function(&start_func); functions.function(self.registries().types().function(vec![], vec![])?); @@ -377,6 +387,8 @@ impl WasmProject { codes: &mut CodeSection, exports: &mut ExportSection, static_func_count: u32, + steps: &Rc>>, + types: &Rc, ) -> HQResult { let mut func = Function::new(vec![]); @@ -388,12 +400,21 @@ impl WasmProject { .iter() .map(|&i| { Ok(wasm![ + I32Const( + steps + .try_borrow()? + .get(i as usize) + .ok_or_else(|| make_hq_bug!("step index out of bounds"))? + .target_index() as i32 + ), RefFunc(i + self.imported_func_count()? + static_func_count), + RefCastNonNull(TStepFunc::ty(types)?), RefNull(HeapType::Abstract { shared: false, ty: AbstractHeapType::Struct }), #StaticFunctionCall(spawn_new_thread), + Drop, ]) }) .flatten_ok() @@ -410,6 +431,7 @@ impl WasmProject { self.imported_func_count()?, static_func_count, self.imported_global_count()?, + self.steps(), )? { func.instruction(&real_instruction); } @@ -433,6 +455,7 @@ impl WasmProject { self.imported_func_count()?, static_func_count, self.imported_global_count()?, + self.steps(), )? { func.instruction(&real_instruction); } @@ -456,6 +479,8 @@ impl WasmProject { codes: &mut CodeSection, exports: &mut ExportSection, static_func_count: u32, + steps: &Rc>>, + types: &Rc, ) -> HQResult<()> { let event_funcs = self .events @@ -476,6 +501,8 @@ impl WasmProject { codes, exports, static_func_count, + steps, + types, )?, ))) }) @@ -534,6 +561,7 @@ impl WasmProject { self.imported_func_count()?, static_func_count, self.imported_global_count()?, + self.steps(), )? { sprite_clicked_func.instruction(&real_instruction); } diff --git a/src/wasm/registries/functions/spawn_threads.rs b/src/wasm/registries/functions/spawn_threads.rs index b5be2fc2..22905ac9 100644 --- a/src/wasm/registries/functions/spawn_threads.rs +++ b/src/wasm/registries/functions/spawn_threads.rs @@ -97,6 +97,8 @@ impl NamedRegistryItem for SpawnThreadInStack { /// - i32 - the index of the target to spawn a thread for /// - step funcref - the step to spawn /// - ref null struct - the stack struct to spawn it with +/// +/// Returns ref TStackArray pub struct SpawnNewThread; impl NamedRegistryItem for SpawnNewThread { const VALUE: MaybeStaticFunction = MaybeStaticFunction { @@ -128,7 +130,9 @@ impl NamedRegistryItem for SpawnNewThread { >::ty(&types)?, >::ty(&types)?, ]), - returns: Box::from([]), + returns: Box::from([ + >::ty(&types)?, + ]), locals: Box::from([>>::ty(&types)?]), instructions: { (wasm_const![ @@ -190,6 +194,8 @@ impl NamedRegistryItem for SpawnNewThread { "static function dependency not registered" ))? as u32) ), + LocalGet(3), + RefCastNonNull(TStackArray::ty(&types)?), End, ] as &[_]) .into() From 7bbc9da54206a08f18d92a97f82db4979cbb0bd6 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Sun, 13 Sep 2026 16:24:35 +0100 Subject: [PATCH 17/18] distinguish same-shaped types in distinct rec groups --- src/wasm/registries/types/rec_group.rs | 32 +++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/wasm/registries/types/rec_group.rs b/src/wasm/registries/types/rec_group.rs index 12b8558b..cb8cb4a1 100644 --- a/src/wasm/registries/types/rec_group.rs +++ b/src/wasm/registries/types/rec_group.rs @@ -45,6 +45,26 @@ impl TypeRegistryLike for RecGroupRegistry { } } +pub struct RecGroupMember(PhantomData<(Marker, T)>); + +impl HasTypeDependencies for RecGroupMember +where + T: HasTypeDependencies, +{ + type Dependencies = T::Dependencies; + type RecGroupDependencies = T::RecGroupDependencies; +} + +impl TRecGroupType for RecGroupMember +where + T: TRecGroupType, + // I: TypeRegistryLike, +{ + fn rec_group_ty(types: &RecGroupRegistry) -> HQResult { + T::rec_group_ty(types) + } +} + #[macro_export] macro_rules! rec_group { ( @@ -148,10 +168,16 @@ macro_rules! rec_group { Ok(()) } + #[expect(non_camel_case_types, reason = "name given in snake_case")] + pub struct ${concat(Marker_, $rec_group_name)}; + $( - pub type $name = ${ concat($rec_group_name, _sub_rec_group_types) }!( - $typename{$($typeparams)+} - ); + pub type $name = $crate::wasm::registries::types::rec_group::RecGroupMember< + ${concat(Marker_, $rec_group_name)}, + ${ concat($rec_group_name, _sub_rec_group_types) }!( + $typename{$($typeparams)+} + ) + >; // type ${concat($name, CompoundTypeRecGroupDependencies)} = < // << From 6bd35c4b72103a5f130d6043638fc6c5d813dda3 Mon Sep 17 00:00:00 2001 From: pufferfish101007 <50246616+pufferfish101007@users.noreply.github.com> Date: Thu, 24 Sep 2026 15:53:18 +0100 Subject: [PATCH 18/18] ensure that types that look structurally equivalent actually are --- src/wasm/registries/types.rs | 1 + src/wasm/registries/types/dependencies.rs | 1 + src/wasm/registries/types/rec_group.rs | 292 +++++++++++----------- src/wasm/registries/types/registration.rs | 24 +- src/wasm/registries/types/registry.rs | 85 ++++++- src/wasm/registries/types/tyfp.rs | 7 + 6 files changed, 255 insertions(+), 155 deletions(-) diff --git a/src/wasm/registries/types.rs b/src/wasm/registries/types.rs index b4d8b392..89e56d26 100644 --- a/src/wasm/registries/types.rs +++ b/src/wasm/registries/types.rs @@ -8,6 +8,7 @@ mod registration; mod rec_group; mod registry; mod subtypes; +#[macro_use] mod tyfp; pub use rec_group::*; diff --git a/src/wasm/registries/types/dependencies.rs b/src/wasm/registries/types/dependencies.rs index 7e090b2b..85a57858 100644 --- a/src/wasm/registries/types/dependencies.rs +++ b/src/wasm/registries/types/dependencies.rs @@ -9,6 +9,7 @@ use super::registration::{ }; use super::tyfp::List; use crate::prelude::*; +use crate::wasm::registries::types::TRecGroupItem; pub trait HasTypeDependencies { type Dependencies: List; diff --git a/src/wasm/registries/types/rec_group.rs b/src/wasm/registries/types/rec_group.rs index cb8cb4a1..c9492263 100644 --- a/src/wasm/registries/types/rec_group.rs +++ b/src/wasm/registries/types/rec_group.rs @@ -5,9 +5,9 @@ use wasm_encoder::HeapType; use super::TypeRegistry; use super::dependencies::HasTypeDependencies; use super::registration::TRecGroupType; -use super::tyfp::{Bool, Func}; use crate::prelude::*; -use crate::wasm::registries::types::{CompoundType, RegistryItem, TypeRegistryLike}; +use crate::registry::RegistryResult; +use crate::wasm::registries::types::{CompoundType, List, RegistryItem, TypeRegistryLike}; pub struct RecGroupRegistry { pub types: Rc, @@ -19,7 +19,7 @@ pub struct RecGroupRegistry { impl TypeRegistryLike for RecGroupRegistry { fn register(&self, ty: CompoundType) -> HQResult where - N: crate::registry::RegistryResult, + N: RegistryResult, { let idx = if let Some(idx) = self .types @@ -58,143 +58,27 @@ where impl TRecGroupType for RecGroupMember where T: TRecGroupType, - // I: TypeRegistryLike, { fn rec_group_ty(types: &RecGroupRegistry) -> HQResult { T::rec_group_ty(types) } } -#[macro_export] -macro_rules! rec_group { - ( - $rec_group_name:ident { - $($name:ident = $typename:ident{$($typeparams:tt)+};)+ - } - ) => { - macro_rules! ${ concat($rec_group_name, _sub_rec_group_types) } { - ( - ${concat($rec_group_name, _sub_rec_group_types)}!($$($$macro_args:tt)+) - ) => { - ${concat($rec_group_name, _sub_rec_group_types)}!($$($$macro_args)+) - }; - ( - $$ty:ident{$$({$$($$params:tt)+}),+} - ) => { - $$ty< - $$( - ${concat($rec_group_name, _sub_rec_group_types)}!( - $$($$params)+ - ) - ),+ - > - }; - $( - ($name) => { - TRecGroupItem<${ index() }> - }; - )+ - ($$ty:ident) => { - $$ty - }; - (()) => {()}; - ( - ({$$($$first:tt)+},) - ) => { - ( - ${concat($rec_group_name, _sub_rec_group_types)}!( - $$($$first)+ - ), - () - ) - }; - ( - ({$$($$first:tt)+}, $$({$$($$rest:tt)+}),+ $$(,)?) - ) => { - ( - ${concat($rec_group_name, _sub_rec_group_types)}!( - $$($$first)+ - ), - ${concat($rec_group_name, _sub_rec_group_types)}!( - ($$({$$($$rest)+},)+) - ) - ) - }; - } +pub trait RecGroupMarker { + const NAME: &str; - fn ${concat($rec_group_name, _dummy_rec_group)}() -> Rc { - Rc::new(RecGroup { - name: stringify!($rec_group_name).into(), - types: vec![] - }) - } + type Types: List; +} - fn ${ concat($rec_group_name, _register_rec_group) }(types: &Rc) -> HQResult<()> { - use $crate::wasm::registries::types::dependencies::*; - use $crate::wasm::registries::types::rec_group::RecGroupRegistry; - // let rec_group_types = ${concat($rec_group_name, _construct_rec_group)}(); - if types.registry().borrow().contains_key(&RegistryItem::RecGroupItem(${concat($rec_group_name, _dummy_rec_group)}(), 0)) { - return Ok(()); - } - $( - <$name as HasTypeDependencies>::Dependencies::register_each(types)?; - )+ - // for i in 0u32..(rec_group_types.types.len() as u32) { - // types.register_default::(RegistryItem::RecGroupItem(Rc::clone(&rec_group_types), i))?; - // } - let start_index = types.registry().borrow().len() as u32; - let rec_group_info = RecGroupRegistry { - types: Rc::clone(types), - rec_group_start: start_index, - main_rec_types_num: ${count($name)}, - rec_type_deps: RefCell::new(vec![]), - }; - let mut compound_types: Vec = vec![]; - $( - compound_types.push($name::rec_group_ty(&rec_group_info)?); - )+ - compound_types.extend(rec_group_info.rec_type_deps.take()); - let num_types = compound_types.len() as u32; - let rec_group = Rc::new(RecGroup { - name: stringify!($rec_group_name).into(), - types: compound_types, - }); - for i in 0..num_types { - types.register_default::(RegistryItem::RecGroupItem( - Rc::clone(&rec_group), - i - ))?; - } - Ok(()) - } +pub trait IsRecGroupMember { + type Marker: RecGroupMarker; +} - #[expect(non_camel_case_types, reason = "name given in snake_case")] - pub struct ${concat(Marker_, $rec_group_name)}; - - $( - pub type $name = $crate::wasm::registries::types::rec_group::RecGroupMember< - ${concat(Marker_, $rec_group_name)}, - ${ concat($rec_group_name, _sub_rec_group_types) }!( - $typename{$($typeparams)+} - ) - >; - - // type ${concat($name, CompoundTypeRecGroupDependencies)} = < - // << - // $name as $crate::wasm::registries::types::dependencies::HasTypeDependencies - // >::RecGroupDependencies as List>::Tail - // as $crate::wasm::registries::types::tyfp::Filter<$crate::wasm::registries::types::rec_group::HasCompoundTypeRegistration> - // >::Filtered; - - impl TRecGroupType> for $name { - fn rec_group_ty(types: &Rc) -> HQResult { - ${ concat($rec_group_name, _register_rec_group) }(types)?; - let rec_group_types = ${concat($rec_group_name, _dummy_rec_group)}(); - types.register_default(RegistryItem::RecGroupItem(rec_group_types, ${index()})) - } - } - )+ - } +impl IsRecGroupMember for RecGroupMember +where + Marker: RecGroupMarker, +{ + type Marker = Marker; } pub struct TRecGroupItem; @@ -210,20 +94,140 @@ impl TRecGroupType for TRecGroupItem = CompoundTypeRegistrationTester; -} +#[macro_export] +macro_rules! rec_group { + ( + $rec_group_name:ident { + $($name:ident = $typename:ident{$($typeparams:tt)+};)+ + } + ) => { + mod $rec_group_name { + use $crate::wasm::registries::types::*; + use $crate::wasm::registries::types::dependencies::HasTypeDependencies; -pub struct CompoundTypeRegistrationTester(PhantomData); + macro_rules! sub_rec_group_types { + ( + sub_rec_group_types!($$($$macro_args:tt)+) + ) => { + sub_rec_group_types!($$($$macro_args)+) + }; + ( + $$ty:ident{$$({$$($$params:tt)+}),+} + ) => { + $$ty< + $$( + sub_rec_group_types!( + $$($$params)+ + ) + ),+ + > + }; + $( + ($name) => { + TRecGroupItem<${ index() }> + }; + )+ + ($$ty:ident) => { + $$ty + }; + (()) => {()}; + ( + ({$$($$first:tt)+},) + ) => { + ( + sub_rec_group_types!( + $$($$first)+ + ), + () + ) + }; + ( + ({$$($$first:tt)+}, $$({$$($$rest:tt)+}),+ $$(,)?) + ) => { + ( + sub_rec_group_types!( + $$($$first)+ + ), + sub_rec_group_types!( + ($$({$$($$rest)+},)+) + ) + ) + }; + } -impl Bool for CompoundTypeRegistrationTester { - default const BOOL: bool = false; -} + fn dummy_rec_group() -> Rc { + Rc::new(RecGroup { + name: stringify!($rec_group_name).into(), + types: vec![] + }) + } -impl Bool for CompoundTypeRegistrationTester<(HeadT, Head)> -where - Head: TRecGroupType, -{ - const BOOL: bool = true; + fn register_rec_group(types: &Rc) -> HQResult<()> { + if types.registry().borrow().contains_key(&RegistryItem::RecGroupItem(dummy_rec_group(), 0)) { + return Ok(()); + } + $( + <$name as HasTypeDependencies>::Dependencies::register_each(types)?; + )+ + let start_index = types.registry().borrow().len() as u32; + let rec_group_info = RecGroupRegistry { + types: Rc::clone(types), + rec_group_start: start_index, + main_rec_types_num: ${count($name)}, + rec_type_deps: RefCell::new(vec![]), + }; + let mut compound_types: Vec = vec![]; + $( + compound_types.push($name::rec_group_ty(&rec_group_info)?); + )+ + compound_types.extend(rec_group_info.rec_type_deps.take()); + let num_types = compound_types.len() as u32; + let rec_group = Rc::new(RecGroup { + name: stringify!($rec_group_name).into(), + types: compound_types, + }); + for i in 0..num_types { + types.register_default::(RegistryItem::RecGroupItem( + Rc::clone(&rec_group), + i + ))?; + } + Ok(()) + } + + pub struct Marker; + + impl RecGroupMarker for Marker { + const NAME: &str = stringify!($rec_group_name); + + type Types = ty_list!($($name),+); + } + + $( + pub type $name = RecGroupMember< + Marker, + sub_rec_group_types!( + $typename{$($typeparams)+} + ) + >; + + // type ${concat($name, CompoundTypeRecGroupDependencies)} = < + // << + // $name as $crate::wasm::registries::types::dependencies::HasTypeDependencies + // >::RecGroupDependencies as List>::Tail + // as $crate::wasm::registries::types::tyfp::Filter<$crate::wasm::registries::types::rec_group::HasCompoundTypeRegistration> + // >::Filtered; + + impl TRecGroupType> for $name { + fn rec_group_ty(types: &Rc) -> HQResult { + register_rec_group(types)?; + let rec_group_types = dummy_rec_group(); + types.register_default(RegistryItem::RecGroupItem(rec_group_types, ${index()})) + } + } + )+ + } + + pub use $rec_group_name::{$($name),+}; + } } diff --git a/src/wasm/registries/types/registration.rs b/src/wasm/registries/types/registration.rs index a4a17e10..2cbc5000 100644 --- a/src/wasm/registries/types/registration.rs +++ b/src/wasm/registries/types/registration.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use wasm_encoder::{AbstractHeapType, FieldType, HeapType, RefType, StorageType, ValType}; use super::tyfp::List; -use super::{CompoundType, RegistryItem, TypeRegistry}; +use super::{CompoundType, TypeRegistry}; use crate::prelude::*; use crate::registry::{CompTimeRegistrand, RegistryResult}; @@ -18,7 +18,7 @@ impl TypeRegistryLike for Rc { where N: RegistryResult, { - self.register_default(RegistryItem::Type(ty)) + self.register_compound_type(ty) } } @@ -107,14 +107,22 @@ where pub struct TStructRef; impl TRecGroupType for TStructRef { fn rec_group_ty(_types: &I) -> HQResult { - panic!("this shouldn't be called ever!!! evil!!!") - } -} -impl TRecGroupType for TStructRef { - fn rec_group_ty(_types: &I) -> HQResult { - panic!("this shouldn't be called ever!!! evil!!!") + // generic in `T` to make const-evaluation lazy + // so that the panic is only reached if the function is used + #[expect(clippy::extra_unused_type_parameters, reason = "explained above")] + const fn error() { + const { + panic!( + "tried to register `TStructRef` as a `CompoundType`! + this implementation exists only to satisfy the trait solver.", + ) + } + } + error::<()>(); + unreachable!(); } } + impl TRecGroupType for TStructRef { fn rec_group_ty(_types: &I) -> HQResult { Ok(HeapType::Abstract { diff --git a/src/wasm/registries/types/registry.rs b/src/wasm/registries/types/registry.rs index 16ace4a3..a3e3e3fb 100644 --- a/src/wasm/registries/types/registry.rs +++ b/src/wasm/registries/types/registry.rs @@ -39,28 +39,107 @@ pub enum RegistryItem { RecGroupItem(Rc, u32), } +#[must_use] +pub const fn immediate_val_dep(val: &ValType) -> Option { + if let ValType::Ref(RefType { + heap_type: HeapType::Concrete(conc), + .. + }) = val + { + Some(*conc) + } else { + None + } +} + +const fn immediate_field_dep(field: &StorageType) -> Option { + match field { + StorageType::Val(val) => immediate_val_dep(val), + StorageType::I16 | StorageType::I8 => None, + } +} + +fn immediate_deps(ty: &CompoundType) -> Vec { + match ty { + CompoundType::Array(field, _) => immediate_field_dep(field).into_iter().collect(), + CompoundType::Struct(fields) => fields + .iter() + .map(|field| &field.element_type) + .filter_map(immediate_field_dep) + .collect(), + CompoundType::Function(params, results) => params + .iter() + .chain(results) + .filter_map(immediate_val_dep) + .collect(), + } +} + +fn extract_rec_group(item: RegistryItem) -> Option> { + match item { + RegistryItem::RecGroupItem(rec_group, _) => Some(Rc::clone(&rec_group)), + RegistryItem::Type(_) => None, + } +} + +fn find_compound_type_in_rec_group( + compound_type: &CompoundType, + rec_group: &Rc, +) -> Option { + rec_group + .types + .iter() + .find_position(|other| compound_type == *other) + .map(|(index, _)| index as u32) +} + pub type TypeRegistry = SetRegistry; impl TypeRegistry { + pub fn register_compound_type(&self, compound_type: CompoundType) -> HQResult + where + N: RegistryResult, + { + let equivalent_in_rec_group = immediate_deps(&compound_type) + .into_iter() + .filter_map(|index| { + self.registry() + .borrow() + .get_index(index as usize) + .map(|(item, ())| item) + .cloned() + }) + .filter_map(extract_rec_group) + .find_map(|rec_group| { + find_compound_type_in_rec_group(&compound_type, &rec_group) + .map(|found| (rec_group, found)) + }); + if let Some((rec_group, found_index)) = equivalent_in_rec_group { + self.register_default(RegistryItem::RecGroupItem(rec_group, found_index)) + } else { + self.register_default(RegistryItem::Type(compound_type)) + } + } + pub fn function(&self, params: Vec, returns: Vec) -> HQResult where N: RegistryResult, { - self.register_default(RegistryItem::Type(CompoundType::Function(params, returns))) + self.register_compound_type(CompoundType::Function(params, returns)) } pub fn array(&self, elem_type: StorageType, mutable: bool) -> HQResult where N: RegistryResult, { - self.register_default(RegistryItem::Type(CompoundType::Array(elem_type, mutable))) + self.register_compound_type(CompoundType::Array(elem_type, mutable)) } pub fn struct_(&self, fields: Vec) -> HQResult where N: RegistryResult, { - self.register_default(RegistryItem::Type(CompoundType::Struct(fields))) + self.register_compound_type(CompoundType::Struct(fields)) } pub const STRUCT_REF: ValType = ValType::Ref(RefType { diff --git a/src/wasm/registries/types/tyfp.rs b/src/wasm/registries/types/tyfp.rs index d70b0d25..30e20f0f 100644 --- a/src/wasm/registries/types/tyfp.rs +++ b/src/wasm/registries/types/tyfp.rs @@ -1,5 +1,12 @@ //! Functional programming in the type system. Or something like that. +#[macro_export] +macro_rules! ty_list { + ($first:ty, $($rest:ty),*) => {($first, ty_list!($($rest),*))}; + ($first:ty) => {($first, ())}; + () => {()}; +} + pub trait List { type Head; type Tail: List;