Skip to content

Commit 51a2208

Browse files
committedMar 23, 2024
Refactor class file parsing
1 parent 2d6b4bc commit 51a2208

17 files changed

+800
-475
lines changed
 

‎Cargo.lock

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[workspace]
2-
members = [ "cli", "parser", "vm"]
2+
members = [ "cli", "parser", "vm"]
3+
resolver = "2"

‎cli/src/main.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
use sumatra_parser::class_file::ClassFile;
22

3+
const CLASSES: [&str; 5] = [
4+
"/home/dylan/Documents/RustProjects/sumatra/java/target/production/java/Main.class",
5+
"/home/dylan/Documents/RustProjects/sumatra/java/target/production/java/Interface.class",
6+
"/home/dylan/Documents/RustProjects/sumatra/java/target/production/java/Import.class",
7+
"/home/dylan/Documents/RustProjects/sumatra/java/target/production/java/Simple.class",
8+
"/home/dylan/Documents/RustProjects/sumatra/java/target/production/java/Taco.class",
9+
];
310
fn main() {
4-
let class_file = ClassFile::parse_class(
5-
"/home/dylan/Documents/RustProjects/sumatra/java/target/production/java/Main.class",
6-
)
7-
.unwrap();
11+
// let class_file = ClassFile::parse_class(
12+
// "/home/dylan/Documents/RustProjects/sumatra/java/target/production/java/Simple.class",
13+
// )
14+
// .unwrap();
15+
// println!("{:#?}", class_file);
816

9-
println!("=========== Parsed .class file ===========");
10-
println!("{:#?}", class_file);
17+
18+
for class in CLASSES {
19+
println!();
20+
println!("Parsing: {class}");
21+
println!();
22+
println!("{:#?}", ClassFile::parse_class(class).unwrap());
23+
}
1124
}

‎parser/src/annotation.rs

+82-10
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,94 @@
1+
use anyhow::{Result, bail};
2+
use crate::annotation::TypeTarget::{Catch, Empty, FormalParameter, LocalVar, Offset, SuperType, Throws, TypeArgument, TypeParameter, TypeParameterBound};
3+
14
// TODO elaborate with documentation from spec
2-
#[derive(Debug)]
5+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
36
pub struct Annotation {
4-
pub type_index: u16,
7+
pub type_index: usize,
58
pub value_pairs: Vec<ElementPairs>,
69
}
710
// TODO elaborate with documentation from spec
8-
#[derive(Debug)]
9-
pub struct ElementPairs(pub u16, pub ElementValue);
11+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
12+
pub struct ElementPairs(pub usize, pub ElementValue);
1013

1114
// TODO elaborate with documentation from spec
12-
#[derive(Debug)]
15+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1316
pub enum ElementValue {
14-
ConstIndex(u16),
15-
EnumConst(u16, u16),
16-
ClassIndex(u16),
17+
ConstIndex(usize),
18+
EnumConst(usize, usize),
19+
ClassIndex(usize),
1720
AnnotationValue(Annotation),
1821
Array(Vec<ElementValue>),
1922
}
2023

