Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
8 changes: 8 additions & 0 deletions crates/c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,10 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{
todo!("named fixed-length list types are not yet supported in the C backend")
}

fn type_map(&mut self, _id: TypeId, _name: &str, _key: &Type, _value: &Type, _docs: &Docs) {
todo!("map types are not yet supported in the C backend")
}

fn type_future(&mut self, id: TypeId, _name: &str, _ty: &Option<Type>, docs: &Docs) {
self.src.h_defs("\n");
self.docs(docs, SourceType::HDefs);
Expand Down Expand Up @@ -1867,6 +1871,10 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a>
) {
todo!("print_anonymous_type for fixed length list");
}

fn anonymous_type_map(&mut self, _id: TypeId, _key: &Type, _value: &Type, _docs: &Docs) {
todo!("anonymous map types are not yet supported in the C backend");
}
}

pub enum CTypeNameInfo<'a> {
Expand Down
105 changes: 98 additions & 7 deletions crates/core/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,28 @@ def_instruction! {
ty: TypeId,
} : [2] => [1],

/// Lowers a map into a canonical pointer/length pair.
///
/// This operation pops a map value from the stack and pushes pointer
/// and length. A block is popped from the block stack to lower one
/// key/value entry into linear memory.
MapLower {
key: &'a Type,
value: &'a Type,
realloc: Option<&'a str>,
} : [1] => [2],

/// Lifts a canonical pointer/length pair into a map.
///
/// This operation consumes pointer and length from the stack. A block
/// is popped from the block stack and must produce key/value for one
/// map entry.
MapLift {
key: &'a Type,
value: &'a Type,
ty: TypeId,
} : [2] => [1],

