Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
106 changes: 89 additions & 17 deletions crates/cranelift/src/compiler/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ impl<'a> TrampolineCompiler<'a> {
}

fn translate(&mut self, trampoline: &Trampoline) {
self.check_may_leave(trampoline);

match trampoline {
Trampoline::Transcoder {
op,
Expand Down Expand Up @@ -1202,23 +1204,7 @@ impl<'a> TrampolineCompiler<'a> {
// calling itself.
let old_may_block = if let Some(def) = resource_def {
if self.types[resource].unwrap_concrete_instance() != def.instance {
let flags = self.builder.ins().load(
ir::types::I32,
trusted,
vmctx,
i32::try_from(
self.offsets
.instance_flags(self.types[resource].unwrap_concrete_instance()),
)
.unwrap(),
);
let masked = self
.builder
.ins()
.band_imm(flags, i64::from(FLAG_MAY_LEAVE));
self.builder
.ins()
.trapz(masked, TRAP_CANNOT_LEAVE_COMPONENT);
self.check_may_leave_instance(self.types[resource].unwrap_concrete_instance());

if self.compiler.tunables.concurrency_support {
// Stash the old value of `may_block` and then set it to false.
Expand Down Expand Up @@ -1471,6 +1457,92 @@ impl<'a> TrampolineCompiler<'a> {
self.compiler
.call_indirect_host(&mut self.builder, index, host_sig, host_fn, args)
}

fn check_may_leave(&mut self, trampoline: &Trampoline) {
let instance = match trampoline {
// These intrinsics explicitly do not check the may-leave flag.
Trampoline::ResourceRep { .. }
| Trampoline::ThreadIndex
| Trampoline::BackpressureInc { .. }
| Trampoline::BackpressureDec { .. }
| Trampoline::ContextGet { .. }
| Trampoline::ContextSet { .. } => return,

// Intrinsics used in adapters generated by FACT that aren't called
// directly from guest wasm, so no check is needed.
Trampoline::ResourceTransferOwn
| Trampoline::ResourceTransferBorrow
| Trampoline::ResourceEnterCall
| Trampoline::ResourceExitCall
| Trampoline::PrepareCall { .. }
| Trampoline::SyncStartCall { .. }
| Trampoline::AsyncStartCall { .. }
| Trampoline::FutureTransfer
| Trampoline::StreamTransfer
| Trampoline::ErrorContextTransfer
| Trampoline::Trap
| Trampoline::EnterSyncCall
| Trampoline::ExitSyncCall
| Trampoline::Transcoder { .. } => return,

Trampoline::LowerImport { options, .. } => self.component.options[*options].instance,

Trampoline::ResourceNew { instance, .. }
| Trampoline::ResourceDrop { instance, .. }
| Trampoline::TaskReturn { instance, .. }
| Trampoline::TaskCancel { instance }
| Trampoline::WaitableSetNew { instance }
| Trampoline::WaitableSetWait { instance, .. }
| Trampoline::WaitableSetPoll { instance, .. }
| Trampoline::WaitableSetDrop { instance }
| Trampoline::WaitableJoin { instance }
| Trampoline::ThreadYield { instance, .. }
| Trampoline::ThreadSwitchTo { instance, .. }
| Trampoline::ThreadNewIndirect { instance, .. }
| Trampoline::ThreadSuspend { instance, .. }
| Trampoline::ThreadResumeLater { instance }
| Trampoline::ThreadYieldTo { instance, .. }
| Trampoline::SubtaskDrop { instance }
| Trampoline::SubtaskCancel { instance, .. }
| Trampoline::ErrorContextNew { instance, .. }
| Trampoline::ErrorContextDebugMessage { instance, .. }
| Trampoline::ErrorContextDrop { instance, .. }
| Trampoline::StreamNew { instance, .. }
| Trampoline::StreamRead { instance, .. }
| Trampoline::StreamWrite { instance, .. }
| Trampoline::StreamCancelRead { instance, .. }
| Trampoline::StreamCancelWrite { instance, .. }
| Trampoline::StreamDropReadable { instance, .. }
| Trampoline::StreamDropWritable { instance, .. }
| Trampoline::FutureNew { instance, .. }
| Trampoline::FutureRead { instance, .. }
| Trampoline::FutureWrite { instance, .. }
| Trampoline::FutureCancelRead { instance, .. }
| Trampoline::FutureCancelWrite { instance, .. }
| Trampoline::FutureDropReadable { instance, .. }
| Trampoline::FutureDropWritable { instance, .. } => *instance,
};

self.check_may_leave_instance(instance)
}

fn check_may_leave_instance(&mut self, instance: RuntimeComponentInstanceIndex) {
let vmctx = self.builder.func.dfg.block_params(self.block0)[0];

let flags = self.builder.ins().load(
ir::types::I32,
ir::MemFlags::trusted(),
vmctx,
i32::try_from(self.offsets.instance_flags(instance)).unwrap(),
);
let may_leave_bit = self
.builder
.ins()
.band_imm(flags, i64::from(FLAG_MAY_LEAVE));
self.builder
.ins()
.trapz(may_leave_bit, TRAP_CANNOT_LEAVE_COMPONENT);
}
}

impl ComponentCompiler for Compiler {
Expand Down
Loading
Loading