wasmtime_internal_cranelift/func_environ/stack_switching/
control_effect.rs

1use cranelift_codegen::ir;
2use cranelift_codegen::ir::InstBuilder;
3use cranelift_codegen::ir::types::{I32, I64};
4use cranelift_frontend::FunctionBuilder;
5
6/// Universal control effect. This structure encodes return signal,
7/// resume signal, suspension signal, and handler index into a
8/// u64 value. This instance is used at compile time. There is a runtime
9/// counterpart in `continuations/src/lib.rs`.
10/// We convert to and from u64 as follows: The low 32 bits of the u64 are the
11/// discriminant, the high 32 bits are the handler_index (if `Suspend`)
12#[derive(Clone, Copy)]
13pub struct ControlEffect(ir::Value);
14
15impl ControlEffect {
16    // Returns the discriminant
17    pub fn signal(&self, builder: &mut FunctionBuilder) -> ir::Value {
18        builder.ins().ushr_imm(self.0, 32)
19    }
20
21    pub fn from_u64(val: ir::Value) -> Self {
22        Self(val)
23    }
24
25    pub fn to_u64(&self) -> ir::Value {
26        self.0
27    }
28
29    pub fn encode_resume(builder: &mut FunctionBuilder) -> Self {
30        let discriminant = builder.ins().iconst(
31            I64,
32            i64::from(wasmtime_environ::CONTROL_EFFECT_RESUME_DISCRIMINANT),
33        );
34        let val = builder.ins().ishl_imm(discriminant, 32);
35
36        Self(val)
37    }
38
39    pub fn encode_switch(builder: &mut FunctionBuilder) -> Self {
40        let discriminant = builder.ins().iconst(
41            I64,
42            i64::from(wasmtime_environ::CONTROL_EFFECT_SWITCH_DISCRIMINANT),
43        );
44        let val = builder.ins().ishl_imm(discriminant, 32);
45
46        Self(val)
47    }
48
49    pub fn encode_suspend(builder: &mut FunctionBuilder, handler_index: ir::Value) -> Self {
50        let discriminant = builder.ins().iconst(
51            I64,
52            i64::from(wasmtime_environ::CONTROL_EFFECT_SUSPEND_DISCRIMINANT),
53        );
54        let val = builder.ins().ishl_imm(discriminant, 32);
55        let handler_index = builder.ins().uextend(I64, handler_index);
56        let val = builder.ins().bor(val, handler_index);
57
58        Self(val)
59    }
60
61    /// Returns the payload of the `Suspend` variant
62    pub fn handler_index(self, builder: &mut FunctionBuilder) -> ir::Value {
63        builder.ins().ireduce(I32, self.0)
64    }
65}