/// Pops all fields for a fixed list off the stack and then composes them
/// into an array.
FixedLengthListLift {
Expand Down Expand Up @@ -349,6 +371,14 @@ def_instruction! {
/// This is only used inside of blocks related to lowering lists.
IterElem { element: &'a Type } : [0] => [1],

/// Pushes an operand onto the stack representing the current map key
/// for each map iteration.
IterMapKey { key: &'a Type } : [0] => [1],

/// Pushes an operand onto the stack representing the current map value
/// for each map iteration.
IterMapValue { value: &'a Type } : [0] => [1],

/// Pushes an operand onto the stack representing the base pointer of
/// the next element in a list.
///
Expand Down Expand Up @@ -581,6 +611,17 @@ def_instruction! {
element: &'a Type,
} : [2] => [0],

/// Used exclusively for guest-code generation this indicates that a
/// map is being deallocated. The ptr/length are on the stack and are
/// popped off and used to deallocate the map entry buffer.
///
/// This variant also pops a block off the block stack to be used as
/// the body of the deallocation loop over map entries.
GuestDeallocateMap {
key: &'a Type,
value: &'a Type,
} : [2] => [0],

/// Used exclusively for guest-code generation this indicates that
/// a variant is being deallocated. The integer discriminant is popped
/// off the stack as well as `blocks` number of blocks popped from the
Expand Down Expand Up @@ -875,7 +916,7 @@ fn needs_deallocate(resolve: &Resolve, ty: &Type, what: Deallocate) -> bool {
TypeDefKind::Future(_) | TypeDefKind::Stream(_) => what.handles(),
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedLengthList(t, _) => needs_deallocate(resolve, t, what),
TypeDefKind::Map(..) => todo!(),
TypeDefKind::Map(_, _) => true,
},

Type::Bool
Expand Down Expand Up @@ -1618,7 +1659,25 @@ impl<'a, B: Bindgen> Generator<'a, B> {
self.lower(ty);
}
}
TypeDefKind::Map(..) => todo!(),
TypeDefKind::Map(key, value) => {
let realloc = self.list_realloc();
let value_offset = self.bindgen.sizes().field_offsets([key, value])[1].0;
self.push_block();
self.emit(&IterMapKey { key });
self.emit(&IterBasePointer);
let key_addr = self.stack.pop().unwrap();
self.write_to_memory(key, key_addr, Default::default());
self.emit(&IterMapValue { value });
self.emit(&IterBasePointer);
let value_addr = self.stack.pop().unwrap();
self.write_to_memory(value, value_addr, value_offset);
self.finish_block(0);
self.emit(&MapLower {
key,
value,
realloc,
});
}
},
}
}
Expand Down Expand Up @@ -1819,7 +1878,16 @@ impl<'a, B: Bindgen> Generator<'a, B> {
id,
});
}
TypeDefKind::Map(..) => todo!(),
TypeDefKind::Map(key, value) => {
let value_offset = self.bindgen.sizes().field_offsets([key, value])[1].0;
self.push_block();
self.emit(&IterBasePointer);
let entry_addr = self.stack.pop().unwrap();
self.read_from_memory(key, entry_addr.clone(), Default::default());
self.read_from_memory(value, entry_addr, value_offset);
self.finish_block(2);
self.emit(&MapLift { key, value, ty: id });
}
},
}
}
Expand Down Expand Up @@ -1907,6 +1975,8 @@ impl<'a, B: Bindgen> Generator<'a, B> {
Type::Id(id) => match &self.resolve.types[id].kind {
TypeDefKind::Type(t) => self.write_to_memory(t, addr, offset),
TypeDefKind::List(_) => self.write_list_to_memory(ty, addr, offset),
// Maps have the same linear memory layout as list<tuple<K, V>>.
TypeDefKind::Map(_, _) => self.write_list_to_memory(ty, addr, offset),

TypeDefKind::Future(_) | TypeDefKind::Stream(_) | TypeDefKind::Handle(_) => {
self.lower_and_emit(ty, addr, &I32Store { offset })
Expand Down Expand Up @@ -2016,7 +2086,6 @@ impl<'a, B: Bindgen> Generator<'a, B> {
id,
});
}
TypeDefKind::Map(..) => todo!(),
},
}
}
Expand Down Expand Up @@ -2115,6 +2184,8 @@ impl<'a, B: Bindgen> Generator<'a, B> {
TypeDefKind::Type(t) => self.read_from_memory(t, addr, offset),

TypeDefKind::List(_) => self.read_list_from_memory(ty, addr, offset),
// Maps have the same linear memory layout as list<tuple<K, V>>.
TypeDefKind::Map(_, _) => self.read_list_from_memory(ty, addr, offset),

TypeDefKind::Future(_) | TypeDefKind::Stream(_) | TypeDefKind::Handle(_) => {
self.emit_and_lift(ty, addr, &I32Load { offset })
Expand Down Expand Up @@ -2216,7 +2287,6 @@ impl<'a, B: Bindgen> Generator<'a, B> {
id,
});
}
TypeDefKind::Map(..) => todo!(),
},
}
}
Expand Down Expand Up @@ -2339,6 +2409,18 @@ impl<'a, B: Bindgen> Generator<'a, B> {
self.emit(&Instruction::GuestDeallocateList { element });
}

TypeDefKind::Map(key, value) => {
let value_offset = self.bindgen.sizes().field_offsets([key, value])[1].0;
self.push_block();
self.emit(&IterBasePointer);
let entry_addr = self.stack.pop().unwrap();
self.deallocate_indirect(key, entry_addr.clone(), Default::default(), what);
self.deallocate_indirect(value, entry_addr, value_offset, what);
self.finish_block(0);

self.emit(&Instruction::GuestDeallocateMap { key, value });
}

TypeDefKind::Handle(Handle::Own(_))
| TypeDefKind::Future(_)
| TypeDefKind::Stream(_)
Expand Down Expand Up @@ -2405,7 +2487,6 @@ impl<'a, B: Bindgen> Generator<'a, B> {
TypeDefKind::Unknown => unreachable!(),

TypeDefKind::FixedLengthList(..) => todo!(),
TypeDefKind::Map(..) => todo!(),
},
}
}
Expand Down Expand Up @@ -2464,6 +2545,17 @@ impl<'a, B: Bindgen> Generator<'a, B> {
self.deallocate(ty, what);
}

