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<'a> MethodAttribute {
83    pub(crate) fn read(
84        pool: &ConstantPool,
85        cursor: &mut ByteCursor<'a>,
86    ) -> Result<Self, ClassFormatErr> {
87        let attr_name_idx = cursor.u16()?;
88        let _attribute_length = cursor.u32()? as usize;
89
90        let attribute_kind = AttributeKind::try_from(pool.get_utf8(&attr_name_idx)?)?;
91        match attribute_kind {
92            AttributeKind::Code => Ok(MethodAttribute::Code {
93                attr_name_idx,
94                code_attr: CodeAttribute::read(pool, cursor)?,
95            }),
96            AttributeKind::RuntimeVisibleAnnotations
97            | AttributeKind::Synthetic
98            | AttributeKind::Deprecated
99            | AttributeKind::RuntimeInvisibleAnnotations
100            | AttributeKind::Signature => Ok(MethodAttribute::Shared(SharedAttribute::read(
101                attr_name_idx,
102                attribute_kind,
103                cursor,
104            )?)),
105            AttributeKind::MethodParameters => {
106                let parameters_count = cursor.u8()? as usize;
107                let mut params = Vec::with_capacity(parameters_count);
108                for _ in 0..parameters_count {
109                    params.push(MethodParameterEntry::new(cursor.u16()?, cursor.u16()?));
110                }
111                Ok(MethodAttribute::MethodParameters {
112                    attr_name_idx,
113                    params,
114                })
115            }
116            AttributeKind::Exceptions => {
117                let number_of_exceptions = cursor.u16()?;
118                let mut exception_idx_table = Vec::with_capacity(number_of_exceptions as usize);
119                for _ in 0..number_of_exceptions {
120                    exception_idx_table.push(cursor.u16()?);
121                }
122                Ok(MethodAttribute::Exceptions {
123                    attr_name_idx,
124                    exception_idx_table,
125                })
126            }
127            AttributeKind::RuntimeVisibleParameterAnnotations => {
128                let number_of_parameters = cursor.u8()?;
129                let mut parameter_annotations = Vec::with_capacity(number_of_parameters as usize);
130                for _ in 0..number_of_parameters {
131                    let num_annotations = cursor.u16()?;
132                    let mut annotations = Vec::with_capacity(num_annotations as usize);
133                    for _ in 0..num_annotations {
134                        annotations.push(Annotation::read(cursor)?);
135                    }
136                    parameter_annotations.push(ParameterAnnotations { annotations });
137                }
138                Ok(MethodAttribute::RuntimeVisibleParameterAnnotations {
139                    attr_name_idx,
140                    annotations: parameter_annotations,
141                })
142            }
143            AttributeKind::RuntimeInvisibleParameterAnnotations => {
144                let number_of_parameters = cursor.u8()?;
145                let mut parameter_annotations = Vec::with_capacity(number_of_parameters as usize);
146                for _ in 0..number_of_parameters {
147                    let num_annotations = cursor.u16()?;
148                    let mut annotations = Vec::with_capacity(num_annotations as usize);
149                    for _ in 0..num_annotations {
150                        annotations.push(Annotation::read(cursor)?);
151                    }
152                    parameter_annotations.push(ParameterAnnotations { annotations });
153                }
154                Ok(MethodAttribute::RuntimeInvisibleParameterAnnotations {
155                    attr_name_idx,
156                    annotations: parameter_annotations,
157                })
158            }
159            other => unimplemented!("Method attribute {:?} not implemented", other),
160        }
161    }
162}
163
164impl<'a> CodeAttribute {
165    pub(crate) fn read(
166        pool: &ConstantPool,
167        cursor: &mut ByteCursor<'a>,
168    ) -> Result<Self, ClassFormatErr> {
169        let max_stack = cursor.u16()?;
170        let max_locals = cursor.u16()?;
171        let code_length = cursor.u32()? as usize;
172
173        let mut code = vec![0u8; code_length];
174        cursor.read_exact(&mut code)?;
175
176        let exception_table_length = cursor.u16()? as usize;
177        let mut exception_table = Vec::with_capacity(exception_table_length);
178        for _ in 0..exception_table_length {
179            exception_table.push(ExceptionTableEntry {
180                start_pc: cursor.u16()?,
181                end_pc: cursor.u16()?,
182                handler_pc: cursor.u16()?,
183                catch_type: cursor.u16()?,
184            });
185        }
186
187        let attributes_count = cursor.u16()? as usize;
188        let mut attributes = Vec::with_capacity(attributes_count);
189        for _ in 0..attributes_count {
190            attributes.push(CodeAttributeInfo::read(pool, cursor)?);
191        }
192
193        Ok(Self {
194            max_stack,
195            max_locals,
196            code,
197            exception_table,
198            attributes,
199        })
200    }
201}