Skip to content

Commit 967f460

Browse files
authored
generate precise traps in component adapters (#12215)
* generate precise traps in component adapters Previously, we generated a generic `unreachable` instruction for each trap in a fused adapter, plus some metadata to recover the specific kind of trap. However, that metadata was never hooked up to anything, so we only got a generic `unreachable` message at runtime. This commit removes the metadata tracking and instead simply calls a host intrinsic, passing the trap code as a parameter. This is somewhate pessimal compared with what we had before, but improves ergonomics and allows us to avoid forking as many tests from the component-model repo. If performance becomes an issue, we can easily add an option to skip the host call and only emit an `unreachable` instruction as before. Note that I've removed forked versions of three tests in favor of their upstream equivalents. Fixes #11683 * update `strings.rs` tests * bless disas tests
1 parent 34ba273 commit 967f460

File tree

20 files changed

+294
-2097
lines changed

20 files changed

+294
-2097
lines changed

crates/cranelift/src/compiler/component.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl<'a> TrampolineCompiler<'a> {
171171
WasmArgs::InRegisters,
172172
|me, params| {
173173
let code = wasmtime_environ::Trap::AlwaysTrapAdapter as u8;
174-
params.push(me.builder.ins().iconst(ir::types::I8, i64::from(code)));
174+
params.push(me.builder.ins().iconst(ir::types::I32, i64::from(code)));
175175
},
176176
);
177177
}
@@ -740,6 +740,14 @@ impl<'a> TrampolineCompiler<'a> {
740740
|_, _| {},
741741
);
742742
}
743+
Trampoline::Trap => {
744+
self.translate_libcall(
745+
host::trap,
746+
TrapSentinel::Falsy,
747+
WasmArgs::InRegisters,
748+
|_, _| {},
749+
);
750+
}
743751
Trampoline::ContextGet { instance, slot } => {
744752
self.translate_libcall(
745753
host::context_get,

crates/environ/src/component.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ macro_rules! foreach_builtin_component_function {
203203
#[cfg(feature = "component-model-async")]
204204
thread_yield_to(vmctx: vmctx, caller_instance: u32, cancellable: u8, thread_idx: u32) -> u32;
205205

206-
trap(vmctx: vmctx, code: u8) -> bool;
206+
trap(vmctx: vmctx, code: u32) -> bool;
207207

208208
utf8_to_utf8(vmctx: vmctx, src: ptr_u8, len: size, dst: ptr_u8) -> bool;
209209
utf16_to_utf16(vmctx: vmctx, src: ptr_u16, len: size, dst: ptr_u16) -> bool;

crates/environ/src/component/dfg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ pub enum Trampoline {
476476
StreamTransfer,
477477
ErrorContextTransfer,
478478
CheckBlocking,
479+
Trap,
479480
ContextGet {
480481
instance: RuntimeComponentInstanceIndex,
481482
slot: u32,
@@ -1156,6 +1157,7 @@ impl LinearizeDfg<'_> {
11561157
Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
11571158
Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
11581159
Trampoline::CheckBlocking => info::Trampoline::CheckBlocking,
1160+
Trampoline::Trap => info::Trampoline::Trap,
11591161
Trampoline::ContextGet { instance, slot } => info::Trampoline::ContextGet {
11601162
instance: *instance,
11611163
slot: *slot,

crates/environ/src/component/info.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,10 @@ pub enum Trampoline {
11091109
/// async-typed function may be called via a sync lower.
11101110
CheckBlocking,
11111111

1112+
/// An intrinsic used by FACT-generated modules to trap with a specified
1113+
/// code.
1114+
Trap,
1115+
11121116
/// Intrinsic used to implement the `context.get` component model builtin.
11131117
///
11141118
/// The payload here represents that this is accessing the Nth slot of local
@@ -1239,6 +1243,7 @@ impl Trampoline {
12391243
StreamTransfer => format!("stream-transfer"),
12401244
ErrorContextTransfer => format!("error-context-transfer"),
12411245
CheckBlocking => format!("check-blocking"),
1246+
Trap => format!("trap"),
12421247
ContextGet { .. } => format!("context-get"),
12431248
ContextSet { .. } => format!("context-set"),
12441249
ThreadIndex => format!("thread-index"),

crates/environ/src/component/translate/adapt.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ fn fact_import_to_core_def(
346346
simple_intrinsic(dfg::Trampoline::ErrorContextTransfer)
347347
}
348348
fact::Import::CheckBlocking => simple_intrinsic(dfg::Trampoline::CheckBlocking),
349+
fact::Import::Trap => simple_intrinsic(dfg::Trampoline::Trap),
349350
}
350351
}
351352

crates/environ/src/fact.rs

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,13 @@ use crate::component::{
2626
use crate::fact::transcode::Transcoder;
2727
use crate::{EntityRef, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap};
2828
use crate::{ModuleInternedTypeIndex, prelude::*};
29-
use std::borrow::Cow;
3029
use std::collections::HashMap;
3130
use wasm_encoder::*;
3231

3332
mod core_types;
3433
mod signature;
3534
mod trampoline;
3635
mod transcode;
37-
mod traps;
3836

3937
/// Fixed parameter types for the `prepare_call` built-in function.
4038
///
@@ -92,6 +90,8 @@ pub struct Module<'a> {
9290

9391
imported_check_blocking: Option<FuncIndex>,
9492

93+
imported_trap: Option<FuncIndex>,
94+
9595
// Current status of index spaces from the imports generated so far.
9696
imported_funcs: PrimaryMap<FuncIndex, Option<CoreDef>>,
9797
imported_memories: PrimaryMap<MemoryIndex, CoreDef>,
@@ -263,6 +263,7 @@ impl<'a> Module<'a> {
263263
imported_stream_transfer: None,
264264
imported_error_context_transfer: None,
265265
imported_check_blocking: None,
266+
imported_trap: None,
266267
exports: Vec::new(),
267268
}
268269
}
@@ -727,6 +728,17 @@ impl<'a> Module<'a> {
727728
)
728729
}
729730

731+
fn import_trap(&mut self) -> FuncIndex {
732+
self.import_simple(
733+
"runtime",
734+
"trap",
735+
&[ValType::I32],
736+
&[],
737+
Import::Trap,
738+
|me| &mut me.imported_trap,
739+
)
740+
}
741+
730742
fn translate_helper(&mut self, helper: Helper) -> FunctionId {
731743
*self.helper_funcs.entry(helper).or_insert_with(|| {
732744
// Generate a fresh `Function` with a unique id for what we're about to
@@ -765,9 +777,7 @@ impl<'a> Module<'a> {
765777
// With all functions numbered the fragments of the body of each
766778
// function can be assigned into one final adapter function.
767779
let mut code = CodeSection::new();
768-
let mut traps = traps::TrapSection::default();
769-
for (id, func) in self.funcs.iter() {
770-
let mut func_traps = Vec::new();
780+
for (_, func) in self.funcs.iter() {
771781
let mut body = Vec::new();
772782

773783
// Encode all locals used for this function
@@ -783,12 +793,8 @@ impl<'a> Module<'a> {
783793
// here to the final function index.
784794
for chunk in func.body.iter() {
785795
match chunk {
786-
Body::Raw(code, traps) => {
787-
let start = body.len();
796+
Body::Raw(code) => {
788797
body.extend_from_slice(code);
789-
for (offset, trap) in traps {
790-
func_traps.push((start + offset, *trap));
791-
}
792798
}
793799
Body::Call(id) => {
794800
Instruction::Call(id_to_index[*id].as_u32()).encode(&mut body);
@@ -799,23 +805,14 @@ impl<'a> Module<'a> {
799805
}
800806
}
801807
code.raw(&body);
802-
traps.append(id_to_index[id].as_u32(), func_traps);
803808
}
804809

805-
let traps = traps.finish();
806-
807810
let mut result = wasm_encoder::Module::new();
808811
result.section(&self.core_types.section);
809812
result.section(&self.core_imports);
810813
result.section(&funcs);
811814
result.section(&exports);
812815
result.section(&code);
813-
if self.debug {
814-
result.section(&CustomSection {
815-
name: "wasmtime-trampoline-traps".into(),
816-
data: Cow::Borrowed(&traps),
817-
});
818-
}
819816
result.finish()
820817
}
821818

@@ -888,6 +885,8 @@ pub enum Import {
888885
/// An intrinsic used by FACT-generated modules to check whether an
889886
/// async-typed function may be called via a sync lower.
890887
CheckBlocking,
888+
/// An intrinsic for trapping the instance with a specific trap code.
889+
Trap,
891890
}
892891

893892
impl Options {
@@ -954,8 +953,6 @@ struct Function {
954953
///
955954
/// 1. First a `Raw` variant is used to contain general instructions for the
956955
/// wasm function. This is populated by `Compiler::instruction` primarily.
957-
/// This also comes with a list of traps. and the byte offset within the
958-
/// first vector of where the trap information applies to.
959956
///
960957
/// 2. A `Call` instruction variant for a `FunctionId` where the final
961958
/// `FuncIndex` isn't known until emission time.
@@ -971,7 +968,7 @@ struct Function {
971968
/// easier to represent. A 5-byte leb may be more efficient at compile-time if
972969
/// necessary, however.
973970
enum Body {
974-
Raw(Vec<u8>, Vec<(usize, traps::Trap)>),
971+
Raw(Vec<u8>),
975972
Call(FunctionId),
976973
RefFunc(FunctionId),
977974
}

0 commit comments

Comments
 (0)