TypeDefKind::Map(_, _) => {
self.stack.push(addr.clone());
self.emit(&Instruction::PointerLoad { offset });
self.stack.push(addr);
self.emit(&Instruction::LengthLoad {
offset: offset + self.bindgen.sizes().align(ty).into(),
});

self.deallocate(ty, what);
}

TypeDefKind::Handle(Handle::Own(_))
| TypeDefKind::Future(_)
| TypeDefKind::Stream(_)
Expand Down Expand Up @@ -2527,7 +2619,6 @@ impl<'a, B: Bindgen> Generator<'a, B> {
TypeDefKind::Stream(_) => unreachable!(),
TypeDefKind::Unknown => unreachable!(),
TypeDefKind::FixedLengthList(_, _) => {}
TypeDefKind::Map(..) => todo!(),
},
}
}
Expand Down
6 changes: 4 additions & 2 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ pub trait InterfaceGenerator<'a> {
fn type_alias(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs);
fn type_list(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs);
fn type_fixed_length_list(&mut self, id: TypeId, name: &str, ty: &Type, size: u32, docs: &Docs);
fn type_map(&mut self, id: TypeId, name: &str, key: &Type, value: &Type, docs: &Docs);
fn type_builtin(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs);
fn type_future(&mut self, id: TypeId, name: &str, ty: &Option<Type>, docs: &Docs);
fn type_stream(&mut self, id: TypeId, name: &str, ty: &Option<Type>, docs: &Docs);
Expand Down Expand Up @@ -203,7 +204,7 @@ where
TypeDefKind::FixedLengthList(t, size) => {
generator.type_fixed_length_list(id, name, t, *size, &ty.docs)
}
TypeDefKind::Map(..) => todo!(),
TypeDefKind::Map(key, value) => generator.type_map(id, name, key, value, &ty.docs),
TypeDefKind::Unknown => unreachable!(),
}
}
Expand All @@ -217,6 +218,7 @@ pub trait AnonymousTypeGenerator<'a> {
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_length_list(&mut self, id: TypeId, ty: &Type, size: u32, docs: &Docs);
fn anonymous_type_map(&mut self, id: TypeId, key: &Type, value: &Type, 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 @@ -242,7 +244,7 @@ pub trait AnonymousTypeGenerator<'a> {
TypeDefKind::FixedLengthList(t, size) => {
self.anonymous_type_fixed_length_list(id, t, *size, &ty.docs)
}
TypeDefKind::Map(..) => todo!(),
TypeDefKind::Map(key, value) => self.anonymous_type_map(id, key, value, &ty.docs),
TypeDefKind::Unknown => unreachable!(),
}
}
Expand Down
6 changes: 5 additions & 1 deletion crates/core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,11 @@ impl Types {
TypeDefKind::FixedLengthList(ty, _) => {
info = self.type_info(resolve, ty);
}
TypeDefKind::Map(..) => todo!(),
TypeDefKind::Map(key, value) => {
info = self.type_info(resolve, key);
info |= self.type_info(resolve, value);
info.has_list = true;
}
TypeDefKind::Unknown => unreachable!(),
}
let prev = self.type_info.insert(ty, info);
Expand Down
18 changes: 18 additions & 0 deletions crates/cpp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2232,6 +2232,17 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a>
todo!("named fixed-length list types are not yet supported in the C++ backend")
}

fn type_map(
&mut self,
_id: TypeId,
_name: &str,
_key: &wit_bindgen_core::wit_parser::Type,
_value: &wit_bindgen_core::wit_parser::Type,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
todo!("map types are not yet supported in the C++ backend")
}

