Skip to content

Initial fixed size list implementation #1277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
479 changes: 393 additions & 86 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ prettyplease = "0.2.20"
syn = { version = "2.0.89", features = ["printing"] }
futures = "0.3.31"

wat = "1.229.0"
wasmparser = "0.229.0"
wasm-encoder = "0.229.0"
wasm-metadata = { version = "0.229.0", default-features = false }
wit-parser = "0.229.0"
wit-component = "0.229.0"
wat = { git = "https://github.com/cpetig/wasm-tools", branch = "fixed-length-list" }
wasmparser = { git = "https://github.com/cpetig/wasm-tools", branch = "fixed-length-list" }
wasm-encoder = { git = "https://github.com/cpetig/wasm-tools", branch = "fixed-length-list" }
wasm-metadata = { git = "https://github.com/cpetig/wasm-tools", branch = "fixed-length-list", default-features = false }
wit-parser = { git = "https://github.com/cpetig/wasm-tools", branch = "fixed-length-list" }
wit-component = { git = "https://github.com/cpetig/wasm-tools", branch = "fixed-length-list" }

wit-bindgen-core = { path = 'crates/core', version = '0.41.0' }
wit-bindgen-c = { path = 'crates/c', version = '0.41.0' }
Expand Down
16 changes: 16 additions & 0 deletions crates/c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ fn is_prim_type_id(resolve: &Resolve, id: TypeId) -> bool {
| TypeDefKind::Future(_)
| TypeDefKind::Stream(_)
| TypeDefKind::Unknown => false,
TypeDefKind::FixedSizeList(_, _) => todo!(),
}
}

Expand Down Expand Up @@ -794,6 +795,7 @@ pub fn push_ty_name(resolve: &Resolve, ty: &Type, src: &mut String) {
push_ty_name(resolve, &Type::Id(*resource), src);
}
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(_, _) => todo!(),
}
}
}
Expand Down Expand Up @@ -1004,6 +1006,7 @@ impl Return {
TypeDefKind::Stream(_) => todo!("return_single for stream"),
TypeDefKind::Resource => todo!("return_single for resource"),
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(_, _) => todo!(),
}

self.retptrs.push(*orig_ty);
Expand Down Expand Up @@ -1454,6 +1457,16 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a>
fn anonymous_type_type(&mut self, _id: TypeId, _ty: &Type, _docs: &Docs) {
todo!("print_anonymous_type for type");
}

fn anonymous_type_fixed_size_list(
&mut self,
_id: TypeId,
_ty: &Type,
_size: u32,
_docs: &Docs,
) {
todo!("print_anonymous_type for fixed size list");
}
}

