Skip to main content

lvm_class/attribute/method/
mod.rs

1use crate::ClassFormatErr;
2use crate::attribute::{Annotation, AttributeKind, SharedAttribute};
3use crate::constant_pool::ConstantPool;
4use lvm_common::utils::cursor::ByteCursor;
5
6pub mod code;
7
8pub use code::{
9    CodeAttributeInfo, LineNumberEntry, LocalVariableEntry, LocalVariableTypeEntry, StackMapFrame,
10    VerificationTypeInfo, VerificationTypeTag,
11};
12
13/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.3
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct ExceptionTableEntry {
16    pub start_pc: u16,
17    pub end_pc: u16,
18    pub handler_pc: u16,
19    pub catch_type: u16,
20}
21
22/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7.3
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct CodeAttribute {
25    pub max_stack: u16,
26    pub max_locals: u16,
27    pub code: Vec<u8>,
28    pub exception_table: Vec<ExceptionTableEntry>,
29    pub attributes: Vec<CodeAttributeInfo>,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct MethodParameterEntry {
34    pub name_index: u16,
35    pub access_flags: u16,
36}
37
38/// Parameter annotations for a single parameter
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct ParameterAnnotations {
41    pub annotations: Vec<Annotation>,
42}
43
44/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.7
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum MethodAttribute {
47    Shared(SharedAttribute),
48    Code {
49        attr_name_idx: u16,
50        code_attr: CodeAttribute,
51    },
52    Exceptions {
53        attr_name_idx: u16,
54        exception_idx_table: Vec<u16>,
55    },
56    RuntimeVisibleParameterAnnotations {
57        attr_name_idx: u16,
58        annotations: Vec<ParameterAnnotations>,
59    },
60    RuntimeInvisibleParameterAnnotations {
61        attr_name_idx: u16,
62        annotations: Vec<ParameterAnnotations>,
63    },
64    AnnotationsDefault {
65        attr_name_idx: u16,
66    },
67    MethodParameters {
68        attr_name_idx: u16,
69        params: Vec<MethodParameterEntry>,
70    },
71}
72
73impl MethodParameterEntry {
74    pub(crate) fn new(name_index: u16, access_flags: u16) -> Self {
75        Self {
76            name_index,
77            access_flags,
78        }
79    }
80}
81
82impl MethodAttribute {
83    pub fn kind(&self) -> AttributeKind {
84        match self {
85            Self::Shared(attr) => attr.kind(),
86            Self::Code { .. } => AttributeKind::Code,
87            Self::Exceptions { .. } => AttributeKind::Exceptions,
88            Self::RuntimeVisibleParameterAnnotations { .. } => {
89                AttributeKind::RuntimeVisibleParameterAnnotations
90            }
91            Self::RuntimeInvisibleParameterAnnotations { .. } => {
92                AttributeKind::RuntimeInvisibleParameterAnnotations
93            }
94            Self::AnnotationsDefault { .. } => AttributeKind::AnnotationDefault,
95            Self::MethodParameters { .. } => AttributeKind::MethodParameters,
96        }
97    }
98}
99
100impl<'a> MethodAttribute {
101    pub(crate) fn read(
102        pool: &ConstantPool,
103        cursor: &mut ByteCursor<'a>,
104    ) -> Result<Self, ClassFormatErr> {
105        let attr_name_idx = cursor.u16()?;
106        let _attribute_length = cursor.u32()? as usize;
107
108        let attribute_kind = AttributeKind::try_from(pool.get_utf8(&attr_name_idx)?)?;
109        match attribute_kind {
110            AttributeKind::Code => Ok(MethodAttribute::Code {
111                attr_name_idx,
112                code_attr: CodeAttribute::read(pool, cursor)?,
113            }),
114            AttributeKind::RuntimeVisibleAnnotations
115            | AttributeKind::Synthetic
116            | AttributeKind::Deprecated
117            | AttributeKind::RuntimeInvisibleAnnotations
118            | AttributeKind::Signature => Ok(MethodAttribute::Shared(SharedAttribute::read(
119                attr_name_idx,
120                attribute_kind,
121                cursor,
122            )?)),
123            AttributeKind::MethodParameters => {
124                let parameters_count = cursor.u8()? as usize;
125                let mut params = Vec::with_capacity(parameters_count);
126                for _ in 0..parameters_count {
127                    params.push(MethodParameterEntry::new(cursor.u16()?, cursor.u16()?));
128                }
129                Ok(MethodAttribute::MethodParameters {
130                    attr_name_idx,
131                    params,
132                })
133            }
134            AttributeKind::Exceptions => {
135                let number_of_exceptions = cursor.u16()?;
136                let mut exception_idx_table = Vec::with_capacity(number_of_exceptions as usize);
137                for _ in 0..number_of_exceptions {
138                    exception_idx_table.push(cursor.u16()?);
139                }
140                Ok(MethodAttribute::Exceptions {
141                    attr_name_idx,
142                    exception_idx_table,
143                })
144            }
145            AttributeKind::RuntimeVisibleParameterAnnotations => {
146                let number_of_parameters = cursor.u8()?;
147                let mut parameter_annotations = Vec::with_capacity(number_of_parameters as usize);
148                for _ in 0..number_of_parameters {
149                    let num_annotations = cursor.u16()?;
150                    let mut annotations = Vec::with_capacity(num_annotations as usize);
151                    for _ in 0..num_annotations {
152                        annotations.push(Annotation::read(cursor)?);
153                    }
154                    parameter_annotations.push(ParameterAnnotations { annotations });
155                }
156                Ok(MethodAttribute::RuntimeVisibleParameterAnnotations {
157                    attr_name_idx,
158                    annotations: parameter_annotations,
159                })
160            }
161            AttributeKind::RuntimeInvisibleParameterAnnotations => {
162                let number_of_parameters = cursor.u8()?;
163                let mut parameter_annotations = Vec::with_capacity(number_of_parameters as usize);
164                for _ in 0..number_of_parameters {
165                    let num_annotations = cursor.u16()?;
166                    let mut annotations = Vec::with_capacity(num_annotations as usize);
167                    for _ in 0..num_annotations {
168                        annotations.push(Annotation::read(cursor)?);
169                    }
170                    parameter_annotations.push(ParameterAnnotations { annotations });
171                }
172                Ok(MethodAttribute::RuntimeInvisibleParameterAnnotations {
173                    attr_name_idx,
174                    annotations: parameter_annotations,
175                })
176            }
177            other => unimplemented!("Method attribute {:?} not implemented", other),
178        }
179    }
180}
181
182impl<'a> CodeAttribute {
183    pub(crate) fn read(
184        pool: &ConstantPool,
185        cursor: &mut ByteCursor<'a>,
186    ) -> Result<Self, ClassFormatErr> {
187        let max_stack = cursor.u16()?;
188        let max_locals = cursor.u16()?;
189        let code_length = cursor.u32()? as usize;
190
191        let mut code = vec![0u8; code_length];
192        cursor.read_exact(&mut code)?;
193
194        let exception_table_length = cursor.u16()? as usize;
195        let mut exception_table = Vec::with_capacity(exception_table_length);
196        for _ in 0..exception_table_length {
197            exception_table.push(ExceptionTableEntry {
198                start_pc: cursor.u16()?,
199                end_pc: cursor.u16()?,
200                handler_pc: cursor.u16()?,
201                catch_type: cursor.u16()?,
202            });
203        }
204
205        let attributes_count = cursor.u16()? as usize;
206        let mut attributes = Vec::with_capacity(attributes_count);
207        for _ in 0..attributes_count {
208            attributes.push(CodeAttributeInfo::read(pool, cursor)?);
209        }
210
211        Ok(Self {
212            max_stack,
213            max_locals,
214            code,
215            exception_table,
216            attributes,
217        })
218    }
219}