fn type_builtin(
&mut self,
_id: TypeId,
Expand Down Expand Up @@ -3503,6 +3514,13 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
}
abi::Instruction::AsyncTaskReturn { .. } => todo!(),
abi::Instruction::DropHandle { .. } => todo!(),
abi::Instruction::MapLower { .. }
| abi::Instruction::MapLift { .. }
| abi::Instruction::IterMapKey { .. }
| abi::Instruction::IterMapValue { .. }
| abi::Instruction::GuestDeallocateMap { .. } => {
todo!("map types are not yet supported in this backend")
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions crates/csharp/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,11 @@ impl Bindgen for FunctionBindgen<'_, '_> {
| Instruction::FixedLengthListLower { .. }
| Instruction::FixedLengthListLowerToMemory { .. }
| Instruction::FixedLengthListLiftFromMemory { .. }
| Instruction::MapLower { .. }
| Instruction::MapLift { .. }
| Instruction::IterMapKey { .. }
| Instruction::IterMapValue { .. }
| Instruction::GuestDeallocateMap { .. }
=> {
dbg!(inst);
todo!()
Expand Down
4 changes: 4 additions & 0 deletions crates/csharp/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,10 @@ impl<'a> CoreInterfaceGenerator<'a> for InterfaceGenerator<'a> {
todo!("named fixed-length list types are not yet supported in the C# backend")
}

fn type_map(&mut self, _id: TypeId, _name: &str, _key: &Type, _value: &Type, _docs: &Docs) {
todo!("map types are not yet supported in the C# backend")
}

fn type_builtin(&mut self, _id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) {
unimplemented!();
}
Expand Down
4 changes: 4 additions & 0 deletions crates/go/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2914,6 +2914,10 @@ const (
uwriteln!(self.src, "{docs}type {name} = [{size}]{ty}");
}

fn type_map(&mut self, _id: TypeId, _name: &str, _key: &Type, _value: &Type, _docs: &Docs) {
todo!("map types are not yet supported in the Go backend")
}

fn type_builtin(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
_ = (id, name, ty, docs);
todo!()
Expand Down
7 changes: 7 additions & 0 deletions crates/guest-rust/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ impl Parse for Config {
Opt::Ownership(ownership) => opts.ownership = ownership,
Opt::Skip(list) => opts.skip.extend(list.iter().map(|i| i.value())),
Opt::RuntimePath(path) => opts.runtime_path = Some(path.value()),
Opt::MapType(path) => opts.map_type = Some(path.value()),
Opt::BitflagsPath(path) => opts.bitflags_path = Some(path.value()),
Opt::Stubs => {
opts.stubs = true;
Expand Down Expand Up @@ -304,6 +305,7 @@ mod kw {
syn::custom_keyword!(inline);
syn::custom_keyword!(ownership);
syn::custom_keyword!(runtime_path);
syn::custom_keyword!(map_type);
syn::custom_keyword!(bitflags_path);
syn::custom_keyword!(exports);
syn::custom_keyword!(stubs);
Expand Down Expand Up @@ -383,6 +385,7 @@ enum Opt {
Skip(Vec<syn::LitStr>),
Ownership(Ownership),
RuntimePath(syn::LitStr),
MapType(syn::LitStr),
BitflagsPath(syn::LitStr),
Stubs,
ExportPrefix(syn::LitStr),
Expand Down Expand Up @@ -486,6 +489,10 @@ impl Parse for Opt {
input.parse::<kw::runtime_path>()?;
input.parse::<Token![:]>()?;
Ok(Opt::RuntimePath(input.parse()?))
} else if l.peek(kw::map_type) {
input.parse::<kw::map_type>()?;
input.parse::<Token![:]>()?;
Ok(Opt::MapType(input.parse()?))
} else if l.peek(kw::bitflags_path) {
input.parse::<kw::bitflags_path>()?;
input.parse::<Token![:]>()?;
Expand Down
Loading
Loading