use rust_asm::class_reader::{
StackMapFrame as RawStackMapFrame, VerificationTypeInfo as RawVerificationType,
};
use rust_asm::constant_pool::CpInfo;
use super::ConstantPoolIndex;
#[derive(Debug, Clone, Copy)]
pub struct StackMapFrame<'a> {
inner: &'a RawStackMapFrame,
constant_pool: &'a [CpInfo],
}
impl<'a> StackMapFrame<'a> {
pub(crate) const fn new(inner: &'a RawStackMapFrame, constant_pool: &'a [CpInfo]) -> Self {
Self {
inner,
constant_pool,
}
}
#[must_use]
pub const fn offset_delta(&self) -> u16 {
match self.inner {
RawStackMapFrame::SameFrame { offset_delta }
| RawStackMapFrame::SameLocals1StackItemFrame { offset_delta, .. }
| RawStackMapFrame::SameLocals1StackItemFrameExtended { offset_delta, .. }
| RawStackMapFrame::ChopFrame { offset_delta, .. }
| RawStackMapFrame::SameFrameExtended { offset_delta }
| RawStackMapFrame::AppendFrame { offset_delta, .. }
| RawStackMapFrame::FullFrame { offset_delta, .. } => *offset_delta,
}
}
#[must_use]
pub const fn kind(&self) -> StackMapFrameKind {
match self.inner {
RawStackMapFrame::SameFrame { .. } => StackMapFrameKind::Same,
RawStackMapFrame::SameLocals1StackItemFrame { .. }
| RawStackMapFrame::SameLocals1StackItemFrameExtended { .. } => {
StackMapFrameKind::SameLocalsOneStackItem
}
RawStackMapFrame::ChopFrame { k, .. } => StackMapFrameKind::Chop { count: *k },
RawStackMapFrame::SameFrameExtended { .. } => StackMapFrameKind::SameExtended,
RawStackMapFrame::AppendFrame { .. } => StackMapFrameKind::Append,
RawStackMapFrame::FullFrame { .. } => StackMapFrameKind::Full,
}
}
#[must_use]
pub fn locals(&self) -> Option<VerificationTypes<'a>> {
let values = match self.inner {
RawStackMapFrame::AppendFrame { locals, .. }
| RawStackMapFrame::FullFrame { locals, .. } => locals,
_ => return None,
};
Some(VerificationTypes::new(values, self.constant_pool))
}
#[must_use]
pub fn stack(&self) -> Option<VerificationTypes<'a>> {
match self.inner {
RawStackMapFrame::SameLocals1StackItemFrame { stack, .. }
| RawStackMapFrame::SameLocals1StackItemFrameExtended { stack, .. } => {
Some(VerificationTypes::single(stack, self.constant_pool))
}
RawStackMapFrame::FullFrame { stack, .. } => {
Some(VerificationTypes::new(stack, self.constant_pool))
}
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StackMapFrameKind {
Same,
SameLocalsOneStackItem,
Chop {
count: u8,
},
SameExtended,
Append,
Full,
}
#[derive(Debug, Clone, Copy)]
pub struct VerificationTypes<'a> {
values: &'a [RawVerificationType],
constant_pool: &'a [CpInfo],
}
impl<'a> VerificationTypes<'a> {
const fn new(values: &'a [RawVerificationType], constant_pool: &'a [CpInfo]) -> Self {
Self {
values,
constant_pool,
}
}
const fn single(value: &'a RawVerificationType, constant_pool: &'a [CpInfo]) -> Self {
Self::new(std::slice::from_ref(value), constant_pool)
}
#[must_use]
pub const fn len(&self) -> usize {
self.values.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = VerificationType<'a>> + '_ {
self.values
.iter()
.map(|value| VerificationType::from_raw(value, self.constant_pool))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerificationType<'a> {
Top,
Integer,
Float,
Long,
Double,
Null,
UninitializedThis,
Object {
internal_name: Option<&'a str>,
constant_pool_index: ConstantPoolIndex,
},
Uninitialized {
offset: u16,
},
}
impl<'a> VerificationType<'a> {
fn from_raw(value: &'a RawVerificationType, constant_pool: &'a [CpInfo]) -> Self {
match value {
RawVerificationType::Top => Self::Top,
RawVerificationType::Integer => Self::Integer,
RawVerificationType::Float => Self::Float,
RawVerificationType::Long => Self::Long,
RawVerificationType::Double => Self::Double,
RawVerificationType::Null => Self::Null,
RawVerificationType::UninitializedThis => Self::UninitializedThis,
RawVerificationType::Object { cpool_index } => Self::Object {
internal_name: class_name(constant_pool, *cpool_index),
constant_pool_index: ConstantPoolIndex::new(*cpool_index),
},
RawVerificationType::Uninitialized { offset } => {
Self::Uninitialized { offset: *offset }
}
}
}
}
fn class_name(constant_pool: &[CpInfo], index: u16) -> Option<&str> {
let CpInfo::Class { name_index } = constant_pool.get(usize::from(index))? else {
return None;
};
let CpInfo::Utf8(name) = constant_pool.get(usize::from(*name_index))? else {
return None;
};
Some(name)
}