Skip to content

Commit

Permalink
Migrate component libcalls to checking for traps
Browse files Browse the repository at this point in the history
This commit is the analog of bytecodealliance#9675 but for component libcalls. This
follows suit from the previous commit which updates all component
libcalls to explicitly returning whether a trap happened and if so
performing said trap. This then removes the need for the old trap
handling functions in the runtime which means they can all be deleted
now as they're no longer necessary.
  • Loading branch information
alexcrichton committed Nov 29, 2024
1 parent c1aafee commit eb19d41
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 119 deletions.
65 changes: 56 additions & 9 deletions crates/cranelift/src/compiler/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use crate::{compiler::Compiler, TRAP_ALWAYS, TRAP_CANNOT_ENTER, TRAP_INTERNAL_ASSERT};
use anyhow::Result;
use cranelift_codegen::ir::condcodes::IntCC;
use cranelift_codegen::ir::{self, InstBuilder, MemFlags};
use cranelift_codegen::isa::{CallConv, TargetIsa};
use cranelift_frontend::FunctionBuilder;
Expand Down Expand Up @@ -97,16 +98,22 @@ impl<'a> TrampolineCompiler<'a> {
Trampoline::ResourceRep(ty) => self.translate_resource_rep(*ty),
Trampoline::ResourceDrop(ty) => self.translate_resource_drop(*ty),
Trampoline::ResourceTransferOwn => {
self.translate_resource_libcall(host::resource_transfer_own)
self.translate_resource_libcall(host::resource_transfer_own, |me, rets| {
rets[0] = me.raise_if_resource_trapped(rets[0]);
})
}
Trampoline::ResourceTransferBorrow => {
self.translate_resource_libcall(host::resource_transfer_borrow)
self.translate_resource_libcall(host::resource_transfer_borrow, |me, rets| {
rets[0] = me.raise_if_resource_trapped(rets[0]);
})
}
Trampoline::ResourceEnterCall => {
self.translate_resource_libcall(host::resource_enter_call)
self.translate_resource_libcall(host::resource_enter_call, |_, _| {})
}
Trampoline::ResourceExitCall => {
self.translate_resource_libcall(host::resource_exit_call)
self.translate_resource_libcall(host::resource_exit_call, |me, rets| {
me.raise_if_host_trapped(rets.pop().unwrap());
})
}
}
}
Expand All @@ -120,7 +127,6 @@ impl<'a> TrampolineCompiler<'a> {
let pointer_type = self.isa.pointer_type();
let args = self.builder.func.dfg.block_params(self.block0).to_vec();
let vmctx = args[0];
let caller_vmctx = args[1];
let wasm_func_ty = self.types[self.signature].unwrap_func();

// Start off by spilling all the wasm arguments into a stack slot to be
Expand Down Expand Up @@ -248,8 +254,7 @@ impl<'a> TrampolineCompiler<'a> {

match self.abi {
Abi::Wasm => {
self.compiler
.raise_if_host_trapped(&mut self.builder, caller_vmctx, succeeded);
self.raise_if_host_trapped(succeeded);
// After the host function has returned the results are loaded from
// `values_vec_ptr` and then returned.
let results = self.compiler.load_values_from_array(
Expand Down Expand Up @@ -284,6 +289,8 @@ impl<'a> TrampolineCompiler<'a> {
);
self.compiler
.call_indirect_host(&mut self.builder, host_sig, host_fn, &[vmctx, code]);
let succeeded = self.builder.ins().iconst(ir::types::I8, 0);
self.raise_if_host_trapped(succeeded);
// debug trap in case execution actually falls through, but this
// shouldn't ever get hit at runtime.
self.builder.ins().trap(TRAP_INTERNAL_ASSERT);
Expand Down Expand Up @@ -319,6 +326,7 @@ impl<'a> TrampolineCompiler<'a> {
self.compiler
.call_indirect_host(&mut self.builder, host_sig, host_fn, &host_args);
let result = self.builder.func.dfg.inst_results(call)[0];
let result = self.raise_if_resource_trapped(result);
self.abi_store_results(&[result]);
}

Expand Down Expand Up @@ -352,6 +360,7 @@ impl<'a> TrampolineCompiler<'a> {
self.compiler
.call_indirect_host(&mut self.builder, host_sig, host_fn, &host_args);
let result = self.builder.func.dfg.inst_results(call)[0];
let result = self.raise_if_resource_trapped(result);
self.abi_store_results(&[result]);
}

Expand Down Expand Up @@ -382,6 +391,14 @@ impl<'a> TrampolineCompiler<'a> {
.call_indirect_host(&mut self.builder, host_sig, host_fn, &host_args);
let should_run_destructor = self.builder.func.dfg.inst_results(call)[0];

// Immediately raise a trap if requested by the host
let minus_one = self.builder.ins().iconst(ir::types::I64, -1);
let succeeded = self
.builder
.ins()
.icmp(IntCC::NotEqual, should_run_destructor, minus_one);
self.raise_if_host_trapped(succeeded);

let resource_ty = self.types[resource].ty;
let resource_def = self
.component
Expand Down Expand Up @@ -541,6 +558,7 @@ impl<'a> TrampolineCompiler<'a> {
fn translate_resource_libcall(
&mut self,
get_libcall: fn(&dyn TargetIsa, &mut ir::Function) -> (ir::SigRef, u32),
handle_results: fn(&mut Self, &mut Vec<ir::Value>),
) {
match self.abi {
Abi::Wasm => {}
Expand All @@ -562,7 +580,8 @@ impl<'a> TrampolineCompiler<'a> {
let call =
self.compiler
.call_indirect_host(&mut self.builder, host_sig, host_fn, &host_args);
let results = self.builder.func.dfg.inst_results(call).to_vec();
let mut results = self.builder.func.dfg.inst_results(call).to_vec();
handle_results(self, &mut results);
self.builder.ins().return_(&results);
}

Expand Down Expand Up @@ -637,6 +656,29 @@ impl<'a> TrampolineCompiler<'a> {
}
}
}

fn raise_if_host_trapped(&mut self, succeeded: ir::Value) {
let caller_vmctx = self.builder.func.dfg.block_params(self.block0)[1];
self.compiler
.raise_if_host_trapped(&mut self.builder, caller_vmctx, succeeded);
}

fn raise_if_transcode_trapped(&mut self, amount_copied: ir::Value) {
let pointer_type = self.isa.pointer_type();
let minus_one = self.builder.ins().iconst(pointer_type, -1);
let succeeded = self
.builder
.ins()
.icmp(IntCC::NotEqual, amount_copied, minus_one);
self.raise_if_host_trapped(succeeded);
}

fn raise_if_resource_trapped(&mut self, ret: ir::Value) -> ir::Value {
let minus_one = self.builder.ins().iconst(ir::types::I64, -1);
let succeeded = self.builder.ins().icmp(IntCC::NotEqual, ret, minus_one);
self.raise_if_host_trapped(succeeded);
self.builder.ins().ireduce(ir::types::I32, ret)
}
}

impl ComponentCompiler for Compiler {
Expand Down Expand Up @@ -806,19 +848,23 @@ impl TrampolineCompiler<'_> {
// Like the arguments the results are fairly similar across libcalls, so
// they're lumped into various buckets here.
match op {
Transcode::Copy(_) | Transcode::Latin1ToUtf16 => {}
Transcode::Copy(_) | Transcode::Latin1ToUtf16 => {
self.raise_if_host_trapped(results[0]);
}

Transcode::Utf8ToUtf16
| Transcode::Utf16ToCompactProbablyUtf16
| Transcode::Utf8ToCompactUtf16
| Transcode::Utf16ToCompactUtf16 => {
self.raise_if_transcode_trapped(results[0]);
raw_results.push(self.cast_from_pointer(results[0], to64));
}

Transcode::Latin1ToUtf8
| Transcode::Utf16ToUtf8
| Transcode::Utf8ToLatin1
| Transcode::Utf16ToLatin1 => {
self.raise_if_transcode_trapped(results[0]);
raw_results.push(self.cast_from_pointer(results[0], from64));
raw_results.push(self.cast_from_pointer(results[1], to64));
}
Expand Down Expand Up @@ -931,6 +977,7 @@ mod host {
(@ty $ptr:ident ptr_u8) => ($ptr);
(@ty $ptr:ident ptr_u16) => ($ptr);
(@ty $ptr:ident ptr_size) => ($ptr);
(@ty $ptr:ident bool) => (ir::types::I8);
(@ty $ptr:ident u8) => (ir::types::I8);
(@ty $ptr:ident u32) => (ir::types::I32);
(@ty $ptr:ident u64) => (ir::types::I64);
Expand Down
18 changes: 9 additions & 9 deletions crates/environ/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ pub use self::types_builder::*;
macro_rules! foreach_transcoder {
($mac:ident) => {
$mac! {
utf8_to_utf8(src: ptr_u8, len: size, dst: ptr_u8);
utf16_to_utf16(src: ptr_u16, len: size, dst: ptr_u16);
latin1_to_latin1(src: ptr_u8, len: size, dst: ptr_u8);
latin1_to_utf16(src: ptr_u8, len: size, dst: ptr_u16);
utf8_to_utf8(src: ptr_u8, len: size, dst: ptr_u8) -> bool;
utf16_to_utf16(src: ptr_u16, len: size, dst: ptr_u16) -> bool;
latin1_to_latin1(src: ptr_u8, len: size, dst: ptr_u8) -> bool;
latin1_to_utf16(src: ptr_u8, len: size, dst: ptr_u16) -> bool;
utf8_to_utf16(src: ptr_u8, len: size, dst: ptr_u16) -> size;
utf16_to_utf8(src: ptr_u16, src_len: size, dst: ptr_u8, dst_len: size, ret2: ptr_size) -> size;
latin1_to_utf8(src: ptr_u8, src_len: size, dst: ptr_u8, dst_len: size, ret2: ptr_size) -> size;
Expand All @@ -91,19 +91,19 @@ macro_rules! foreach_transcoder {
macro_rules! foreach_builtin_component_function {
($mac:ident) => {
$mac! {
resource_new32(vmctx: vmctx, resource: u32, rep: u32) -> u32;
resource_rep32(vmctx: vmctx, resource: u32, idx: u32) -> u32;
resource_new32(vmctx: vmctx, resource: u32, rep: u32) -> u64;
resource_rep32(vmctx: vmctx, resource: u32, idx: u32) -> u64;

// Returns an `Option<u32>` where `None` is "no destructor needed"
// and `Some(val)` is "run the destructor on this rep". The option
// is encoded as a 64-bit integer where the low bit is Some/None
// and bits 1-33 are the payload.
resource_drop(vmctx: vmctx, resource: u32, idx: u32) -> u64;

resource_transfer_own(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u32;
resource_transfer_borrow(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u32;
resource_transfer_own(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64;
resource_transfer_borrow(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64;
resource_enter_call(vmctx: vmctx);
resource_exit_call(vmctx: vmctx);
resource_exit_call(vmctx: vmctx) -> bool;

trap(vmctx: vmctx, code: u8);
}
Expand Down
Loading

0 comments on commit eb19d41

Please sign in to comment.