This commit is contained in:
nora 2021-07-23 21:53:40 +02:00
parent 48a7270bbb
commit b07a20566c
12 changed files with 514 additions and 158 deletions

5
.gitignore vendored
View file

@ -1 +1,6 @@
.idea
*.iml
/target /target
*.class

8
.idea/.gitignore generated vendored
View file

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/../../../../../../../:\Users\nilsh\CLionProjects\rust\coldsquare\.idea/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

11
.idea/coldsquare.iml generated
View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/discord.xml generated
View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
</component>
</project>

11
.idea/misc.xml generated
View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MavenImportPreferences">
<option name="generalSettings">
<MavenGeneralSettings>
<option name="mavenHome" value="C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.2\plugins\maven\lib\maven3" />
</MavenGeneralSettings>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Haskell Tool Stack" project-jdk-type="Haskell Tool Stack SDK" />
</project>

8
.idea/modules.xml generated
View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/coldsquare.iml" filepath="$PROJECT_DIR$/.idea/coldsquare.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View file

@ -4,9 +4,7 @@ pub struct OperandStack {
impl OperandStack { impl OperandStack {
pub fn new() -> OperandStack { pub fn new() -> OperandStack {
OperandStack { OperandStack { vec: vec![] }
vec: vec![],
}
} }
pub fn pop(&mut self) -> u32 { pub fn pop(&mut self) -> u32 {
@ -24,14 +22,12 @@ impl OperandStack {
} }
pub struct LocalVariables { pub struct LocalVariables {
vec: Vec<u32> vec: Vec<u32>,
} }
impl LocalVariables { impl LocalVariables {
pub fn new(size: usize) -> LocalVariables { pub fn new(size: usize) -> LocalVariables {
LocalVariables { LocalVariables { vec: vec![0; size] }
vec: vec![0; size]
}
} }
pub fn store(&mut self, address: u8, value: u32) { pub fn store(&mut self, address: u8, value: u32) {
@ -49,12 +45,11 @@ impl LocalVariables {
pub fn load2(&self, address: u8) -> (u32, u32) { pub fn load2(&self, address: u8) -> (u32, u32) {
(self.vec[address as usize], self.vec[address as usize + 1]) (self.vec[address as usize], self.vec[address as usize + 1])
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::model::{LocalVariables, OperandStack}; use crate::execute::model::{LocalVariables, OperandStack};
#[test] #[test]
fn operand_stack() { fn operand_stack() {

View file

@ -1,2 +1,8 @@
mod parse; use crate::parse::{ClassFile, ParseErr};
mod execute; mod execute;
mod parse;
pub fn parse_class_file(file: Vec<u8>) -> Result<ClassFile, ParseErr> {
parse::parse_class_file(file)
}

View file

@ -1,3 +1,10 @@
use coldsquare::parse_class_file;
fn main() { fn main() {
println!("Hello, world!"); let file = "primeNumberChecker.class";
let file = std::fs::read(file).unwrap();
let class_file = parse_class_file(file).unwrap();
println!("{:?}", class_file);
} }

View file

@ -1,14 +1,22 @@
use crate::parse::model::{u1, u2, u4, ClassFile, CpInfo};
mod model; mod model;
pub use model::*;
use std::path::Prefix::Verbatim;
struct ParseErr; #[derive(Debug)]
pub struct ParseErr;
pub type Result<T> = std::result::Result<T, ParseErr>;
struct Data { struct Data {
data: Vec<u1>, data: Vec<u1>,
pointer: usize, pointer: usize,
} }
pub fn parse_class_file(data: Vec<u1>) -> Result<ClassFile> {
let mut data = Data { data, pointer: 0 };
ClassFile::parse(&mut data)
}
impl From<Vec<u8>> for Data { impl From<Vec<u8>> for Data {
fn from(data: Vec<u1>) -> Self { fn from(data: Vec<u1>) -> Self {
Self { data, pointer: 0 } Self { data, pointer: 0 }
@ -16,67 +24,422 @@ impl From<Vec<u8>> for Data {
} }
impl Data { impl Data {
fn u1(&mut self) -> Result<u1, ParseErr> { fn u1(&mut self) -> Result<u1> {
let item = self.data.get(self.pointer).cloned(); let item = self.data.get(self.pointer).cloned();
self.pointer += 1; self.pointer += 1;
item.ok_or(ParseErr) item.ok_or(ParseErr)
} }
fn u2(&mut self) -> Result<u2, ParseErr> { fn u2(&mut self) -> Result<u2> {
Ok(((self.u1()? as u2) << 8) | self.u1() as u2) Ok(((self.u1()? as u2) << 8) | self.u1()? as u2)
} }
fn u4(&mut self) -> Result<u4, ParseErr> { fn u4(&mut self) -> Result<u4> {
Ok(((self.u2()? as u4) << 16) | self.u2() as u4) Ok(((self.u2()? as u4) << 16) | self.u2()? as u4)
} }
fn last_u1(&mut self) -> Result<u1, ParseErr> { fn last_u1(&self) -> Result<u1> {
self.data.get(self.pointer - 1).cloned().ok_or(ParseErr) self.data.get(self.pointer - 1).cloned().ok_or(ParseErr)
} }
fn last_u2(&mut self) -> Result<u2, ParseErr> { fn last_u2(&self) -> Result<u2> {
let last2u1 = self.data.get(self.pointer - 2).cloned().ok_or(ParseErr); let last2u1 = self.data.get(self.pointer - 2).cloned().ok_or(ParseErr)?;
Ok(((self.last_u1()? as u2) << 8) | last2u1 as u2) Ok(((last2u1 as u2) << 8) | self.last_u1()? as u2)
}
fn last_u4(&self) -> Result<u4> {
let last2u1 = self.data.get(self.pointer - 3).cloned().ok_or(ParseErr)?;
let last3u1 = self.data.get(self.pointer - 4).cloned().ok_or(ParseErr)?;
Ok(((last3u1 as u4) << 24) | ((last2u1 as u4) << 16) | self.last_u2()? as u4)
} }
} }
pub trait Parse { pub trait Parse {
fn parse(data: &mut Data) -> Result<Self, ParseErr>; fn parse(data: &mut Data) -> Result<Self>
where
Self: Sized;
} }
pub trait ParseVec<T> { pub trait ParseVec<T> {
fn parse_vec<T: Parse>(data: &mut Data, len: usize) -> Result<Self, ParseErr>; fn parse_vec(data: &mut Data, len: usize) -> Result<Self>
} where
Self: Sized;
impl Parse for ClassFile {
fn parse(data: &mut Data) -> Result<Self, ParseErr> {
Ok(Self {
magic: data.u4()?,
minor_version: data.u2()?,
major_version: data.u2()?,
constant_pool_count: data.u2()?,
constant_pool: Vec::parse_vec::<CpInfo>(data, data.last_u2() as usize)?,
access_flags: data.u2()?,
this_class: data.u2()?,
super_class: data.u2()?,
interfaces_count: data.u2()?,
interfaces: vec![],
fields_count: 0,
fields: vec![],
method_count: 0,
methods: vec![],
attributes_count: 0,
attributes: vec![],
})
}
} }
impl<T: Parse> ParseVec<T> for Vec<T> { impl<T: Parse> ParseVec<T> for Vec<T> {
fn parse_vec<T: Parse>(data: &mut Data, len: usize) -> Result<Self, ParseErr> { fn parse_vec(data: &mut Data, len: usize) -> Result<Self> {
let mut vec = Vec::with_capacity(len); let mut vec = Vec::with_capacity(len);
for i in 0..len { for _ in 0..len {
vec.push(T::parse(data)?); vec.push(T::parse(data)?);
} }
Ok(vec) Ok(vec)
} }
} }
macro_rules! parse_primitive {
($value:ident) => {
impl Parse for $value {
fn parse(data: &mut Data) -> Result<Self>
where
Self: Sized,
{
data.$value()
}
}
};
}
parse_primitive!(u1);
parse_primitive!(u2);
parse_primitive!(u4);
impl Parse for ClassFile {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
magic: data.u4()?,
minor_version: data.u2()?,
major_version: data.u2()?,
constant_pool_count: data.u2()?,
constant_pool: Vec::parse_vec(data, data.last_u2()? as usize)?,
access_flags: data.u2()?,
this_class: data.u2()?,
super_class: data.u2()?,
interfaces_count: data.u2()?,
interfaces: Vec::parse_vec(data, data.last_u2()? as usize)?,
fields_count: data.u2()?,
fields: Vec::parse_vec(data, data.last_u2()? as usize)?,
method_count: data.u2()?,
methods: Vec::parse_vec(data, data.last_u2()? as usize)?,
attributes_count: data.u2()?,
attributes: Vec::parse_vec(data, data.last_u2()? as usize)?,
})
}
}
impl Parse for CpInfo {
fn parse(data: &mut Data) -> Result<Self> {
let tag = data.u1()?;
Ok(match tag {
7 => Self::Class {
tag,
name_index: data.u2()?,
},
9 => Self::Fieldref {
tag,
class_index: data.u2()?,
name_and_type_index: data.u2()?,
},
10 => Self::Methodref {
tag,
class_index: data.u2()?,
name_and_type_index: data.u2()?,
},
11 => Self::InterfaceMethodref {
tag,
class_index: data.u2()?,
name_and_type_index: data.u2()?,
},
8 => Self::String {
tag,
string_index: data.u2()?,
},
3 => Self::Integer {
tag,
bytes: data.u4()?,
},
4 => Self::Float {
tag,
bytes: data.u4()?,
},
5 => Self::Long {
tag,
high_bytes: data.u4()?,
low_bytes: data.u4()?,
},
6 => Self::Double {
tag,
high_bytes: data.u4()?,
low_bytes: data.u4()?,
},
12 => Self::NameAndType {
tag,
name_index: data.u2()?,
descriptor_index: data.u2()?,
},
1 => Self::Utf8 {
tag,
length: data.u2()?,
bytes: Vec::parse_vec(data, data.last_u2()? as usize)?,
},
15 => Self::MethodHandle {
tag,
reference_kind: data.u1()?,
reference_index: data.u2()?,
},
16 => Self::MethodType {
tag,
descriptor_index: data.u2()?,
},
18 => Self::InvokeDynamic {
tag,
bootstrap_method_attr_index: data.u2()?,
name_and_type_index: data.u2()?,
},
_ => Err(ParseErr)?,
})
}
}
impl Parse for FieldInfo {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
access_flags: data.u2()?,
name_index: data.u2()?,
descriptor_index: data.u2()?,
attributes_count: data.u2()?,
attributes: Vec::parse_vec(data, data.last_u2()? as usize)?,
})
}
}
impl Parse for MethodInfo {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
access_flags: data.u2()?,
name_index: data.u2()?,
descriptor_index: data.u2()?,
attributes_count: data.u2()?,
attributes: Vec::parse_vec(data, data.last_u2()? as usize)?,
})
}
}
impl Parse for Attribute {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
attribute_name_index: data.u2()?,
attribute_length: data.u4()?,
attribute_content: Vec::parse_vec(data, data.last_u4()? as usize)?,
})
}
}
impl Parse for AttributeCodeException {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
start_pc: data.last_u2()?,
end_pc: data.last_u2()?,
handler_pc: data.last_u2()?,
catch_type: data.last_u2()?,
})
}
}
impl Parse for StackMapFrame {
fn parse(data: &mut Data) -> Result<Self> {
let frame_type = data.u1()?;
Ok(match frame_type {
0..=63 => Self::SameFrame { frame_type },
64..=127 => Self::SameLocals1StackItemFrame {
frame_type,
stack: VerificationTypeInfo::parse(data)?,
},
247 => Self::SameLocals1StackItemFrameExtended {
frame_type,
offset_delta: data.u2()?,
stack: VerificationTypeInfo::parse(data)?,
},
246..=250 => Self::ChopFrame {
frame_type,
offset_delta: data.u2()?,
},
251 => Self::SameFrameExtended {
frame_type,
offset_delta: data.u2()?,
},
252..=254 => Self::AppendFrame {
frame_type,
offset_delta: data.u2()?,
locals: Vec::parse_vec(data, data.last_u2()? as usize)?,
},
255 => Self::FullFrame {
frame_type,
offset_delta: data.u2()?,
number_of_locals: data.u2()?,
locals: Vec::parse_vec(data, data.last_u2()? as usize)?,
number_of_stack_items: data.u2()?,
stack: Vec::parse_vec(data, data.last_u2()? as usize)?,
},
_ => Err(ParseErr)?,
})
}
}
impl Parse for VerificationTypeInfo {
fn parse(data: &mut Data) -> Result<Self>
where
Self: Sized,
{
let tag = data.u1()?;
Ok(match tag {
0 => Self::Top { tag },
1 => Self::Integer { tag },
2 => Self::Float { tag },
4 => Self::Long { tag },
3 => Self::Double { tag },
5 => Self::Null { tag },
6 => Self::UninitializedThis { tag },
7 => Self::Object {
tag,
cpool_index: data.u2()?,
},
8 => Self::Uninitialized {
tag,
offset: data.u2()?,
},
_ => Err(ParseErr)?,
})
}
}
impl Parse for AttributeInnerClass {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
inner_class_info_index: data.u2()?,
outer_class_info_index: data.u2()?,
inner_class_name_index: data.u2()?,
inner_class_access_flags: data.u2()?,
})
}
}
impl Parse for AttributeLineNumber {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
start_pc: data.u2()?,
line_number: data.u2()?,
})
}
}
impl Parse for AttributeLocalVariableTable {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
start_pc: data.u2()?,
length: data.u2()?,
name_index: data.u2()?,
descriptor_or_signature_index: data.u2()?,
index: data.u2()?,
})
}
}
impl Parse for Annotation {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
type_index: data.u2()?,
num_element_value_pairs: data.u2()?,
element_value_pairs: Vec::parse_vec(data, data.last_u2()? as usize)?,
})
}
}
impl Parse for AnnotationElementValuePair {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
element_name_index: data.u2()?,
element_name_name: AnnotationElementValue::parse(data)?,
})
}
}
impl Parse for AnnotationElementValue {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
tag: data.u1()?,
value: AnnotationElementValueValue::parse(data)?,
})
}
}
impl Parse for AnnotationElementValueValue {
fn parse(data: &mut Data) -> Result<Self> {
let tag = data.last_u1()? as char;
Ok(match tag {
'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' => {
Self::ConstValueIndex { index: data.u2()? }
}
'e' => Self::EnumConstValue {
type_name_index: data.u2()?,
const_name_index: data.u2()?,
},
'c' => Self::ClassInfoIndex { index: data.u2()? },
'@' => Self::AnnotationValue {
annotation: Box::new(Annotation::parse(data)?),
},
'[' => Self::ArrayValue {
num_values: data.u2()?,
values: Vec::parse_vec(data, data.last_u2()? as usize)?,
},
_ => Err(ParseErr)?,
})
}
}
impl Parse for ParameterAnnotation {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
num_annotations: data.u2()?,
annotations: Vec::parse_vec(data, data.last_u2()? as usize)?,
})
}
}
impl Parse for BootstrapMethod {
fn parse(data: &mut Data) -> Result<Self> {
Ok(Self {
bootstrap_method_ref: data.u2()?,
num_bootstrap_arguments: data.u2()?,
bootstrap_arguments: Vec::parse_vec(data, data.last_u2()? as usize)?,
})
}
}
#[cfg(test)]
mod test {
use crate::parse::Data;
#[test]
fn data_u1() {
let mut data = Data {
data: vec![0xff, 0x00],
pointer: 0,
};
assert_eq!(data.u1().unwrap(), 0xff);
assert_eq!(data.u1().unwrap(), 0x00);
assert_eq!(data.last_u1().unwrap(), 0x00);
}
#[test]
fn data_u2() {
let mut data = Data {
data: vec![0xff, 0x33, 0x11, 0x00],
pointer: 0,
};
assert_eq!(data.u2().unwrap(), 0xff33);
assert_eq!(data.u2().unwrap(), 0x1100);
assert_eq!(data.last_u2().unwrap(), 0x1100);
}
#[test]
fn data_u4() {
let mut data = Data {
data: vec![0xff, 0x33, 0x11, 0x00],
pointer: 0,
};
assert_eq!(data.u4().unwrap(), 0xff331100);
assert_eq!(data.last_u4().unwrap(), 0xff331100);
}
}

