Skip to content

Commit 19a2351

Browse files
authored
Refactor some ABI bits in wit-bindgen-core (#1241)
Pass some variables around instead of storing them on `Generator`, removing the need to synthesize dummy values in a few contexts.
1 parent 33442e3 commit 19a2351

File tree

5 files changed

+62
-68
lines changed

5 files changed

+62
-68
lines changed

crates/c/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,7 @@ impl InterfaceGenerator<'_> {
18771877

18781878
let mut f = FunctionBindgen::new(self, c_sig, &import_name);
18791879
f.params = params;
1880-
abi::post_return(f.gen.resolve, func, &mut f, false);
1880+
abi::post_return(f.gen.resolve, func, &mut f);
18811881
let FunctionBindgen { src, .. } = f;
18821882
self.src.c_fns(&src);
18831883
self.src.c_fns("}\n");

crates/core/src/abi.rs

Lines changed: 58 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ pub fn call(
738738
bindgen: &mut impl Bindgen,
739739
async_: bool,
740740
) {
741-
Generator::new(resolve, variant, lift_lower, bindgen, async_).call(func);
741+
Generator::new(resolve, bindgen).call(func, variant, lift_lower, async_);
742742
}
743743

744744
pub fn lower_to_memory<B: Bindgen>(
@@ -748,14 +748,12 @@ pub fn lower_to_memory<B: Bindgen>(
748748
value: B::Operand,
749749
ty: &Type,
750750
) {
751-
// TODO: refactor so we don't need to pass in a bunch of unused dummy parameters:
752-
let mut generator = Generator::new(
753-
resolve,
754-
AbiVariant::GuestImport,
755-
LiftLower::LowerArgsLiftResults,
756-
bindgen,
757-
true,
758-
);
751+
let mut generator = Generator::new(resolve, bindgen);
752+
// TODO: make this configurable? Right this this function is only called for
753+
// future/stream callbacks so it's appropriate to skip realloc here as it's
754+
// all "lower for wasm import", but this might get reused for something else
755+
// in the future.
756+
generator.realloc = Some(Realloc::None);
759757
generator.stack.push(value);
760758
generator.write_to_memory(ty, address, Default::default());
761759
}
@@ -766,14 +764,7 @@ pub fn lift_from_memory<B: Bindgen>(
766764
address: B::Operand,
767765
ty: &Type,
768766
) -> B::Operand {
769-
// TODO: refactor so we don't need to pass in a bunch of unused dummy parameters:
770-
let mut generator = Generator::new(
771-
resolve,
772-
AbiVariant::GuestImport,
773-
LiftLower::LowerArgsLiftResults,
774-
bindgen,
775-
true,
776-
);
767+
let mut generator = Generator::new(resolve, bindgen);
777768
generator.read_from_memory(ty, address, Default::default());
778769
generator.stack.pop().unwrap()
779770
}
@@ -784,16 +775,10 @@ pub fn lift_from_memory<B: Bindgen>(
784775
/// This is only intended to be used in guest generators for exported
785776
/// functions and will primarily generate `GuestDeallocate*` instructions,
786777
/// plus others used as input to those instructions.
787-
pub fn post_return(resolve: &Resolve, func: &Function, bindgen: &mut impl Bindgen, async_: bool) {
788-
Generator::new(
789-
resolve,
790-
AbiVariant::GuestExport,
791-
LiftLower::LiftArgsLowerResults,
792-
bindgen,
793-
async_,
794-
)
795-
.post_return(func);
778+
pub fn post_return(resolve: &Resolve, func: &Function, bindgen: &mut impl Bindgen) {
779+
Generator::new(resolve, bindgen).post_return(func);
796780
}
781+
797782
/// Returns whether the `Function` specified needs a post-return function to
798783
/// be generated in guest code.
799784
///
@@ -846,47 +831,54 @@ fn needs_post_return(resolve: &Resolve, ty: &Type) -> bool {
846831
}
847832
}
848833

834+
#[derive(Copy, Clone)]
835+
pub enum Realloc {
836+
None,
837+
Export(&'static str),
838+
}
839+
849840
struct Generator<'a, B: Bindgen> {
850-
variant: AbiVariant,
851-
lift_lower: LiftLower,
852841
bindgen: &'a mut B,
853-
async_: bool,
854842
resolve: &'a Resolve,
855843
operands: Vec<B::Operand>,
856844
results: Vec<B::Operand>,
857845
stack: Vec<B::Operand>,
858846
return_pointer: Option<B::Operand>,
847+
realloc: Option<Realloc>,
859848
}
860849

861850
impl<'a, B: Bindgen> Generator<'a, B> {
862-
fn new(
863-
resolve: &'a Resolve,
864-
variant: AbiVariant,
865-
lift_lower: LiftLower,
866-
bindgen: &'a mut B,
867-
async_: bool,
868-
) -> Generator<'a, B> {
851+
fn new(resolve: &'a Resolve, bindgen: &'a mut B) -> Generator<'a, B> {
869852
Generator {
870853
resolve,
871-
variant,
872-
lift_lower,
873854
bindgen,
874-
async_,
875855
operands: Vec::new(),
876856
results: Vec::new(),
877857
stack: Vec::new(),
878858
return_pointer: None,
859+
realloc: None,
879860
}
880861
}
881862

882-
fn call(&mut self, func: &Function) {
863+
fn call(&mut self, func: &Function, variant: AbiVariant, lift_lower: LiftLower, async_: bool) {
883864
const MAX_FLAT_PARAMS: usize = 16;
884865

885-
let sig = self.resolve.wasm_signature(self.variant, func);
866+
let sig = self.resolve.wasm_signature(variant, func);
867+
868+
// Lowering parameters calling a wasm import _or_ returning a result
869+
// from an async-lifted wasm export means we don't need to pass
870+
// ownership, but we pass ownership in all other cases.
871+
let realloc = match (variant, lift_lower, async_) {
872+
(AbiVariant::GuestImport, LiftLower::LowerArgsLiftResults, _)
873+
| (AbiVariant::GuestExport, LiftLower::LiftArgsLowerResults, true) => Realloc::None,
874+
_ => Realloc::Export("cabi_realloc"),
875+
};
876+
assert!(self.realloc.is_none());
886877

887-
match self.lift_lower {
878+
match lift_lower {
888879
LiftLower::LowerArgsLiftResults => {
889-
if let (AbiVariant::GuestExport, true) = (self.variant, self.async_) {
880+
self.realloc = Some(realloc);
881+
if let (AbiVariant::GuestExport, true) = (variant, async_) {
890882
unimplemented!("host-side code generation for async lift/lower not supported");
891883
}
892884

@@ -902,7 +894,7 @@ impl<'a, B: Bindgen> Generator<'a, B> {
902894
self_.stack.push(ptr);
903895
};
904896

905-
if self.async_ {
897+
if async_ {
906898
let ElementInfo { size, align } = self
907899
.bindgen
908900
.sizes()
@@ -926,7 +918,7 @@ impl<'a, B: Bindgen> Generator<'a, B> {
926918
.bindgen
927919
.sizes()
928920
.record(func.params.iter().map(|t| &t.1));
929-
let ptr = match self.variant {
921+
let ptr = match variant {
930922
// When a wasm module calls an import it will provide
931923
// space that isn't explicitly deallocated.
932924
AbiVariant::GuestImport => self.bindgen.return_pointer(size, align),
@@ -949,8 +941,9 @@ impl<'a, B: Bindgen> Generator<'a, B> {
949941
lower_to_memory(self, ptr);
950942
}
951943
}
944+
self.realloc = None;
952945

953-
if self.async_ {
946+
if async_ {
954947
let ElementInfo { size, align } =
955948
self.bindgen.sizes().record(func.result.iter());
956949
let ptr = self.bindgen.return_pointer(size, align);
@@ -964,7 +957,7 @@ impl<'a, B: Bindgen> Generator<'a, B> {
964957
} else {
965958
// If necessary we may need to prepare a return pointer for
966959
// this ABI.
967-
if self.variant == AbiVariant::GuestImport && sig.retptr {
960+
if variant == AbiVariant::GuestImport && sig.retptr {
968961
let info = self.bindgen.sizes().params(&func.result);
969962
let ptr = self.bindgen.return_pointer(info.size, info.align);
970963
self.return_pointer = Some(ptr.clone());
@@ -978,22 +971,22 @@ impl<'a, B: Bindgen> Generator<'a, B> {
978971
});
979972
}
980973

981-
if !(sig.retptr || self.async_) {
974+
if !(sig.retptr || async_) {
982975
// With no return pointer in use we can simply lift the
983976
// result(s) of the function from the result of the core
984977
// wasm function.
985978
if let Some(ty) = &func.result {
986979
self.lift(ty)
987980
}
988981
} else {
989-
let ptr = match self.variant {
982+
let ptr = match variant {
990983
// imports into guests means it's a wasm module
991984
// calling an imported function. We supplied the
992985
// return pointer as the last argument (saved in
993986
// `self.return_pointer`) so we use that to read
994987
// the result of the function from memory.
995988
AbiVariant::GuestImport => {
996-
assert!(sig.results.is_empty() || self.async_);
989+
assert!(sig.results.is_empty() || async_);
997990
self.return_pointer.take().unwrap()
998991
}
999992

@@ -1025,7 +1018,7 @@ impl<'a, B: Bindgen> Generator<'a, B> {
10251018
});
10261019
}
10271020
LiftLower::LiftArgsLowerResults => {
1028-
if let (AbiVariant::GuestImport, true) = (self.variant, self.async_) {
1021+
if let (AbiVariant::GuestImport, true) = (variant, async_) {
10291022
todo!("implement host-side support for async lift/lower");
10301023
}
10311024

@@ -1065,10 +1058,10 @@ impl<'a, B: Bindgen> Generator<'a, B> {
10651058
// ... and that allows us to call the interface types function
10661059
self.emit(&Instruction::CallInterface {
10671060
func,
1068-
async_: self.async_,
1061+
async_: async_,
10691062
});
10701063

1071-
let (lower_to_memory, async_results) = if self.async_ {
1064+
let (lower_to_memory, async_results) = if async_ {
10721065
self.emit(&Instruction::AsyncPostCallInterface { func });
10731066

10741067
let mut results = Vec::new();
@@ -1083,8 +1076,8 @@ impl<'a, B: Bindgen> Generator<'a, B> {
10831076
// This was dynamically allocated by the caller (or async start
10841077
// function) so after it's been read by the guest we need to
10851078
// deallocate it.
1086-
if let AbiVariant::GuestExport = self.variant {
1087-
if sig.indirect_params && !self.async_ {
1079+
if let AbiVariant::GuestExport = variant {
1080+
if sig.indirect_params && !async_ {
10881081
let ElementInfo { size, align } = self
10891082
.bindgen
10901083
.sizes()
@@ -1094,14 +1087,16 @@ impl<'a, B: Bindgen> Generator<'a, B> {
10941087
}
10951088
}
10961089

1090+
self.realloc = Some(realloc);
1091+
10971092
if !lower_to_memory {
10981093
// With no return pointer in use we simply lower the
10991094
// result(s) and return that directly from the function.
11001095
if let Some(ty) = &func.result {
11011096
self.lower(ty);
11021097
}
11031098
} else {
1104-
match self.variant {
1099+
match variant {
11051100
// When a function is imported to a guest this means
11061101
// it's a host providing the implementation of the
11071102
// import. The result is stored in the pointer
@@ -1159,9 +1154,12 @@ impl<'a, B: Bindgen> Generator<'a, B> {
11591154
amt: sig.results.len(),
11601155
});
11611156
}
1157+
self.realloc = None;
11621158
}
11631159
}
11641160

1161+
assert!(self.realloc.is_none());
1162+
11651163
assert!(
11661164
self.stack.is_empty(),
11671165
"stack has {} items remaining",
@@ -1170,7 +1168,7 @@ impl<'a, B: Bindgen> Generator<'a, B> {
11701168
}
11711169

11721170
fn post_return(&mut self, func: &Function) {
1173-
let sig = self.resolve.wasm_signature(self.variant, func);
1171+
let sig = self.resolve.wasm_signature(AbiVariant::GuestExport, func);
11741172

11751173
// Currently post-return is only used for lists and lists are always
11761174
// returned indirectly through memory due to their flat representation
@@ -1424,13 +1422,9 @@ impl<'a, B: Bindgen> Generator<'a, B> {
14241422
}
14251423

14261424
fn list_realloc(&self) -> Option<&'static str> {
1427-
// Lowering parameters calling a wasm import _or_ returning a result
1428-
// from an async-lifted wasm export means we don't need to pass
1429-
// ownership, but we pass ownership in all other cases.
1430-
match (self.variant, self.lift_lower, self.async_) {
1431-
(AbiVariant::GuestImport, LiftLower::LowerArgsLiftResults, _)
1432-
| (AbiVariant::GuestExport, LiftLower::LiftArgsLowerResults, true) => None,
1433-
_ => Some("cabi_realloc"),
1425+
match self.realloc.expect("realloc should be configured") {
1426+
Realloc::None => None,
1427+
Realloc::Export(s) => Some(s),
14341428
}
14351429
}
14361430

crates/csharp/src/interface.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ impl InterfaceGenerator<'_> {
495495
ParameterType::ABI,
496496
);
497497

498-
abi::post_return(bindgen.interface_gen.resolve, func, &mut bindgen, false);
498+
abi::post_return(bindgen.interface_gen.resolve, func, &mut bindgen);
499499

500500
let src = bindgen.src;
501501

crates/moonbit/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -969,7 +969,7 @@ impl InterfaceGenerator<'_> {
969969
(0..sig.results.len()).map(|i| format!("p{i}")).collect(),
970970
);
971971

972-
abi::post_return(bindgen.gen.resolve, func, &mut bindgen, false);
972+
abi::post_return(bindgen.gen.resolve, func, &mut bindgen);
973973

974974
let src = bindgen.src;
975975

crates/rust/src/interface.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ pub mod vtable{ordinal} {{
10651065
self.src.push_str("{ unsafe {\n");
10661066

10671067
let mut f = FunctionBindgen::new(self, params, async_, self.wasm_import_module, false);
1068-
abi::post_return(f.r#gen.resolve, func, &mut f, async_);
1068+
abi::post_return(f.r#gen.resolve, func, &mut f);
10691069
let FunctionBindgen {
10701070
needs_cleanup_list,
10711071
src,

0 commit comments

Comments
 (0)