Skip to main content

lvm_class/attribute/method/
code.rs

1use crate::ClassFormatErr;
2use crate::attribute::AttributeKind;
3use crate::constant_pool::ConstantPool;
4use common::utils::cursor::ByteCursor;
5use num_enum::TryFromPrimitive;
6
7/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.3
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum CodeAttributeInfo {
10    LineNumberTable(Vec<LineNumberEntry>),
11    LocalVariableTable(Vec<LocalVariableEntry>),
12    StackMapTable(Vec<StackMapFrame>),
13    LocalVariableTypeTable(Vec<LocalVariableTypeEntry>),
14    RuntimeVisibleTypeAnnotations,
15    RuntimeInvisibleTypeAnnotations,
16}
17
18/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.12
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct LineNumberEntry {
21    pub start_pc: u16,
22    pub line_number: u16,
23}
24
25/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.13
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct LocalVariableEntry {
28    pub start_pc: u16,
29    pub length: u16,
30    pub name_index: u16,
31    pub descriptor_index: u16,
32    pub index: u16,
33}
34
35/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.14
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct LocalVariableTypeEntry {
38    pub start_pc: u16,
39    pub length: u16,
40    pub name_index: u16,
41    pub signature_index: u16,
42    pub index: u16,
43}
44
45/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.4
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub enum StackMapFrame {
48    Same {
49        offset_delta: u16,
50    },
51    SameLocals1StackItem {
52        offset_delta: u16,
53        stack: VerificationTypeInfo,
54    },
55    SameLocals1StackItemExtended {
56        offset_delta: u16,
57        stack: VerificationTypeInfo,
58    },
59    Chop {
60        k: u8,
61        offset_delta: u16,
62    },
63    SameExtended {
64        offset_delta: u16,
65    },
66    Append {
67        k: u8,
68        offset_delta: u16,
69        locals: Vec<VerificationTypeInfo>,
70    },
71    Full {
72        offset_delta: u16,
73        locals: Vec<VerificationTypeInfo>,
74        stack: Vec<VerificationTypeInfo>,
75    },
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, TryFromPrimitive)]
79#[repr(u8)]
80pub enum VerificationTypeTag {
81    Top,
82    Integer,
83    Float,
84    Double,
85    Long,
86    Null,
87    UninitializedThis,
88    Object,
89    Uninitialized,
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub enum VerificationTypeInfo {
94    Top,
95    Integer,
96    Float,
97    Double,
98    Long,
99    Null,
100    UninitializedThis,
101    Object(u16),
102    Uninitialized(u16),
103}
104
105impl<'a> StackMapFrame {
106    pub(crate) fn read(cursor: &mut ByteCursor<'a>) -> Result<Self, ClassFormatErr> {
107        let frame_type = cursor.u8()?;
108        match frame_type {
109            0..=63 => Ok(StackMapFrame::Same {
110                offset_delta: u16::from(frame_type),
111            }),
112            64..=127 => Ok(StackMapFrame::SameLocals1StackItem {
113                offset_delta: u16::from(frame_type - 64),
114                stack: VerificationTypeInfo::read(cursor)?,
115            }),
116            247 => Ok(StackMapFrame::SameLocals1StackItemExtended {
117                offset_delta: cursor.u16()?,
118                stack: VerificationTypeInfo::read(cursor)?,
119            }),
120            248..=250 => Ok(StackMapFrame::Chop {
121                k: 251 - frame_type,
122                offset_delta: cursor.u16()?,
123            }),
124            251 => Ok(StackMapFrame::SameExtended {
125                offset_delta: cursor.u16()?,
126            }),
127            252..=254 => Ok(StackMapFrame::Append {
128                k: frame_type - 251,
129                offset_delta: cursor.u16()?,
130                locals: (0..usize::from(frame_type - 251))
131                    .map(|_| VerificationTypeInfo::read(cursor)) // -> Result<_, E>
132                    .collect::<Result<Vec<_>, _>>()?,
133            }),
134            255 => {
135                let offset_delta = cursor.u16()?;
136                let number_of_locals = cursor.u16()?;
137                let mut locals = Vec::with_capacity(number_of_locals as usize);
138                for _ in 0..number_of_locals {
139                    locals.push(VerificationTypeInfo::read(cursor)?)
140                }
141                let number_of_stack_items = cursor.u16()?;
142                let mut stack = Vec::with_capacity(number_of_stack_items as usize);
143                for _ in 0..number_of_stack_items {
144                    stack.push(VerificationTypeInfo::read(cursor)?)
145                }
146                Ok(StackMapFrame::Full {
147                    offset_delta,
148                    locals,
149                    stack,
150                })
151            }
152            other => Err(ClassFormatErr::UnknownStackFrameType(other)),
153        }
154    }
155}
156
157impl<'a> VerificationTypeInfo {
158    pub(crate) fn read(cursor: &mut ByteCursor<'a>) -> Result<Self, ClassFormatErr> {
159        let raw_tag = cursor.u8()?;
160        let frame_type: VerificationTypeTag = VerificationTypeTag::try_from_primitive(raw_tag)
161            .map_err(|_| ClassFormatErr::UnknownTag(raw_tag))?;
162        Ok(match frame_type {
163            VerificationTypeTag::Top => Self::Top,
164            VerificationTypeTag::Integer => Self::Integer,
165            VerificationTypeTag::Float => Self::Float,
166            VerificationTypeTag::Double => Self::Double,
167            VerificationTypeTag::Long => Self::Long,
168            VerificationTypeTag::Null => Self::Null,
169            VerificationTypeTag::UninitializedThis => Self::UninitializedThis,
170            VerificationTypeTag::Object => Self::Object(cursor.u16()?),
171            VerificationTypeTag::Uninitialized => Self::Uninitialized(cursor.u16()?),
172        })
173    }
174}
175
176impl<'a> CodeAttributeInfo {
177    pub(crate) fn read(
178        pool: &ConstantPool,
179        cursor: &mut ByteCursor<'a>,
180    ) -> Result<Self, ClassFormatErr> {
181        let attribute_name_index = cursor.u16()?;
182        let _attribute_length = cursor.u32()? as usize;
183
184        let attribute_kind = AttributeKind::try_from(pool.get_utf8(&attribute_name_index)?)?;
185        match attribute_kind {
186            AttributeKind::LineNumberTable => {
187                let line_number_table_length = cursor.u16()? as usize;
188                let mut line_number_table = Vec::with_capacity(line_number_table_length);
189                for _ in 0..line_number_table_length {
190                    line_number_table.push(LineNumberEntry {
191                        start_pc: cursor.u16()?,
192                        line_number: cursor.u16()?,
193                    });
194                }
195                Ok(CodeAttributeInfo::LineNumberTable(line_number_table))
196            }
197            AttributeKind::LocalVariableTable => {
198                let local_variable_table_length = cursor.u16()?;
199                let mut local_variable_table =
200                    Vec::with_capacity(local_variable_table_length as usize);
201                for _ in 0..local_variable_table_length {
202                    local_variable_table.push(LocalVariableEntry {
203                        start_pc: cursor.u16()?,
204                        length: cursor.u16()?,
205                        name_index: cursor.u16()?,
206                        descriptor_index: cursor.u16()?,
207                        index: cursor.u16()?,
208                    });
209                }
210                Ok(CodeAttributeInfo::LocalVariableTable(local_variable_table))
211            }
212            AttributeKind::LocalVariableTypeTable => {
213                let local_variable_table_type_length = cursor.u16()?;
214                let mut local_variable_type_table =
215                    Vec::with_capacity(local_variable_table_type_length as usize);
216                for _ in 0..local_variable_table_type_length {
217                    local_variable_type_table.push(LocalVariableTypeEntry {
218                        start_pc: cursor.u16()?,
219                        length: cursor.u16()?,
220                        name_index: cursor.u16()?,
221                        signature_index: cursor.u16()?,
222                        index: cursor.u16()?,
223                    });
224                }
225                Ok(CodeAttributeInfo::LocalVariableTypeTable(
226                    local_variable_type_table,
227                ))
228            }
229            AttributeKind::StackMapTable => {
230                let frames_count = cursor.u16()?;
231                let mut frames = Vec::with_capacity(frames_count as usize);
232                for _ in 0..frames_count {
233                    frames.push(StackMapFrame::read(cursor)?)
234                }
235                Ok(CodeAttributeInfo::StackMapTable(frames))
236            }
237            other => unimplemented!("{other:?}"),
238        }
239    }
240}