21-
#[derive(Debug)]
22-
pub struct ParameterAnnotations(Vec<Annotation>);
24+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
25+
pub struct TypeAnnotation {
26+
pub type_target: TypeTarget,
27+
pub type_path: TypePath,
28+
pub type_index: usize,
29+
pub value_pairs: Vec<ElementPairs>,
30+
}
31+
32+
// TODO The arguments may be unnecessary but different target
33+
// types meaning different things in different contexts despite
34+
// mapping to the same variant.
35+
// https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.20
36+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
37+
pub enum TypeTarget {
38+
TypeParameter {
39+
value: u8,
40+
type_param_index: usize
41+
},
42+
SuperType {
43+
value: u8,
44+
supertype_index: usize,
45+
},
46+
TypeParameterBound { value: u8, type_parameter_index: usize, bound_index: usize },
47+
Empty(u8),
48+
FormalParameter {
49+
value: u8,
50+
formal_param_index: usize
51+
},
52+
Throws {
53+
value: u8,
54+
throws_type_index: usize
55+
},
56+
LocalVar {
57+
value: u8,
58+
target_table: LocalVarTargetTable
59+
},
60+
Catch {
61+
value: u8,
62+
exception_table_index: usize
63+
},
64+
Offset {
65+
value: u8,
66+
offset: u16
67+
},
68+
TypeArgument {
69+
value: u8,
70+
type_arg_index: usize
71+
},
72+
}
73+
74+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
75+
pub struct LocalVarTargetTable(pub Vec<LocalVarTargetTableEntry>);
76+
77+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
78+
pub struct LocalVarTargetTableEntry {
79+
pub start_pc: u16,
80+
pub length: u16,
81+
pub index: usize,
82+
}
83+
84+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
85+
pub struct TypePath(pub Vec<TypePathEntry>);
86+
87+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
88+
pub struct TypePathEntry {
89+
pub type_path_kind: u8,
90+
pub type_arg_index: usize
91+
}
92+
93+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
94+
pub struct ParameterAnnotation(pub Vec<Annotation>);

‎parser/src/attribute.rs

+168-120
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use anyhow::bail;
2+
use std::{iter::Empty, path::Path};
23

