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 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}