Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ae35a3d
work towards different thread tables for each target
pufferfish101007 Aug 11, 2026
18dfea4
progress?
pufferfish101007 Aug 14, 2026
0c0d9d9
start working on types in the type system
pufferfish101007 Aug 16, 2026
09d1df6
more type system types and start implementing dyn_array funcs
pufferfish101007 Aug 19, 2026
b2faa61
rewrite `SpawnNewThreadInStack` with new dyn arrays + threadss array …
pufferfish101007 Aug 19, 2026
435604e
finish thread spawning routines, start cleaning up other references
pufferfish101007 Aug 20, 2026
02599e9
rewrite more functions and instructions to use new thread layout
pufferfish101007 Aug 23, 2026
30ec873
remove a layer of indirection in thread referencing
pufferfish101007 Aug 23, 2026
c5c2071
finally a typesafe representation of mutually recursive types?
pufferfish101007 Sep 4, 2026
349d506
get rec types to compile; adapt yield to new type layout
pufferfish101007 Sep 10, 2026
a5dac89
static functions declare their own overrides; encode rec groups in ac…
pufferfish101007 Sep 11, 2026
ff6b823
fix static function dependency resolution
pufferfish101007 Sep 11, 2026
e96f04b
fixup some mistyped functions (incl casts between matching types)
pufferfish101007 Sep 11, 2026
b3bb95f
more typecasting fixes
pufferfish101007 Sep 12, 2026
e348739
...and some more typecasting fixes
pufferfish101007 Sep 12, 2026
2bfbde4
fix broadcast & wait
pufferfish101007 Sep 13, 2026
7bbc9da
distinguish same-shaped types in distinct rec groups
pufferfish101007 Sep 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.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"] }
Expand All @@ -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 = { 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" }
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2026-08-07"
channel = "nightly-2026-09-10"
targets = [ "wasm32-unknown-unknown" ]
2 changes: 2 additions & 0 deletions src/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ mod pen;
mod procedures;
mod sensing;

pub use event::poll_waiting_threads::{TPollStruct, TWaitingThreadArray};

#[macro_use]
mod tests;

Expand Down
71 changes: 54 additions & 17 deletions src/instructions/control/stop_all.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,67 @@
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::registries::functions::static_functions::DynArrayClear;
use crate::wasm::registries::types::{
TNullable, TStackArray, TTargetThreadArray, TTargetThreadsStruct, TThreadArray, TType,

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Lint (clippy)

unused import: `TThreadArray`

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Run rust unit tests

unused import: `TThreadArray`

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Run rust unit tests

unused import: `TThreadArray`

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Lint (clippy)

unused import: `TThreadArray`

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Build check

unused import: `TThreadArray`

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Build check

unused import: `TThreadArray`

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Build WASM & website

unused import: `TThreadArray`

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Run integration tests

unused import: `TThreadArray`

Check failure on line 7 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Run integration tests

unused import: `TThreadArray`
};

pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult<Vec<InternalInstruction>> {
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::<ThreadsTable, _>()?;
let thread_struct_type = func.registries().types().thread_struct_type()?;

Ok(wasm![
fn clear_thread(

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Lint (clippy)

function `clear_thread` is never used

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Run rust unit tests

function `clear_thread` is never used

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Run rust unit tests

function `clear_thread` is never used

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Lint (clippy)

function `clear_thread` is never used

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Build check

function `clear_thread` is never used

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Build check

function `clear_thread` is never used

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Build WASM & website

function `clear_thread` is never used

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Run integration tests

function `clear_thread` is never used

Check failure on line 10 in src/instructions/control/stop_all.rs

View workflow job for this annotation

GitHub Actions / Run integration tests

function `clear_thread` is never used
threads_count: u32,
threads_table: u32,
thread_struct_type: u32,
) -> Vec<InternalInstruction> {
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<Vec<InternalInstruction>> {
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_targets = 1 + func.costume_names().len() as i32;
let array_type = func
.registries()
.types()
.register_comp::<TTargetThreadArray, _>()?;
let dyn_array_clear = func
.registries()
.static_functions()
.register::<DynArrayClear<TNullable<TStackArray>>, _>()?;

Ok(wasm![
I32Const(0),
#LazyGlobalSet(total_threads_count),
I32Const(0),
LocalSet(local_target_counter),
Loop(wasm_encoder::BlockType::Empty),
#LazyGlobalGet(threadss_global),
LocalGet(local_target_counter),
ArrayGet(array_type),
StructGet {
struct_type_index: TTargetThreadsStruct::ty(func.registries().types())?,
field_index: 1,
},
#StaticFunctionCall(dyn_array_clear),
LocalGet(local_target_counter),
I32Const(1),
I32Add,
LocalTee(local_target_counter),
I32Const(num_targets),
I32LtS,
BrIf(0),
End,
])
}

Expand Down
13 changes: 11 additions & 2 deletions src/instructions/control/wait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::super::prelude::*;
use crate::instructions_test;
use crate::ir::StepIndex;
use crate::wasm::registries::functions::static_functions::SpawnThreadInStack;
use crate::wasm::registries::types::{TStepFunc, TType};
use crate::wasm::{GlobalExportable, GlobalMutable, StepFunc};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -62,6 +63,8 @@ pub fn wasm(
),
)?;

let step_func_ty = TStepFunc::ty(func.registries().types())?;

Ok(
if t1.contains(IrType::FloatNeg) {
wasm![
Expand All @@ -79,9 +82,11 @@ pub fn wasm(
LocalSet(struct_local),
LocalGet((func.params().len() - 2).try_into().map_err(|_| make_hq_bug!("local index out of bounds"))?),
#LazyStepRef(*poll_step),
RefCastNonNull(step_func_ty),
LocalGet(struct_local),
RefCastNullable(HeapType::Abstract { shared: false, ty: AbstractHeapType::Struct }),
#LazyStepRef(*next_step),
RefCastNonNull(step_func_ty),
#StaticFunctionCall(spawn_thread_in_stack_func),
]
).collect()
Expand Down Expand Up @@ -111,6 +116,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]
Expand All @@ -122,13 +128,16 @@ mod test {
pub fn make_fields() -> 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([
<TNonNullable<TStackArray>>::ty(wasm_proj.registries().types()).unwrap(),
TypeRegistry::STRUCT_REF,
]),
Box::from([]),
wasm_proj.registries(),
flags,
Expand Down
21 changes: 10 additions & 11 deletions src/instructions/event/broadcast_and_wait.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -35,14 +35,9 @@ pub fn wasm(
next_step,
}: &Fields,
) -> HQResult<Vec<InternalInstruction>> {
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(<TNonNullable<TWaitingThreadArray>>::ty(
func.registries().types(),
)?)?;
func.free_local(arr_local)?;

Ok(wasm![
Expand Down Expand Up @@ -74,6 +69,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]
Expand All @@ -92,7 +88,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([
<TNonNullable<TStackArray>>::ty(wasm_proj.registries().types()).unwrap(),
TypeRegistry::STRUCT_REF,
]),
Box::from([]),
wasm_proj.registries(),
flags,
Expand Down
103 changes: 54 additions & 49 deletions src/instructions/event/poll_waiting_threads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +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, ThreadsTable};
use crate::wasm::StepFunc;
use crate::wasm::registries::functions::static_functions::DynArrayLen;
use crate::wasm::registries::types::{
TArray, TConstField, TMutField, TNonNullable, TNullable, TStackArray, TStackStruct, TStruct,
TType,
};

pub type TWaitingThreadArray = TArray<TMutField<TNullable<TStackArray>>>;
pub type TPollStruct = TStruct<(TConstField<TNonNullable<TWaitingThreadArray>>, ())>;

pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult<Vec<InternalInstruction>> {
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::<TWaitingThreadArray, _>()?;
let poll_struct_type = types.register_comp::<TPollStruct, _>()?;

let arr_local = func.local(<TNonNullable<TWaitingThreadArray>>::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(<TNullable<TStackStruct>>::ty(&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.registries().tables().register::<ThreadsTable, _>()?;
let dyn_array_len = func
.registries()
.static_functions()
.register::<DynArrayLen<TNullable<TStackArray>>, _>()?;

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::ty(&types)?),
StructGet {
struct_type_index: poll_struct_type,
field_index: 0
field_index: 0,
},
LocalTee(arr_local),
ArrayLen,
Expand All @@ -51,35 +54,37 @@ pub fn wasm(func: &StepFunc, _inputs: Rc<[IrType]>) -> HQResult<Vec<InternalInst
LocalSet(i_local),
I32Const(0),
LocalSet(wait_local),

Block(WasmBlockType::Empty),
Loop(WasmBlockType::Empty),
LocalGet(i_local),
I32Const(1),
I32Add,
LocalTee(i_local),
LocalGet(arr_len_local),
I32Eq,
BrIf(1),
LocalGet(i_local),
I32Const(0),
I32LtS,
BrIf(0),
Block(WasmBlockType::Empty),
LocalGet(arr_local),
LocalGet(i_local),
ArrayGet(i32_array_type),
TableGet(threads_table),
RefIsNull,
BrIf(0),
I32Const(1),
LocalSet(wait_local),
Br(1),
End,
LocalGet(arr_local),
LocalGet(i_local),
I32Const(-1),
ArraySet(i32_array_type),
Br(0),
LocalGet(i_local),
I32Const(1),
I32Add,
LocalTee(i_local),
LocalGet(arr_len_local),
I32Eq,
BrIf(1),

LocalGet(arr_local),
LocalGet(i_local),
ArrayGet(thread_array_type),
LocalTee(stack_local),
RefIsNull,
BrIf(0),

LocalGet(stack_local),
#StaticFunctionCall(dyn_array_len),
I32Eqz,
If(WasmBlockType::Empty),
LocalGet(arr_local),
LocalGet(i_local),
RefNull(TStackArray::ty(&types)?),
Br(1),
End,

I32Const(1),
LocalSet(wait_local),
Br(1),
End,
End,
LocalGet(wait_local),
Expand Down
Loading
Loading