lvm_class/attribute/method/
code.rs1use crate::ClassFormatErr;
2use crate::attribute::AttributeKind;
3use crate::constant_pool::ConstantPool;
4use lvm_common::utils::cursor::ByteCursor;
5use num_enum::TryFromPrimitive;
6
7#[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#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct LineNumberEntry {
37 pub start_pc: u16,
38 pub line_number: u16,
39}
40
41#[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#[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#[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)) .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}