use crate::loader::Instruction;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Coverage {
Supported,
RejectedIncremental { reason: &'static str },
RejectedInherent { reason: &'static str },
}
pub fn coverage(instruction: &Instruction) -> Coverage {
match instruction {
Instruction::Label { .. }
| Instruction::Move { .. }
| Instruction::Swap { .. }
| Instruction::Bif { .. }
| Instruction::TypeTest { .. }
| Instruction::Comparison { .. }
| Instruction::TestArity { .. }
| Instruction::IsTaggedTuple { .. }
| Instruction::SelectVal { .. }
| Instruction::Jump { .. }
| Instruction::Send
| Instruction::LoopRec { .. }
| Instruction::LoopRecEnd { .. }
| Instruction::RemoveMessage
| Instruction::Wait { .. }
| Instruction::WaitTimeout { .. }
| Instruction::Timeout
| Instruction::RecvMarkerReserve { .. }
| Instruction::RecvMarkerBind { .. }
| Instruction::RecvMarkerClear { .. }
| Instruction::RecvMarkerUse { .. }
| Instruction::Try { .. }
| Instruction::TryEnd { .. }
| Instruction::TryCase { .. }
| Instruction::Return
| Instruction::CallExt { .. }
| Instruction::CallExtOnly { .. }
| Instruction::MakeFun { .. }
| Instruction::CallFun { .. }
| Instruction::Call { .. }
| Instruction::CallOnly { .. }
| Instruction::Apply { .. }
| Instruction::Fmove { .. }
| Instruction::Fconv { .. }
| Instruction::Fadd { .. }
| Instruction::Fsub { .. }
| Instruction::Fmul { .. }
| Instruction::Fdiv { .. }
| Instruction::Fnegate { .. }
| Instruction::PutList { .. }
| Instruction::GetList { .. }
| Instruction::GetHd { .. }
| Instruction::GetTl { .. }
| Instruction::PutTuple2 { .. }
| Instruction::GetTupleElement { .. }
| Instruction::BinaryOp { .. }
| Instruction::MapOp { .. }
| Instruction::Line { .. }
| Instruction::Allocate { .. }
| Instruction::AllocateHeap { .. }
| Instruction::AllocateZero { .. }
| Instruction::Deallocate { .. }
| Instruction::TestHeap { .. }
| Instruction::InitYregs { .. }
| Instruction::Trim { .. }
| Instruction::CallLast { .. }
| Instruction::CallExtLast { .. }
| Instruction::ApplyLast { .. }
| Instruction::CallFun2 { .. }
| Instruction::FuncInfo { .. } => Coverage::Supported,
Instruction::SelectTupleArity { .. } => Coverage::RejectedIncremental {
reason: "wave 2: SelectTupleArity (sibling of SelectVal)",
},
Instruction::Catch { .. }
| Instruction::CatchEnd { .. }
| Instruction::TryCaseEnd { .. }
| Instruction::Raise { .. }
| Instruction::RawRaise
| Instruction::BuildStacktrace => Coverage::RejectedIncremental {
reason: "wave 2: exception machinery / error terminals",
},
Instruction::Badmatch { .. }
| Instruction::Badrecord { .. }
| Instruction::CaseEnd { .. }
| Instruction::IfEnd => Coverage::RejectedIncremental {
reason: "wave 2: error-raising terminals",
},
Instruction::UpdateRecord { .. } => Coverage::RejectedIncremental {
reason: "wave 2: UpdateRecord (record update over tuples)",
},
Instruction::OnLoad => Coverage::RejectedInherent {
reason: "module-lifecycle pseudo-op, not steady-state execution",
},
Instruction::NifStart => Coverage::RejectedInherent {
reason: "module-lifecycle pseudo-op, not interpreter-dispatched",
},
Instruction::Generic { .. } => Coverage::RejectedInherent {
reason: "unknown-by-construction loader escape hatch",
},
}
}
pub(crate) fn is_observable_side_effect(instruction: &Instruction) -> bool {
match instruction {
Instruction::Send
| Instruction::RemoveMessage
| Instruction::Timeout
| Instruction::RecvMarkerReserve { .. }
| Instruction::RecvMarkerBind { .. }
| Instruction::RecvMarkerClear { .. }
| Instruction::RecvMarkerUse { .. }
| Instruction::CallExt { .. }
| Instruction::CallExtOnly { .. }
| Instruction::CallExtLast { .. }
| Instruction::Apply { .. }
| Instruction::ApplyLast { .. }
| Instruction::CallFun { .. }
| Instruction::CallFun2 { .. } => true,
Instruction::Call { .. }
| Instruction::CallOnly { .. }
| Instruction::CallLast { .. }
| Instruction::LoopRec { .. }
| Instruction::LoopRecEnd { .. }
| Instruction::Wait { .. }
| Instruction::WaitTimeout { .. }
| Instruction::Label { .. }
| Instruction::FuncInfo { .. }
| Instruction::Move { .. }
| Instruction::Swap { .. }
| Instruction::Bif { .. }
| Instruction::TypeTest { .. }
| Instruction::Comparison { .. }
| Instruction::TestArity { .. }
| Instruction::IsTaggedTuple { .. }
| Instruction::SelectVal { .. }
| Instruction::SelectTupleArity { .. }
| Instruction::Jump { .. }
| Instruction::Try { .. }
| Instruction::TryEnd { .. }
| Instruction::TryCase { .. }
| Instruction::TryCaseEnd { .. }
| Instruction::Catch { .. }
| Instruction::CatchEnd { .. }
| Instruction::Return
| Instruction::Fmove { .. }
| Instruction::Fconv { .. }
| Instruction::Fadd { .. }
| Instruction::Fsub { .. }
| Instruction::Fmul { .. }
| Instruction::Fdiv { .. }
| Instruction::Fnegate { .. }
| Instruction::PutList { .. }
| Instruction::PutTuple2 { .. }
| Instruction::GetTupleElement { .. }
| Instruction::GetList { .. }
| Instruction::GetHd { .. }
| Instruction::GetTl { .. }
| Instruction::MakeFun { .. }
| Instruction::BinaryOp { .. }
| Instruction::MapOp { .. }
| Instruction::Allocate { .. }
| Instruction::AllocateHeap { .. }
| Instruction::AllocateZero { .. }
| Instruction::Deallocate { .. }
| Instruction::TestHeap { .. }
| Instruction::InitYregs { .. }
| Instruction::Trim { .. }
| Instruction::Line { .. }
| Instruction::Badmatch { .. }
| Instruction::Badrecord { .. }
| Instruction::CaseEnd { .. }
| Instruction::IfEnd
| Instruction::Raise { .. }
| Instruction::RawRaise
| Instruction::BuildStacktrace
| Instruction::OnLoad
| Instruction::NifStart
| Instruction::UpdateRecord { .. }
| Instruction::Generic { .. } => false,
}
}
pub(crate) fn is_runtime_deopt_capable(instruction: &Instruction) -> bool {
match instruction {
Instruction::Bif { .. }
| Instruction::Allocate { .. }
| Instruction::AllocateHeap { .. }
| Instruction::AllocateZero { .. }
| Instruction::Deallocate { .. }
| Instruction::TestHeap { .. }
| Instruction::Trim { .. }
| Instruction::LoopRec { .. }
| Instruction::Wait { .. }
| Instruction::WaitTimeout { .. }
| Instruction::RecvMarkerReserve { .. }
| Instruction::RecvMarkerBind { .. }
| Instruction::RecvMarkerClear { .. }
| Instruction::RecvMarkerUse { .. }
| Instruction::CallExt { .. }
| Instruction::CallExtOnly { .. }
| Instruction::CallExtLast { .. }
| Instruction::CallLast { .. }
| Instruction::CallFun { .. }
| Instruction::CallFun2 { .. }
| Instruction::Apply { .. }
| Instruction::ApplyLast { .. }
| Instruction::PutList { .. }
| Instruction::PutTuple2 { .. }
| Instruction::MakeFun { .. }
| Instruction::BinaryOp { .. }
| Instruction::Fmove { .. }
| Instruction::FuncInfo { .. } => true,
Instruction::Label { .. }
| Instruction::Line { .. }
| Instruction::Move { .. }
| Instruction::Swap { .. }
| Instruction::Jump { .. }
| Instruction::Return
| Instruction::Call { .. }
| Instruction::CallOnly { .. }
| Instruction::TypeTest { .. }
| Instruction::Comparison { .. }
| Instruction::TestArity { .. }
| Instruction::IsTaggedTuple { .. }
| Instruction::SelectVal { .. }
| Instruction::GetList { .. }
| Instruction::GetHd { .. }
| Instruction::GetTl { .. }
| Instruction::GetTupleElement { .. }
| Instruction::InitYregs { .. }
| Instruction::Send
| Instruction::RemoveMessage
| Instruction::Timeout
| Instruction::LoopRecEnd { .. }
| Instruction::MapOp { .. }
| Instruction::Fconv { .. }
| Instruction::Fadd { .. }
| Instruction::Fsub { .. }
| Instruction::Fmul { .. }
| Instruction::Fdiv { .. }
| Instruction::Fnegate { .. }
| Instruction::Try { .. }
| Instruction::TryEnd { .. }
| Instruction::TryCase { .. }
| Instruction::SelectTupleArity { .. }
| Instruction::Catch { .. }
| Instruction::CatchEnd { .. }
| Instruction::TryCaseEnd { .. }
| Instruction::Raise { .. }
| Instruction::RawRaise
| Instruction::BuildStacktrace
| Instruction::Badmatch { .. }
| Instruction::Badrecord { .. }
| Instruction::CaseEnd { .. }
| Instruction::IfEnd
| Instruction::UpdateRecord { .. }
| Instruction::OnLoad
| Instruction::NifStart
| Instruction::Generic { .. } => false,
}
}
pub(crate) fn is_no_fail_label(operand: &crate::loader::decode::Operand) -> bool {
matches!(operand, crate::loader::decode::Operand::Label(0))
}