34
use crate::{
4-
annotation::{Annotation, ParameterAnnotations},
5+
annotation::{Annotation, ElementPairs, ParameterAnnotation, TypeAnnotation},
56
flags::{ExportFlags, InnerClassAccessFlags, ModuleFlags, OpenFlags, RequiresFlags},
67
instruction::Instruction,
78
type_verification::VType,
@@ -19,7 +20,7 @@ pub(crate) mod attr_constants {
1920
pub(crate) const SYNTHETIC: &[u8] = b"Synthetic";
2021
pub(crate) const SIGNATURE: &[u8] = b"Signature";
2122
pub(crate) const SOURCE_FILE: &[u8] = b"SourceFile";
22-
pub(crate) const SOURCE_DEBUG_EXTENSION: &[u8] = b"SourceDebugExtension";
23+
pub(crate) const SOURCE_DEBUG_EXTENSION: &[u8] = b"SourceDebug, Clone, Eq, PartialEqExtension";
2324
pub(crate) const LINE_NUMBER_TABLE: &[u8] = b"LineNumberTable";
2425
pub(crate) const LOCAL_VARIABLE_TABLE: &[u8] = b"LocalVariableTable";
2526
pub(crate) const LOCAL_VARIABLE_TYPE_TABLE: &[u8] = b"LocalVariableTypeTable";
@@ -42,130 +43,160 @@ pub(crate) mod attr_constants {
4243
pub(crate) const RECORD: &[u8] = b"Record";
4344
}
4445

46+
// TODO Delete Attribute when everything compiles without it.
47+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
48+
pub struct Attribute;
4549
/// Attributes are used in the [`crate::class_file::ClassFile`],
4650
/// [`crate::field::Field`], [`crate::method::Method`], Code_attribute, and
4751
/// record_component_info structures of the class file format
48-
#[derive(Debug)]
49-
pub enum Attribute {
50-
///The [`Attribute::ConstantValue`] attribute is a fixed-length attribute
51-
/// in the attributes table of a field_info structure. A
52-
/// [`Attribute::ConstantValue`] attribute represents the value of a
53-
/// constant expression. https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.5
54-
/// https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.29
55-
ConstantValue {
56-
attribute_name_index: u16,
57-
attribute_info: Vec<Attribute>,
58-
},
59-
/// The [`Attribute::Code`] attribute is a variable-length attribute in the
60-
/// attributes table of a [`crate::method::Method`] structure. A
61-
/// [`Attribute::Code`] attribute contains the Java Virtual Machine
62-
/// instructions and auxiliary information for a method, including an
63-
/// instance initialization method and a class or interface initialization
64-
/// method. https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html#jvms-2.9.1
65-
/// https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html#jvms-2.9.2
66-
Code {
67-
max_stack: u16,
68-
max_locals: u16,
69-
code: Vec<Instruction>,
70-
exception_table: Vec<Exception>,
71-
attributes: Vec<Attribute>,
72-
},
73-
/// The [`Attribute::StackMapTable`] attribute is a variable-length
74-
/// attribute in the attributes table of a [`Attribute::Code`]
75-
/// attribute. A [`Attribute::StackMapTable`] attribute is used during
76-
/// the process of verification by type checking. https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.3
77-
/// https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.10.1
78-
StackMapTable(Vec<StackMapFrame>),
79-
Exceptions(Vec<u16>),
80-
InnerClasses(Vec<InnerClassInfo>),
81-
EnclosingMethod {
82-
class_index: u16,
83-
method_index: u16,
84-
},
85-
Synthetic,
86-
Signature,
87-
SourceFile(u16),
88-
SourceDebugExtension(Vec<u8>),
89-
LineNumberTable(Vec<LineNumberTableEntry>),
90-
LocalVariableTable(Vec<LocalVarTableEntry>),
91-
LocalVariableTypeTable(Vec<LocalVarTypeEntry>),
92-
Deprecated,
93-
RuntimeVisibleAnnotations(Vec<Annotation>),
94-
RuntimeInvisibleAnnotations(Vec<Annotation>),
95-
RuntimeVisibleParameterAnnotations(Vec<ParameterAnnotations>),
96-
RuntimeInvisibleParameterAnnotations {
97-
attribute_name_index: u16,
98-
attributes: Vec<Attribute>,
99-
},
100-
RuntimeVisibleTypeAnnotations {
101-
attribute_name_index: u16,
102-
attributes: Vec<Attribute>,
103-
},
104-
RuntimeInvisibleTypeAnnotations {
105-
attribute_name_index: u16,
106-
attributes: Vec<Attribute>,
107-
},
108-
AnnotationDefault {
109-
attribute_name_index: u16,
110-
attributes: Vec<Attribute>,
111-
},
112-
BootstrapMethods(Vec<BootstrapMethod>),
113-
MethodParameters {
114-
attribute_name_index: u16,
115-
attributes: Vec<Attribute>,
116-
},
117-
Module {
118-
module_name_index: u16,
119-
module_flags: ModuleFlags,
120-
module_ver_index: u16,
121-
requires: Vec<Requires>,
122-
exports: Vec<Exports>,
123-
opens: Vec<Opens>,
124-
uses: Vec<u16>,
125-
provides: Vec<Provides>,
126-
},
127-
ModulePackages(Vec<u16>),
128-
ModuleMainClass(u16),
129-
NestHost(u16),
130-
NestMembers(Vec<u16>),
131-
Record(Vec<RecordComponent>),
132-
PermittedSubclasses(Vec<u16>),
133-
Custom(Vec<u8>),
52+
53+
///The [`Attribute::ConstantValue`] attribute is a fixed-length attribute
54+
/// in the attributes table of a field_info structure. A
55+
/// [`Attribute::ConstantValue`] attribute represents the value of a
56+
/// constant expression. https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.5
57+
/// https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.29
58+
59+
/// The [`Attribute::StackMapTable`] attribute is a variable-length
60+
/// attribute in the attributes table of a [`Attribute::Code`]
61+
/// attribute. A [`Attribute::StackMapTable`] attribute is used during
62+
/// the process of verification by type checking. https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.3
63+
/// https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.10.1
64+
65+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
66+
pub struct ClassFileAttributes {
67+
pub source_file: SourceFile,
68+
pub inner_classes: InnerClasses,
69+
pub enclosing_method: EnclosingMethod,
70+
pub source_debug_extension: SourceDebugExtension,
71+
pub synthetic: bool,
72+
pub signature: String,
73+
pub bootstrap_methods: BootstrapMethods,
74+
pub module: Module,
75+
pub module_packages: ModulePackages,
76+
pub module_main_class: ModuleMainClass,
77+
pub nest_host: NestHost,
78+
pub nest_members: NestMembers,
79+
pub record: Record,
80+
pub permitted_subclasses: PermittedSubclasses,
81+
}
82+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
83+
pub struct StackMapTable(pub Vec<StackMapFrame>);
84+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
85+
pub struct Exceptions(pub Vec<u16>);
86+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
87+
pub struct InnerClasses(pub Vec<InnerClassInfo>);
88+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
89+
pub struct EnclosingMethod {
90+
pub class_index: usize,
91+
pub method_index: usize,
13492
}
93+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
94+
pub struct Synthetic;
95+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
96+
pub struct Signature(pub u16);
97+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
98+
pub struct SourceFile(pub usize);
99+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
100+
pub struct SourceDebugExtension(pub Vec<u8>);
101+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
102+
pub struct LineNumberTable(pub Vec<LineNumberTableEntry>);
103+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
104+
pub struct LocalVariableTable(pub Vec<LocalVarTableEntry>);
105+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
106+
pub struct LocalVariableTypeTable(pub Vec<LocalVarTypeEntry>);
107+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
108+
pub struct Deprecated;
109+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
110+
pub struct AnnotationDefault {
111+
pub attribute_name_index: usize,
112+
pub attributes: Vec<u8>,
113+
}
114+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
115+
pub struct BootstrapMethods(pub Vec<BootstrapMethod>);
116+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
117+
pub struct MethodParameters {
118+
pub attribute_name_index: usize,
119+
pub attributes: Vec<Attribute>,
120+
}
121+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
122+
pub struct Module {
123+
pub module_name_index: usize,
124+
pub module_flags: ModuleFlags,
125+
pub module_ver_index: usize,
126+
pub requires: Vec<Requires>,
127+
pub exports: Vec<Exports>,
128+
pub opens: Vec<Opens>,
129+
pub uses: Vec<usize>,
130+
pub provides: Vec<Provides>,
131+
}
132+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
133+
pub struct ModulePackages(pub Vec<usize>);
134+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
135+
pub struct ModuleMainClass(pub usize);
136+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
137+
pub struct NestHost(pub usize);
138+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
139+
pub struct NestMembers(pub Vec<usize>);
140+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
141+
pub struct Record(pub Vec<RecordComponent>);
142+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
143+
pub struct PermittedSubclasses(pub Vec<usize>);
144+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
145+
pub struct Custom(pub Vec<u8>);
135146

136-
#[derive(Debug)]
147+
/// The [`Attribute::Code`] attribute is a variable-length attribute in the
148+
/// attributes table of a [`crate::method::Method`] structure. A
149+
/// [`Attribute::Code`] attribute contains the Java Virtual Machine
150+
/// instructions and auxiliary information for a method, including an
151+
/// instance initialization method and a class or interface initialization
152+
/// method. https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html#jvms-2.9.1
153+
/// https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html#jvms-2.9.2
154+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
155+
pub struct Code {
156+
pub max_stack: u16,
157+
pub max_locals: u16,
158+
pub code: Vec<Instruction>,
159+
pub exception_table: Vec<Exception>,
160+
pub line_number_table: LineNumberTable,
161+
pub local_var_table: LocalVariableTable,
162+
pub stack_map_table: StackMapTable,
163+
pub local_var_type_table: LocalVariableTypeTable,
164+
pub attributes: Vec<u8>,
165+
}
166+
167+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
137168
pub struct Exception {
138169
pub start_pc: u16,
139170
pub end_pc: u16,
140171
pub handler_pc: u16,
141172
pub catch_type: u16,
142173
}
143174

144-
#[derive(Debug)]
175+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
145176
pub struct LineNumberTableEntry {
146177
pub start_pc: u16,
147178
pub line_number: u16,
148179
}
149180

150-
#[derive(Debug)]
181+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
151182
pub struct LocalVarTableEntry {
152183
pub start_pc: u16,
153184
pub len: u16,
154-
pub name_index: u16,
155-
pub descriptor_index: u16,
156-
pub index: u16,
185+
pub name_index: usize,
186+
pub descriptor_index: usize,
187+
pub index: usize,
157188
}
158189

159-
#[derive(Debug)]
190+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
160191
pub struct LocalVarTypeEntry {
161192
pub start_pc: u16,
162193
pub len: u16,
163-
pub name_index: u16,
164-
pub signature_index: u16,
165-
pub index: u16,
194+
pub name_index: usize,
195+
pub signature_index: usize,
196+
pub index: usize,
166197
}
167198

168-
#[derive(Debug)]
199+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
169200
pub enum StackMapFrame {
170201
SameFrame,
171202
SameLocals,
@@ -178,63 +209,80 @@ pub enum StackMapFrame {
178209
locals: Vec<VType>,
179210
stack: Vec<VType>,
180211
},
212+
#[default]
213+
Invalid,
181214
}
182215

183-
#[derive(Debug)]
216+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
184217
pub struct InnerClassInfo {
185-
pub inner_class_info_index: u16,
186-
pub outer_class_info_index: u16,
187-
pub inner_name_index: u16,
218+
pub inner_class_info_index: usize,
219+
pub outer_class_info_index: usize,
220+
pub inner_name_index: usize,
188221
pub inner_class_access_flags: InnerClassAccessFlags,
189222
}
190223

191-
#[derive(Debug)]
224+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
192225
pub struct BootstrapMethod {
193226
pub btstr_mthd_ref: u16,
194227
pub btstr_args: Vec<u16>,
195228
}
196229

197-
#[derive(Debug)]
230+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
198231
pub struct Requires {
199-
pub requires_index: u16,
232+
pub requires_index: usize,
200233
pub requires_flags: RequiresFlags,
201-
pub requires_ver_index: u16,
234+
pub requires_ver_index: usize,
202235
}
203236

204-
#[derive(Debug)]
237+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
205238
pub struct Exports {
206-
pub exports_index: u16,
239+
pub exports_index: usize,
207240
pub exports_flags: ExportFlags,
208-
pub exports_to_index: Vec<u16>,
241+
pub exports_to_index: Vec<usize>,
209242
}
210243

211-
#[derive(Debug)]
244+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
212245
pub struct Opens {
213-
pub opens_index: u16,
246+
pub opens_index: usize,
214247
pub opens_flags: OpenFlags,
215248
pub opens_to_index: Vec<u16>,
216249
}
217250

218-
#[derive(Debug)]
251+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
219252
pub struct Provides {
220-
pub provides_index: u16,
221-
pub provides_with_index: Vec<u16>,
253+
pub provides_index: usize,
254+
pub provides_with_index: Vec<usize>,
222255
}
223256

224-
#[derive(Debug)]
257+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
225258
pub struct RecordComponent {
226-
pub name_index: u16,
227-
pub descriptor_index: u16,
228-
pub attributes: Vec<Attribute>,
259+
pub name_index: usize,
260+
pub descriptor_index: usize,
261+
pub runtime_annotations: Vec<RuntimeAnnotation>,
229262
}
230263

231264
/// Used to tell parsers if the attributes being parsed are for a
232265
/// Class | Interface | Record.
233-
#[derive(Debug)]
266+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
234267
pub enum ClassType {
235268
Class,
236269
Interface,
237270
Record,
271+
#[default]
272+
Invalid,
273+
}
274+
275+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
276+
pub enum RuntimeAnnotation {
277+
#[default]
278+
Invalid,
279+
RuntimeVisibleAnnotations(Vec<Annotation>),
280+
RuntimeInvisibleAnnotations(Vec<Annotation>),
281+
RuntimeVisibleParameterAnnotations(Vec<ParameterAnnotation>),
282+
RuntimeInvisibleParameterAnnotations(Vec<ParameterAnnotation>),
283+
RuntimeVisibleTypeAnnotations(Vec<TypeAnnotation>),
284+
RuntimeInvisibleTypeAnnotations(Vec<TypeAnnotation>),
285+
AnnotationDefault(ElementPairs),
238286
}
239287

240288
impl TryFrom<u8> for StackMapFrame {

‎parser/src/class_file.rs

+34-36
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@ use bitflags::Flags;
55
use byteorder::ReadBytesExt;
66

77
use crate::{
8-
attribute::Attribute
9-
,
10-
class_reader::ClassReader
11-
,
8+
attribute::{
9+
Attribute, BootstrapMethods, ClassFileAttributes, EnclosingMethod, InnerClasses, Module,
10+
ModuleMainClass, ModulePackages, PermittedSubclasses, Record, SourceDebugExtension,
11+
},
12+
class_reader::ClassReader,
1213
constant_pool::ConstantPool,
1314
field::Field,
1415
flags::ClassAccessFlags,
1516
method::Method,
1617
};
1718

1819
/// Represents the format of a JVM `.class` file
19-
#[derive(Debug)]
20+
#[derive(Debug, Default, Clone)]
2021
pub struct ClassFile {
21-
pub magic: u32,
2222
pub minor_version: u16,
2323
pub major_version: u16,
2424
pub cp: ConstantPool,
@@ -28,53 +28,51 @@ pub struct ClassFile {
2828
pub interfaces: Vec<u16>,
2929
pub fields: Vec<Field>,
3030
pub methods: Vec<Method>,
31-
pub attributes: Vec<Attribute>,
31+
pub attributes: ClassFileAttributes,
3232
}
3333

3434
impl ClassFile {
3535
const MAGIC: u32 = 0xCAFEBABE;
3636

3737
pub fn parse_class<P: AsRef<Path>>(path: P) -> Result<ClassFile> {
38+
let mut class_file = ClassFile::default();
39+
3840
let mut cr = ClassReader::new(path.as_ref())?;
3941

40-
let magic = cr.read_u32()?;
41-
if magic != ClassFile::MAGIC {
42-
bail!("Invalid class file.".to_string());
43-
}
44-
let minor_version = cr.read_u16()?;
45-
let major_version = cr.read_u16()?;
42+
Self::valid_magic(&mut cr)?;
43+
class_file.minor_version = cr.read_u16()?;
44+
class_file.major_version = cr.read_u16()?;
4645
let cp = cr.parse_cp()?;
4746
let flag = cr.read_u16()?;
48-
let access_flags = ClassAccessFlags::from_bits(flag)
47+
class_file.access_flags = ClassAccessFlags::from_bits(flag)
4948
.context(format!("Invalid Class access flag: {flag}."))?;
50-
let this_class = cr.read_u16()?;
51-
let super_class = cr.read_u16()?;
52-
let interfaces = cr.parse_interfaces()?;
53-
let fields = cr.parse_fields(&cp)?;
49+
class_file.this_class = cr.read_u16()?;
50+
class_file.super_class = cr.read_u16()?;
51+
class_file.interfaces = cr.parse_interfaces()?;
52+
class_file.fields = cr.parse_fields(&cp)?;
5453
let method_count = cr.read_u16()? as usize;
55-
let methods = cr.parse_methods(&cp, method_count, major_version, minor_version)?;
54+
class_file.methods = cr.parse_methods(
55+
&cp,
56+
method_count,
57+
class_file.major_version,
58+
class_file.minor_version,
59+
)?;
5660
let attributes_count = cr.read_u16()? as usize;
57-
let attributes = cr.parse_class_attr(
61+
cr.parse_class_attr(
5862
&cp,
5963
attributes_count,
60-
!access_flags.contains(ClassAccessFlags::FINAL),
64+
!class_file.access_flags.contains(ClassAccessFlags::FINAL),
65+
&mut class_file.attributes,
6166
)?;
62-
Ok(ClassFile {
63-
magic,
64-
minor_version,
65-
major_version,
66-
cp,
67-
access_flags,
68-
this_class,
69-
super_class,
70-
interfaces,
71-
fields,
72-
methods,
73-
attributes,
74-
})
67+
Ok(class_file)
7568
}
7669

77-
pub fn get_utf8(&self, index: usize) -> Result<&str> {
78-
self.cp.get_utf8(index)
70+
fn valid_magic(cr: &mut ClassReader) -> Result<()> {
71+
let magic = cr.read_u32()?;
72+
if magic != ClassFile::MAGIC {
73+
bail!("Invalid class file.".to_string());
74+
}
75+
Ok(())
7976
}
77+
pub fn get_utf8(&self, index: usize) -> Result<&str> { self.cp.get_utf8(index) }
8078
}

‎parser/src/class_reader.rs

+451-273
Large diffs are not rendered by default.

‎parser/src/constant.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/// All possible `constant_pool` entries.
2-
#[derive(Debug)]
2+
#[derive(Debug, Default, PartialEq, Clone)]
33
pub enum Constant {
4+
#[default]
45
Dummy,
56
UTF8(String),
67
Integer(i32),

‎parser/src/constant_pool.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ use anyhow::{bail, Result};
44

55
use crate::constant::{Constant, Constant::UTF8};
66

7-
#[derive(Debug)]
7+
#[derive(Debug, Default, PartialEq, Clone)]
88
pub struct ConstantPool(Vec<Constant>);
99

1010
impl ConstantPool {
11-
pub fn new(capacity: usize) -> Self {
12-
Self(Vec::with_capacity(capacity))
13-
}
11+
pub fn new(capacity: usize) -> Self { Self(Vec::with_capacity(capacity)) }
1412

1513
pub(crate) fn get_utf8(&self, index: usize) -> Result<&str> {
1614
match self.get(index) {
@@ -28,13 +26,9 @@ impl ConstantPool {
2826
impl Deref for ConstantPool {
2927
type Target = Vec<Constant>;
3028

31-
fn deref(&self) -> &Self::Target {
32-
&self.0
33-
}
29+
fn deref(&self) -> &Self::Target { &self.0 }
3430
}
3531

3632
impl DerefMut for ConstantPool {
37-
fn deref_mut(&mut self) -> &mut Self::Target {
38-
&mut self.0
39-
}
33+
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
4034
}

‎parser/src/field.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
use crate::{attribute::Attribute, flags::FieldAccessFlags};
1+
use crate::{attribute::RuntimeAnnotation, constant::Constant, flags::FieldAccessFlags};
22

3-
#[derive(Debug)]
3+
#[derive(Debug, Default, PartialEq, Clone)]
44
pub struct Field {
55
pub access_flags: FieldAccessFlags,
66
pub name_index: usize,
77
pub descriptor_index: usize,
8-
pub attributes: Vec<Attribute>,
8+
pub signature_index: usize,
9+
pub constant_value: Constant,
10+
pub synthetic: bool,
11+
pub deprecated: bool,
12+
pub runtime_annotations: Vec<RuntimeAnnotation>,
913
}

‎parser/src/flags.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ bitflags! {
55
to and properties of this method. The interpretation of each flag, when set, is specified in
66
https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.1-200-E.1"
77
]
8-
#[derive(Debug, Default)]
8+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
99
pub struct ClassAccessFlags: u16 {
1010
const PUBLIC = 0x0001;
1111
const FINAL = 0x0010;
@@ -24,7 +24,7 @@ bitflags! {
2424
to and properties of this method. The interpretation of each flag, when set, is specified in
2525
https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.6-200-A.1"
2626
]
27-
#[derive(Debug, Default)]
27+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
2828
pub struct MethodAccessFlags: u16 {
2929
const PUBLIC = 0x0001;
3030
const PRIVATE = 0x0002;
@@ -46,7 +46,7 @@ bitflags! {
4646
to and properties of this method. The interpretation of each flag, when set, is specified in
4747
https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.5-200-A.1"
4848
]
49-
#[derive(Debug, Default)]
49+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
5050
pub struct FieldAccessFlags: u16 {
5151
const PUBLIC = 0x0001;
5252
const PRIVATE = 0x0002;
@@ -65,7 +65,7 @@ bitflags! {
6565
to and properties of this method. The interpretation of each flag, when set, is specified in
6666
https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.6"
6767
]
68-
#[derive(Debug, Default)]
68+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
6969
pub struct InnerClassAccessFlags: u16 {
7070
const PUBLIC = 0x0001;
7171
const PRIVATE = 0x0002;
@@ -85,7 +85,7 @@ bitflags! {
8585
to and properties of this method. The interpretation of each flag, when set, is specified in
8686
https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.25"
8787
]
88-
#[derive(Debug, Default)]
88+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
8989
pub(crate) struct ModuleFlags: u16 {
9090
const OPEN = 0x0020;
9191
const SYNTHETIC = 0x1000;
@@ -98,7 +98,7 @@ bitflags! {
9898
to and properties of this method. The interpretation of each flag, when set, is specified in
9999
https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.25"
100100
]
101-
#[derive(Debug, Default)]
101+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
102102
pub(crate) struct RequiresFlags: u16 {
103103
const TRANSITIVE = 0x0020;
104104
const STATIC_PHASE = 0x0040;
@@ -112,7 +112,7 @@ bitflags! {
112112
to and properties of this method. The interpretation of each flag, when set, is specified in
113113
https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.25"
114114
]
115-
#[derive(Debug, Default)]
115+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
116116
pub struct ExportFlags: u16 {
117117
const SYNTHETIC = 0x1000;
118118
const MANDATED = 0x8000;
@@ -124,7 +124,7 @@ bitflags! {
124124
to and properties of this method. The interpretation of each flag, when set, is specified in
125125
https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.25"
126126
]
127-
#[derive(Debug, Default)]
127+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
128128
pub struct OpenFlags: u16 {
129129
const SYNTHETIC = 0x1000;
130130
const MANDATED = 0x8000;

‎parser/src/instruction.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
},
1212
};
1313

14-
#[derive(Debug, Clone)]
14+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1515
pub enum Instruction {
1616
AaLoad,
1717
AaStore,
@@ -438,6 +438,7 @@ impl Instruction {
438438
195 => MonitorExit,
439439
197 => MultiaNewArray(cursor.read_u16()?, cursor.read_u8()?),
440440
188 => NewArray(ArrayType::try_from(cursor.read_u8()?)?),
441+
187 => New(cursor.read_u16()?),
441442
0 => Nop,
442443
87 => Pop,
443444
88 => Pop2,
@@ -745,7 +746,7 @@ impl TryFrom<u8> for Instruction {
745746
}
746747
}
747748

748-
#[derive(Debug, Clone)]
749+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
749750
pub enum ArrayType {
750751
Boolean,
751752
Char,

‎parser/src/method.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
use crate::{attribute::Attribute, flags::MethodAccessFlags};
1+
use crate::{
2+
attribute::{Attribute, Code, Exceptions, RuntimeAnnotation},
3+
flags::MethodAccessFlags,
4+
};
25

3-
#[derive(Debug)]
6+
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
47
pub struct Method {
58
pub access_flags: MethodAccessFlags,
69
pub name_index: usize,
710
pub descriptor_index: usize,
11+
pub signature_index: usize,
12+
pub code: Code,
13+
pub exceptions: Exceptions,
14+
pub runtime_annotations: Vec<RuntimeAnnotation>,
815
pub attributes: Vec<Attribute>,
916
}

‎parser/src/type_verification.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anyhow::{bail, Result};
22

3-
#[derive(Debug)]
3+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
44
pub enum VType {
55
Top,
66
Integer,

‎rustfmt.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
imports_granularity = "Crate"
22
reorder_imports = true
33
reorder_modules = true
4-
wrap_comments = true
4+
wrap_comments = true
5+
fn_single_line = true

‎vm/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7+
sumatra_parser = { path = "../parser" }

‎vm/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
1+
mod class;
2+
mod class_loader;
3+
mod code;
4+
mod method;

0 commit comments

Comments
 (0)
Please sign in to comment.