Skip to content

Commit

Permalink
Rework DeferCallCore to DeferFree
Browse files Browse the repository at this point in the history
Co-Authored-By: Liam Murphy <[email protected]>
  • Loading branch information
daxpedda and Liamolucko committed Jun 6, 2023
1 parent 8a88582 commit 73a7f68
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 55 deletions.
68 changes: 18 additions & 50 deletions crates/cli-support/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,57 +548,32 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
| Instruction::CallExport(_)
| Instruction::CallAdapter(_)
| Instruction::CallTableElement(_)
| Instruction::DeferCallCore(_) => {
| Instruction::DeferFree { align, .. } => {
let invoc = Invocation::from(instr, js.cx.module)?;
let (mut params, results) = invoc.params_results(js.cx);
assert_eq!(results, 0, "deferred calls must have no results");
// substract alignment
params -= 1;

let mut args = Vec::new();
let tmp = js.tmp();
if invoc.defer() {
// substract alignment
params -= 1;
// If the call is deferred, the arguments to the function still need to be
// accessible in the `finally` block, so we declare variables to hold the args
// outside of the try-finally block and then set those to the args.
for (i, arg) in js.stack[js.stack.len() - params..].iter().enumerate() {
let name = format!("deferred{tmp}_{i}");
writeln!(js.pre_try, "let {name};").unwrap();
writeln!(js.prelude, "{name} = {arg};").unwrap();
args.push(name);
}
// add alignment
args.push(String::from("4"));
} else {
// Otherwise, pop off the number of parameters for the function we're calling.
for _ in 0..params {
args.push(js.pop());
}
args.reverse();

// If the call is deferred, the arguments to the function still need to be
// accessible in the `finally` block, so we declare variables to hold the args
// outside of the try-finally block and then set those to the args.
for (i, arg) in js.stack[js.stack.len() - params..].iter().enumerate() {
let name = format!("deferred{tmp}_{i}");
writeln!(js.pre_try, "let {name};").unwrap();
writeln!(js.prelude, "{name} = {arg};").unwrap();
args.push(name);
}
// add alignment
args.push(align.to_string());

// Call the function through an export of the underlying module.
let call = invoc.invoke(js.cx, &args, &mut js.prelude, log_error)?;

// And then figure out how to actually handle where the call
// happens. This is pretty conditional depending on the number of
// return values of the function.
match (invoc.defer(), results) {
(true, 0) => {
js.finally(&format!("{};", call));
}
(true, _) => panic!("deferred calls must have no results"),
(false, 0) => js.prelude(&format!("{};", call)),
(false, n) => {
js.prelude(&format!("const ret = {};", call));
if n == 1 {
js.push("ret".to_string());
} else {
for i in 0..n {
js.push(format!("ret[{}]", i));
}
}
}
}
js.finally(&format!("{};", call));
}

Instruction::IntToWasm { input, .. } => {
Expand Down Expand Up @@ -1194,8 +1169,8 @@ impl Invocation {
defer: false,
},

DeferCallCore(f) => Invocation::Core {
id: *f,
DeferFree { free, .. } => Invocation::Core {
id: *free,
defer: true,
},

Expand Down Expand Up @@ -1264,13 +1239,6 @@ impl Invocation {
}
}
}

fn defer(&self) -> bool {
match self {
Invocation::Core { defer, .. } => *defer,
_ => false,
}
}
}

fn adapter2ts(ty: &AdapterType, dst: &mut String) {
Expand Down
6 changes: 3 additions & 3 deletions crates/cli-support/src/wit/outgoing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl InstructionBuilder<'_, '_> {
// ... then defer a call to `free` to happen later
let free = self.cx.free()?;
self.instructions.push(InstructionData {
instr: Instruction::DeferCallCore(free),
instr: Instruction::DeferFree { free, align: 1 },
stack_change: StackChange::Modified {
popped: 2,
pushed: 2,
Expand Down Expand Up @@ -389,7 +389,7 @@ impl InstructionBuilder<'_, '_> {
// special case it.
assert!(!self.instructions[len..]
.iter()
.any(|idata| matches!(idata.instr, Instruction::DeferCallCore(_))));
.any(|idata| matches!(idata.instr, Instruction::DeferFree { .. })));

// Finally, we add the two inputs to UnwrapResult, and everything checks out
//
Expand Down Expand Up @@ -429,7 +429,7 @@ impl InstructionBuilder<'_, '_> {
// implementation.
let free = self.cx.free()?;
self.instructions.push(InstructionData {
instr: Instruction::DeferCallCore(free),
instr: Instruction::DeferFree { free, align: 1 },
stack_change: StackChange::Modified {
popped: 2,
pushed: 2,
Expand Down
7 changes: 5 additions & 2 deletions crates/cli-support/src/wit/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ pub enum Instruction {
CallCore(walrus::FunctionId),
/// Schedules a function to be called after the whole lift/lower cycle is
/// finished, e.g. to deallocate a string or something.
DeferCallCore(walrus::FunctionId),
DeferFree {
free: walrus::FunctionId,
align: usize,
},
/// A call to one of our own defined adapters, similar to the standard
/// call-adapter instruction
CallAdapter(AdapterId),
Expand Down Expand Up @@ -423,7 +426,7 @@ impl walrus::CustomSection for NonstandardWitSection {
};
for instr in instrs {
match instr.instr {
DeferCallCore(f) | CallCore(f) => {
DeferFree { free: f, .. } | CallCore(f) => {
roots.push_func(f);
}
StoreRetptr { mem, .. }
Expand Down

0 comments on commit 73a7f68

Please sign in to comment.