pub enum CTypeNameInfo<'a> {
Expand Down Expand Up @@ -1630,6 +1643,7 @@ impl InterfaceGenerator<'_> {
self.free(&Type::Id(*id), "*ptr");
}
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(_, _) => todo!(),
}
if c_helpers_body_start == self.src.c_helpers.len() {
self.src.c_helpers.as_mut_string().truncate(c_helpers_start);
Expand Down Expand Up @@ -2101,6 +2115,7 @@ impl InterfaceGenerator<'_> {
TypeDefKind::Type(ty) => self.contains_droppable_borrow(ty),

TypeDefKind::Unknown => false,
TypeDefKind::FixedSizeList(_, _) => todo!(),
}
} else {
false
Expand Down Expand Up @@ -3182,6 +3197,7 @@ pub fn is_arg_by_pointer(resolve: &Resolve, ty: &Type) -> bool {
TypeDefKind::Stream(_) => todo!("is_arg_by_pointer for stream"),
TypeDefKind::Resource => todo!("is_arg_by_pointer for resource"),
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(_, _) => todo!(),
},
Type::String => true,
_ => false,
Expand Down
86 changes: 86 additions & 0 deletions crates/core/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,28 @@ def_instruction! {
ty: TypeId,
} : [2] => [1],

/// Pops all fields for a fixed list off the stack and then composes them
/// into an array.
FixedSizeListLift {
element: &'a Type,
size: u32,
id: TypeId,
} : [*size as usize] => [1],

/// Pops an array off the stack, decomposes the elements and then pushes them onto the stack.
FixedSizeListLower {
element: &'a Type,
size: u32,
id: TypeId,
} : [1] => [*size as usize],
Comment on lines +310 to +323
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this I'll echo some of my thoughts on the sibling PRs: I think we'll want to have this with a different shape where the size of the list isn't affecting the O(...) processing here. For example this is pushing/popping the list items from the operand stack of the ABI code, but I think we're going to want something different more akin to how dynamically sized lists work to avoid generating an exponential amount of code in the code generators


/// Pops an array and an address off the stack, passes each element to a block storing it
FixedSizeListLowerBlock {
element: &'a Type,
size: u32,
id: TypeId,
} : [2] => [0],

/// Pushes an operand onto the stack representing the list item from
/// each iteration of the list.
///
Expand Down Expand Up @@ -811,6 +833,7 @@ fn needs_post_return(resolve: &Resolve, ty: &Type) -> bool {
TypeDefKind::Flags(_) | TypeDefKind::Enum(_) => false,
TypeDefKind::Future(_) | TypeDefKind::Stream(_) => false,
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(_, _) => false,
},

Type::Bool
Expand Down Expand Up @@ -1355,6 +1378,21 @@ impl<'a, B: Bindgen> Generator<'a, B> {
});
}
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(ty, size) => {
self.emit(&FixedSizeListLower {
element: ty,
size: *size,
id,
});
let mut values = self
.stack
.drain(self.stack.len() - (*size as usize)..)
.collect::<Vec<_>>();
for value in values.drain(..) {
self.stack.push(value);
self.lower(ty);
}
}
},
}
}
Expand Down Expand Up @@ -1548,6 +1586,25 @@ impl<'a, B: Bindgen> Generator<'a, B> {
});
}
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(ty, size) => {
let mut temp = Vec::new();
self.resolve.push_flat(&Type::Id(id), &mut temp);
let mut args = self
.stack
.drain(self.stack.len() - temp.len()..)
.collect::<Vec<_>>();
for _ in 0..*size {
temp.truncate(0);
self.resolve.push_flat(ty, &mut temp);
self.stack.extend(args.drain(..temp.len()));
self.lift(ty);
}
self.emit(&FixedSizeListLift {
element: ty,
size: *size,
id,
});
}
},
}
}
Expand Down Expand Up @@ -1708,6 +1765,21 @@ impl<'a, B: Bindgen> Generator<'a, B> {
}

TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(element, size) => {
// resembles write_list_to_memory
self.push_block();
self.emit(&IterElem { element });
self.emit(&IterBasePointer);
let elem_addr = self.stack.pop().unwrap();
self.write_to_memory(element, elem_addr, Default::default());
self.finish_block(0);
self.stack.push(addr);
self.emit(&FixedSizeListLowerBlock {
element,
size: *size,
id,
});
}
},
}
}
Expand Down Expand Up @@ -1894,6 +1966,19 @@ impl<'a, B: Bindgen> Generator<'a, B> {
}

TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(ty, size) => {
let increment = self.bindgen.sizes().size(ty);
let mut position = offset;
for _ in 0..*size {
self.read_from_memory(ty, addr.clone(), position);
position = position + increment;
}
self.emit(&FixedSizeListLift {
element: ty,
size: *size,
id,
});
}
},
}
}
Expand Down Expand Up @@ -2076,6 +2161,7 @@ impl<'a, B: Bindgen> Generator<'a, B> {
TypeDefKind::Future(_) => todo!("read future from memory"),
TypeDefKind::Stream(_) => todo!("read stream from memory"),
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(_, _) => {}
},
}
}
Expand Down
5 changes: 5 additions & 0 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ pub trait InterfaceGenerator<'a> {
TypeDefKind::Stream(t) => self.type_stream(id, name, t, &ty.docs),
TypeDefKind::Handle(_) => panic!("handle types do not require definition"),
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(_, _) => todo!(),
}
}
}
Expand All @@ -192,6 +193,7 @@ pub trait AnonymousTypeGenerator<'a> {
fn anonymous_type_option(&mut self, id: TypeId, ty: &Type, docs: &Docs);
fn anonymous_type_result(&mut self, id: TypeId, ty: &Result_, docs: &Docs);
fn anonymous_type_list(&mut self, id: TypeId, ty: &Type, docs: &Docs);
fn anonymous_type_fixed_size_list(&mut self, id: TypeId, ty: &Type, size: u32, docs: &Docs);
fn anonymous_type_future(&mut self, id: TypeId, ty: &Option<Type>, docs: &Docs);
fn anonymous_type_stream(&mut self, id: TypeId, ty: &Option<Type>, docs: &Docs);
fn anonymous_type_type(&mut self, id: TypeId, ty: &Type, docs: &Docs);
Expand All @@ -215,6 +217,9 @@ pub trait AnonymousTypeGenerator<'a> {
TypeDefKind::Stream(s) => self.anonymous_type_stream(id, s, &ty.docs),
TypeDefKind::Handle(handle) => self.anonymous_type_handle(id, handle, &ty.docs),
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(t, size) => {
self.anonymous_type_fixed_size_list(id, t, *size, &ty.docs)
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ impl Types {
info.has_own_handle = true;
}
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(ty, _) => {
info = self.type_info(resolve, ty);
}
}
let prev = self.type_info.insert(ty, info);
assert!(prev.is_none());
Expand Down
3 changes: 3 additions & 0 deletions crates/csharp/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,9 @@ impl Bindgen for FunctionBindgen<'_, '_> {
| Instruction::StreamLift { .. }
| Instruction::ErrorContextLower { .. }
| Instruction::ErrorContextLift { .. } => todo!(),
Instruction::FixedSizeListLift { .. } => todo!(),
Instruction::FixedSizeListLower { .. } => todo!(),
Instruction::FixedSizeListLowerBlock { .. } => todo!(),
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/markdown/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ impl InterfaceGenerator<'_> {
self.push_str(">");
}
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedSizeList(_, _) => todo!(),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/moonbit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2667,6 +2667,9 @@ impl Bindgen for FunctionBindgen<'_, '_> {
| Instruction::StreamLift { .. }
| Instruction::ErrorContextLower { .. }
| Instruction::ErrorContextLift { .. } => todo!(),
Instruction::FixedSizeListLift { .. } => todo!(),
Instruction::FixedSizeListLower { .. } => todo!(),
Instruction::FixedSizeListLowerBlock { .. } => todo!(),
}
}

