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 CodeAttributeInfo {
193    pub fn kind(&self) -> AttributeKind {
194        match self {
195            Self::LineNumberTable { .. } => AttributeKind::LineNumberTable,
196            Self::LocalVariableTable { .. } => AttributeKind::LocalVariableTable,
197            Self::StackMapTable { .. } => AttributeKind::StackMapTable,
198            Self::LocalVariableTypeTable { .. } => AttributeKind::LocalVariableTypeTable,
199            Self::RuntimeVisibleTypeAnnotations { .. } => {
200                AttributeKind::RuntimeVisibleTypeAnnotations
201            }
202            Self::RuntimeInvisibleTypeAnnotations { .. } => {
203                AttributeKind::RuntimeInvisibleTypeAnnotations
204            }
205        }
206    }
207}
208
209impl<'a> CodeAttributeInfo {
210    pub(crate) fn read(
211        pool: &ConstantPool,
212        cursor: &mut ByteCursor<'a>,
213    ) -> Result<Self, ClassFormatErr> {
214        let attr_name_idx = cursor.u16()?;
215        let _attribute_length = cursor.u32()? as usize;
216
217        let attribute_kind = AttributeKind::try_from(pool.get_utf8(&attr_name_idx)?)?;
218        match attribute_kind {
219            AttributeKind::LineNumberTable => {
220                let line_number_table_length = cursor.u16()? as usize;
221                let mut line_number_table = Vec::with_capacity(line_number_table_length);
222                for _ in 0..line_number_table_length {
223                    line_number_table.push(LineNumberEntry {
224                        start_pc: cursor.u16()?,
225                        line_number: cursor.u16()?,
226                    });
227                }
228                Ok(CodeAttributeInfo::LineNumberTable {
229                    attr_name_idx,
230                    table: line_number_table,
231                })
232            }
233            AttributeKind::LocalVariableTable => {
234                let local_variable_table_length = cursor.u16()?;
235                let mut local_variable_table =
236                    Vec::with_capacity(local_variable_table_length as usize);
237                for _ in 0..local_variable_table_length {
238                    local_variable_table.push(LocalVariableEntry {
239                        start_pc: cursor.u16()?,
240                        length: cursor.u16()?,
241                        name_index: cursor.u16()?,
242                        descriptor_index: cursor.u16()?,
243                        index: cursor.u16()?,
244                    });
245                }
246                Ok(CodeAttributeInfo::LocalVariableTable {
247                    attr_name_idx,
248                    table: local_variable_table,
249                })
250            }
251            AttributeKind::LocalVariableTypeTable => {
252                let local_variable_table_type_length = cursor.u16()?;
253                let mut local_variable_type_table =
254                    Vec::with_capacity(local_variable_table_type_length as usize);
255                for _ in 0..local_variable_table_type_length {
256                    local_variable_type_table.push(LocalVariableTypeEntry {
257                        start_pc: cursor.u16()?,
258                        length: cursor.u16()?,
259                        name_index: cursor.u16()?,
260                        signature_index: cursor.u16()?,
261                        index: cursor.u16()?,
262                    });
263                }
264                Ok(CodeAttributeInfo::LocalVariableTypeTable {
265                    attr_name_idx,
266                    table: local_variable_type_table,
267                })
268            }
269            AttributeKind::StackMapTable => {
270                let frames_count = cursor.u16()?;
271                let mut frames = Vec::with_capacity(frames_count as usize);
272                for _ in 0..frames_count {
273                    frames.push(StackMapFrame::read(cursor)?)
274                }
275                Ok(CodeAttributeInfo::StackMapTable {
276                    attr_name_idx,
277                    table: frames,
278                })
279            }
280            other => unimplemented!("{other:?}"),
281        }
282    }
283}