View file

@ -14,44 +14,46 @@ pub type u4 = u32;
/// ///
/// # Represents a .class file /// # Represents a .class file
/// ///
#[derive(Debug, Clone, Hash)]
pub struct ClassFile { pub struct ClassFile {
/// Magic number identifying the format (= 0xCAFEBABE) /// Magic number identifying the format (= 0xCAFEBABE)
pub(crate) magic: u4, pub magic: u4,
/// The version of the class file (.X) /// The version of the class file (.X)
pub(crate) minor_version: u2, pub minor_version: u2,
/// The version of the class file (X.) /// The version of the class file (X.)
pub(crate) major_version: u2, pub major_version: u2,
/// Number of entries in the constant pool + 1 /// Number of entries in the constant pool + 1
pub(crate) constant_pool_count: u2, pub constant_pool_count: u2,
/// The constant pool. Indexed from 1 to constant_pool_count - 1 /// The constant pool. Indexed from 1 to constant_pool_count - 1
pub(crate) constant_pool: Vec<CpInfo>, pub constant_pool: Vec<CpInfo>,
/// Mask of `ClassAccessFlag` used to denote access permissions /// Mask of `ClassAccessFlag` used to denote access permissions
pub(crate) access_flags: u2, pub access_flags: u2,
/// A valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo` /// A valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo`
pub(crate) this_class: u2, pub this_class: u2,
/// Zero or a valid index into the `constant_pool` table /// Zero or a valid index into the `constant_pool` table
pub(crate) super_class: u2, pub super_class: u2,
/// The number if direct superinterfaces of this class or interface type /// The number if direct superinterfaces of this class or interface type
pub(crate) interfaces_count: u2, pub interfaces_count: u2,
/// Each entry must be a valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo` /// Each entry must be a valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo`
pub(crate) interfaces: Vec<u2>, pub interfaces: Vec<u2>,
/// The number of fields in the `fields` table /// The number of fields in the `fields` table
pub(crate) fields_count: u2, pub fields_count: u2,
/// All fields of the class. Contains only fields of the class itself /// All fields of the class. Contains only fields of the class itself
pub(crate) fields: Vec<FieldInfo>, pub fields: Vec<FieldInfo>,
/// The number of methods in `methods` /// The number of methods in `methods`
pub(crate) method_count: u2, pub method_count: u2,
/// All methods of the class. If it's neither Native nor Abstract, the implementation has to be provided too /// All methods of the class. If it's neither Native nor Abstract, the implementation has to be provided too
pub(crate) methods: Vec<MethodInfo>, pub methods: Vec<MethodInfo>,
/// The number of attributes in `attributes` /// The number of attributes in `attributes`
pub(crate) attributes_count: u2, pub attributes_count: u2,
/// All attributes of the class /// All attributes of the class
pub(crate) attributes: Vec<AttributeInfo>, pub attributes: Vec<Attribute>,
} }
/// A constant from the constant pool /// A constant from the constant pool
/// May have indices back to the constant pool, with expected types /// May have indices back to the constant pool, with expected types
/// _index: A valid index into the `constant_pool` table. /// _index: A valid index into the `constant_pool` table.
#[derive(Debug, Clone, Hash)]
pub enum CpInfo { pub enum CpInfo {
Class { Class {
tag: u1, // 7 tag: u1, // 7
@ -139,7 +141,7 @@ pub enum CpInfo {
descriptor_index: u2, descriptor_index: u2,
}, },
InvokeDynamic { InvokeDynamic {
tag: u1, tag: u1, // 18
/// Must be a valid index into the `bootstrap_methods` array of the bootstrap method table of this class fiel /// Must be a valid index into the `bootstrap_methods` array of the bootstrap method table of this class fiel
bootstrap_method_attr_index: u2, bootstrap_method_attr_index: u2,
/// Entry must `NameAndType` /// Entry must `NameAndType`
@ -148,26 +150,36 @@ pub enum CpInfo {
} }
/// Information about a field /// Information about a field
#[derive(Debug, Clone, Hash)]
pub struct FieldInfo { pub struct FieldInfo {
access_flags: u2, pub access_flags: u2,
name_index: u2, pub name_index: u2,
descriptor_index: u2, pub descriptor_index: u2,
attributes_count: u2, pub attributes_count: u2,
attributes: Vec<AttributeInfo>, pub attributes: Vec<Attribute>,
} }
/// Information about a method /// Information about a method
#[derive(Debug, Clone, Hash)]
pub struct MethodInfo { pub struct MethodInfo {
/// Mask of `MethodAccessFlag` used to denote access permissions /// Mask of `MethodAccessFlag` used to denote access permissions
access_flags: u2, pub access_flags: u2,
/// Index to the `constant_pool` of the method name, must be `Utf8` /// Index to the `constant_pool` of the method name, must be `Utf8`
name_index: u2, pub name_index: u2,
/// Index to the `constant_pool` of the method descriptor, must be `Utf8` /// Index to the `constant_pool` of the method descriptor, must be `Utf8`
descriptor_index: u2, pub descriptor_index: u2,
/// The amount of attributes for this method /// The amount of attributes for this method
attributes_count: u2, pub attributes_count: u2,
/// The attributes for this method /// The attributes for this method
attributes: Vec<AttributeInfo>, pub attributes: Vec<Attribute>,
}
/// See `AttributeInfo`
#[derive(Debug, Clone, Hash)]
pub struct Attribute {
pub attribute_name_index: u2,
pub attribute_length: u4,
pub attribute_content: Vec<u1>,
} }
/// Information about an attribute /// Information about an attribute
@ -176,6 +188,8 @@ pub struct MethodInfo {
/// `attribute_length`: The length of the subsequent bytes, does not include the first 6 /// `attribute_length`: The length of the subsequent bytes, does not include the first 6
/// ///
/// _index: Index to the `constant_pool` table of any type /// _index: Index to the `constant_pool` table of any type
#[derive(Debug, Clone, Hash)]
#[allow(dead_code)] // todo yeah lol
pub enum AttributeInfo { pub enum AttributeInfo {
/// Only on fields, the constant value of that field /// Only on fields, the constant value of that field
ConstantValue { ConstantValue {
@ -202,7 +216,7 @@ pub enum AttributeInfo {
exception_table: Vec<AttributeCodeException>, exception_table: Vec<AttributeCodeException>,
attributes_count: u2, attributes_count: u2,
/// The attributes of the code /// The attributes of the code
attributes: Vec<AttributeInfo>, attributes: Vec<Attribute>,
}, },
/// Only on the `Code` attribute, used for verification /// Only on the `Code` attribute, used for verification
/// May be implicit on version >= 50.0, with no entries /// May be implicit on version >= 50.0, with no entries
@ -336,22 +350,24 @@ pub enum AttributeInfo {
} }
/// An exception handler in the JVM bytecode array /// An exception handler in the JVM bytecode array
#[derive(Debug, Clone, Hash)]
pub struct AttributeCodeException { pub struct AttributeCodeException {
/// The ranges in the code in which the handler is active. Must be a valid index into the code array. /// The ranges in the code in which the handler is active. Must be a valid index into the code array.
/// The `start_pc` is inclusive /// The `start_pc` is inclusive
start_pc: u2, pub start_pc: u2,
/// The ranges in the code in which the handler is active. Must be a valid index into the code array or the length. /// The ranges in the code in which the handler is active. Must be a valid index into the code array or the length.
/// The `end_pc` is exclusive /// The `end_pc` is exclusive
end_pc: u2, pub end_pc: u2,
/// The start of the exception handler, must be a valid index into the code array at an opcode instruction /// The start of the exception handler, must be a valid index into the code array at an opcode instruction
handler_pc: u2, pub handler_pc: u2,
/// If the catch type is nonzero, it must be a valid index into the `constant_pool`, must be a `Class` /// If the catch type is nonzero, it must be a valid index into the `constant_pool`, must be a `Class`
/// Zero means it catches all Exceptions, this is usually for `finally` /// Zero means it catches all Exceptions, this is usually for `finally`
catch_type: u2, pub catch_type: u2,
} }
/// Specifies the type state at a particular bytecode offset /// Specifies the type state at a particular bytecode offset
/// Has a offset_delta, the offset is calculated by adding offset_delta + 1 to the previous offset /// Has a offset_delta, the offset is calculated by adding offset_delta + 1 to the previous offset
#[derive(Debug, Clone, Hash)]
pub enum StackMapFrame { pub enum StackMapFrame {
/// Exactly the same locals as the previous frame and zero stack items, offset_delta is frame_type /// Exactly the same locals as the previous frame and zero stack items, offset_delta is frame_type
SameFrame { SameFrame {
@ -364,7 +380,7 @@ pub enum StackMapFrame {
}, },
/// Exactly the same locals as the previous frame and 1 stack item, offset_delta is given explicitly /// Exactly the same locals as the previous frame and 1 stack item, offset_delta is given explicitly
SameLocals1StackItemFrameExtended { SameLocals1StackItemFrameExtended {
frame_type: u1, // 257 frame_type: u1, // 247
offset_delta: u2, offset_delta: u2,
stack: VerificationTypeInfo, stack: VerificationTypeInfo,
}, },
@ -397,6 +413,7 @@ pub enum StackMapFrame {
} }
/// A stack value/local variable type `StackMapFrame` /// A stack value/local variable type `StackMapFrame`
#[derive(Debug, Clone, Hash)]
pub enum VerificationTypeInfo { pub enum VerificationTypeInfo {
Top { Top {
tag: u1, // 0 tag: u1, // 0
@ -431,64 +448,71 @@ pub enum VerificationTypeInfo {
} }
/// A struct for the `AttributeInfo::InnerClasses` /// A struct for the `AttributeInfo::InnerClasses`
#[derive(Debug, Clone, Hash)]
pub struct AttributeInnerClass { pub struct AttributeInnerClass {
/// Must be a `Class` /// Must be a `Class`
inner_class_info_index: u2, pub inner_class_info_index: u2,
/// Must be 0 or a `Class` /// Must be 0 or a `Class`
outer_class_info_index: u2, pub outer_class_info_index: u2,
/// Must be 0 or `Utf8` /// Must be 0 or `Utf8`
inner_class_name_index: u2, pub inner_class_name_index: u2,
/// Must be a mask of `InnerClassAccessFlags` /// Must be a mask of `InnerClassAccessFlags`
inner_class_access_flags: u2, pub inner_class_access_flags: u2,
} }
/// Line number information for `AttributeInfo::LineNumberTable` /// Line number information for `AttributeInfo::LineNumberTable`
#[derive(Debug, Clone, Hash)]
pub struct AttributeLineNumber { pub struct AttributeLineNumber {
/// Index into the code array where a new line in the source begins /// Index into the code array where a new line in the source begins
start_pc: u2, pub start_pc: u2,
/// The line number in the source file /// The line number in the source file
line_number: u2, pub line_number: u2,
} }
/// Local variable information for `AttributeInfo::LocalVariableTable` and `AttributeInfo::LocalVariableTypeTable` /// Local variable information for `AttributeInfo::LocalVariableTable` and `AttributeInfo::LocalVariableTypeTable`
#[derive(Debug, Clone, Hash)]
pub struct AttributeLocalVariableTable { pub struct AttributeLocalVariableTable {
/// The local variable must have a value between `start_pc` and `start_pc + length`. Must be a valid opcode /// The local variable must have a value between `start_pc` and `start_pc + length`. Must be a valid opcode
start_pc: u2, pub start_pc: u2,
/// The local variable must have a value between `start_pc` and `start_pc + length` /// The local variable must have a value between `start_pc` and `start_pc + length`
length: u2, pub length: u2,
/// Must be `Utf8` /// Must be `Utf8`
name_index: u2, pub name_index: u2,
/// Must be `Utf8`, field descriptor or field signature encoding the type /// Must be `Utf8`, field descriptor or field signature encoding the type
descriptor_or_signature_index: u2, pub descriptor_or_signature_index: u2,
/// The variable must be at `index` in the local variable array /// The variable must be at `index` in the local variable array
index: u2, pub index: u2,
} }
/// A runtime-visible annotation to the program /// A runtime-visible annotation to the program
#[derive(Debug, Clone, Hash)]
pub struct Annotation { pub struct Annotation {
/// Must be `Utf8` /// Must be `Utf8`
type_index: u2, pub type_index: u2,
num_element_value_pairs: u2, pub num_element_value_pairs: u2,
element_value_pairs: Vec<AnnotationElementValuePair>, pub element_value_pairs: Vec<AnnotationElementValuePair>,
} }
// these type names have just become java at this point. no shame. // these type names have just become java at this point. no shame.
/// A element-value pair in the `Annotation` /// A element-value pair in the `Annotation`
#[derive(Debug, Clone, Hash)]
pub struct AnnotationElementValuePair { pub struct AnnotationElementValuePair {
/// Must be `Utf8` /// Must be `Utf8`
element_name_index: u2, pub element_name_index: u2,
element_name_name: AnnotationElementValue, pub element_name_name: AnnotationElementValue,
} }
/// The value of an `AnnotationElementValuePair` /// The value of an `AnnotationElementValuePair`
#[derive(Debug, Clone, Hash)]
pub struct AnnotationElementValue { pub struct AnnotationElementValue {
/// B, C, D, F, I, J, S, Z or s, e, c, @, /// B, C, D, F, I, J, S, Z or s, e, c, @,
tag: u1, pub tag: u1,
value: AnnotationElementValueValue, pub value: AnnotationElementValueValue,
} }
/// The value of a `AnnotationElementValue` /// The value of a `AnnotationElementValue`
#[derive(Debug, Clone, Hash)]
pub enum AnnotationElementValueValue { pub enum AnnotationElementValueValue {
/// If the tag is B, C, D, F, I, J, S, Z, or s. /// If the tag is B, C, D, F, I, J, S, Z, or s.
ConstValueIndex { ConstValueIndex {
@ -520,24 +544,27 @@ pub enum AnnotationElementValueValue {
} }
/// Used in `AttributeInfo::RuntimeVisibleParameterAnnotations` /// Used in `AttributeInfo::RuntimeVisibleParameterAnnotations`
#[derive(Debug, Clone, Hash)]
pub struct ParameterAnnotation { pub struct ParameterAnnotation {
num_annotations: u2, pub num_annotations: u2,
annotations: Vec<Annotation>, pub annotations: Vec<Annotation>,
} }
/// Used in `AttributeInfo::BootstrapMethods ` /// Used in `AttributeInfo::BootstrapMethods `
#[derive(Debug, Clone, Hash)]
pub struct BootstrapMethod { pub struct BootstrapMethod {
/// Must be a `MethodHandle` /// Must be a `MethodHandle`
bootstrap_method_ref: u2, pub bootstrap_method_ref: u2,
num_bootstrap_arguments: u2, pub num_bootstrap_arguments: u2,
/// Each argument is a cpool entry. The constants must be `String, Class, Integer, Long, Float, Double, MethodHandle, or MethodType` /// Each argument is a cpool entry. The constants must be `String, Class, Integer, Long, Float, Double, MethodHandle, or MethodType`
bootstrap_arguments: Vec<u2>, pub bootstrap_arguments: Vec<u2>,
} }
/////// Access Flags /////// Access Flags
/// Access Flags of a class /// Access Flags of a class
#[repr(u16)] #[repr(u16)]
#[derive(Debug, Clone, Hash)]
pub enum ClassAccessFlag { pub enum ClassAccessFlag {
/// Declared public; may be accessed from outside its package. /// Declared public; may be accessed from outside its package.
Public = 0x0001, Public = 0x0001,
@ -559,6 +586,7 @@ pub enum ClassAccessFlag {
/// Access Flags of a method /// Access Flags of a method
#[repr(u16)] #[repr(u16)]
#[derive(Debug, Clone, Hash)]
pub enum MethodAccessFlag { pub enum MethodAccessFlag {
// Declared public; may be accessed from outside its package. // Declared public; may be accessed from outside its package.
PUBLIC = 0x0001, PUBLIC = 0x0001,
@ -588,6 +616,7 @@ pub enum MethodAccessFlag {
/// Access flags for an inner class /// Access flags for an inner class
#[repr(u16)] #[repr(u16)]
#[derive(Debug, Clone, Hash)]
pub enum InnerClassAccessFlags { pub enum InnerClassAccessFlags {
/// Marked or implicitly public in source. /// Marked or implicitly public in source.
PUBLIC = 0x0001, PUBLIC = 0x0001,
@ -613,6 +642,7 @@ pub enum InnerClassAccessFlags {
/// Access flags for a field /// Access flags for a field
#[repr(u16)] #[repr(u16)]
#[derive(Debug, Clone, Hash)]
pub enum FieldAccessFlags { pub enum FieldAccessFlags {
/// Declared public; may be accessed from outside its package. /// Declared public; may be accessed from outside its package.
PUBLIC = 0x0001, PUBLIC = 0x0001,