Expand Down
42 changes: 42 additions & 0 deletions crates/rust/src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,24 @@ impl Bindgen for FunctionBindgen<'_, '_> {
results.push(len);
}

Instruction::FixedSizeListLowerBlock {
element,
size: _,
id: _,
} => {
let body = self.blocks.pop().unwrap();
let vec = operands[0].clone();
let target = operands[1].clone();
let size = self.r#gen.sizes.size(element);
self.push_str(&format!("for (i, e) in {vec}.into_iter().enumerate() {{\n",));
self.push_str(&format!(
"let base = {target}.add(i * {});\n",
size.format(POINTER_SIZE_EXPRESSION)
));
self.push_str(&body);
self.push_str("\n}\n");
}

Instruction::ListLift { element, .. } => {
let body = self.blocks.pop().unwrap();
let tmp = self.tmp();
Expand Down Expand Up @@ -1202,6 +1220,30 @@ impl Bindgen for FunctionBindgen<'_, '_> {
align = align.format(POINTER_SIZE_EXPRESSION)
));
}
Instruction::FixedSizeListLift {
element: _,
size,
id: _,
} => {
let tmp = self.tmp();
let result = format!("result{tmp}");
self.push_str(&format!("let {result} = [",));
for a in operands.drain(0..(*size as usize)) {
self.push_str(&a);
self.push_str(", ");
}
self.push_str("];\n");
results.push(result);
}
Instruction::FixedSizeListLower {
element: _,
size,
id: _,
} => {
for i in 0..(*size as usize) {
results.push(format!("{}[{i}]", operands[0]));
}
}
}
}
}
13 changes: 13 additions & 0 deletions crates/rust/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2932,4 +2932,17 @@ impl<'a, 'b> wit_bindgen_core::AnonymousTypeGenerator<'a> for AnonTypeGenerator<
self.interface.print_optional_ty(ty.as_ref(), mode);
self.interface.push_str(">");
}

fn anonymous_type_fixed_size_list(&mut self, _id: TypeId, ty: &Type, size: u32, _docs: &Docs) {
self.interface.push_str("[");
self.interface.print_ty(
ty,
TypeMode {
lifetime: None,
lists_borrowed: false,
style: TypeOwnershipStyle::Owned,
},
);
self.interface.push_str(&format!("; {size}]"));
}
}
6 changes: 3 additions & 3 deletions crates/test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ regex = "1.11.1"
serde = { workspace = true }
toml = "0.8.20"
wasi-preview1-component-adapter-provider = "30.0.2"
wac-parser = "0.6.1"
wac-types = "0.6.1"
wac-graph = "0.6.1"
wac-parser = { git = "https://github.com/cpetig/wac", branch = "fixed-size-lists" }
wac-types = { git = "https://github.com/cpetig/wac", branch = "fixed-size-lists" }
wac-graph = { git = "https://github.com/cpetig/wac", branch = "fixed-size-lists" }
indexmap = { workspace = true }
wasm-encoder = { workspace = true }
wasmparser = { workspace = true, features = ["features"] }
Expand Down
Loading
Loading