Skip to main content

lvm_class/attribute/method/
code.rs

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