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 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(CodeAttribute),
49    Exceptions(Vec<u16>),
50    RuntimeVisibleParameterAnnotations(Vec<ParameterAnnotations>),
51    RuntimeInvisibleParameterAnnotations(Vec<ParameterAnnotations>),
52    AnnotationsDefault,
53    MethodParameters(Vec<MethodParameterEntry>),
54}
55
56impl MethodParameterEntry {
57    pub(crate) fn new(name_index: u16, access_flags: u16) -> Self {
58        Self {
59            name_index,
60            access_flags,
61        }
62    }
63}
64
65impl<'a> MethodAttribute {
66    pub(crate) fn read(
67        pool: &ConstantPool,
68        cursor: &mut ByteCursor<'a>,
69    ) -> Result<Self, ClassFormatErr> {
70        let attribute_name_index = cursor.u16()?;
71        let _attribute_length = cursor.u32()? as usize;
72
73        let attribute_kind = AttributeKind::try_from(pool.get_utf8(&attribute_name_index)?)?;
74        match attribute_kind {
75            AttributeKind::Code => Ok(MethodAttribute::Code(CodeAttribute::read(pool, cursor)?)),
76            AttributeKind::RuntimeVisibleAnnotations
77            | AttributeKind::Synthetic
78            | AttributeKind::Deprecated
79            | AttributeKind::RuntimeInvisibleAnnotations
80            | AttributeKind::Signature => Ok(MethodAttribute::Shared(SharedAttribute::read(
81                attribute_kind,
82                cursor,
83            )?)),
84            AttributeKind::MethodParameters => {
85                let parameters_count = cursor.u8()? as usize;
86                let mut parameters = Vec::with_capacity(parameters_count);
87                for _ in 0..parameters_count {
88                    parameters.push(MethodParameterEntry::new(cursor.u16()?, cursor.u16()?));
89                }
90                Ok(MethodAttribute::MethodParameters(parameters))
91            }
92            AttributeKind::Exceptions => {
93                let number_of_exceptions = cursor.u16()?;
94                let mut exception_index_table = Vec::with_capacity(number_of_exceptions as usize);
95                for _ in 0..number_of_exceptions {
96                    exception_index_table.push(cursor.u16()?);
97                }
98                Ok(MethodAttribute::Exceptions(exception_index_table))
99            }
100            AttributeKind::RuntimeVisibleParameterAnnotations => {
101                let number_of_parameters = cursor.u8()?;
102                let mut parameter_annotations = Vec::with_capacity(number_of_parameters as usize);
103                for _ in 0..number_of_parameters {
104                    let num_annotations = cursor.u16()?;
105                    let mut annotations = Vec::with_capacity(num_annotations as usize);
106                    for _ in 0..num_annotations {
107                        annotations.push(Annotation::read(cursor)?);
108                    }
109                    parameter_annotations.push(ParameterAnnotations { annotations });
110                }
111                Ok(MethodAttribute::RuntimeVisibleParameterAnnotations(
112                    parameter_annotations,
113                ))
114            }
115            AttributeKind::RuntimeInvisibleParameterAnnotations => {
116                let number_of_parameters = cursor.u8()?;
117                let mut parameter_annotations = Vec::with_capacity(number_of_parameters as usize);
118                for _ in 0..number_of_parameters {
119                    let num_annotations = cursor.u16()?;
120                    let mut annotations = Vec::with_capacity(num_annotations as usize);
121                    for _ in 0..num_annotations {
122                        annotations.push(Annotation::read(cursor)?);
123                    }
124                    parameter_annotations.push(ParameterAnnotations { annotations });
125                }
126                Ok(MethodAttribute::RuntimeInvisibleParameterAnnotations(
127                    parameter_annotations,
128                ))
129            }
130            other => unimplemented!("Method attribute {:?} not implemented", other),
131        }
132    }
133}
134
135impl<'a> CodeAttribute {
136    pub(crate) fn read(
137        pool: &ConstantPool,
138        cursor: &mut ByteCursor<'a>,
139    ) -> Result<Self, ClassFormatErr> {
140        let max_stack = cursor.u16()?;
141        let max_locals = cursor.u16()?;
142        let code_length = cursor.u32()? as usize;
143
144        let mut code = vec![0u8; code_length];
145        cursor.read_exact(&mut code)?;
146
147        let exception_table_length = cursor.u16()? as usize;
148        let mut exception_table = Vec::with_capacity(exception_table_length);
149        for _ in 0..exception_table_length {
150            exception_table.push(ExceptionTableEntry {
151                start_pc: cursor.u16()?,
152                end_pc: cursor.u16()?,
153                handler_pc: cursor.u16()?,
154                catch_type: cursor.u16()?,
155            });
156        }
157
158        let attributes_count = cursor.u16()? as usize;
159        let mut attributes = Vec::with_capacity(attributes_count);
160        for _ in 0..attributes_count {
161            attributes.push(CodeAttributeInfo::read(pool, cursor)?);
162        }
163
164        Ok(Self {
165            max_stack,
166            max_locals,
167            code,
168            exception_table,
169            attributes,
170        })
171    }
172}