Actually good handling of the Constant Pool indecies

The code does not compile yet, because `FromCpInfo<'_>` needs to be implemented for some more types.
This commit is contained in:
nora 2021-08-25 22:04:32 +02:00
parent 5ec9260b59
commit 2a85d1fdfd
4 changed files with 188 additions and 153 deletions

View file

@ -1,4 +1,4 @@
use file_parser::{ClassFile, ParseErr}; use file_parser::ClassFile;
use std::error::Error; use std::error::Error;
use std::io::Write; use std::io::Write;
@ -16,7 +16,11 @@ pub fn display_class<W: Write>(mut w: W, class: &ClassFile) -> Result<(), Box<dy
writeln!( writeln!(
w, w,
"class {} extends {}{} {{", "class {} extends {}{} {{",
&class.this_class.get(cp)?.name_index.get(cp)?, &class.this_class.get(cp).name_index.get(cp),
match class.super_class.maybe_get(cp) {
None => "<none>",
Some(class) => &class.name_index.get(cp),
},
if class.interfaces.len() == 0 { if class.interfaces.len() == 0 {
"".to_string() "".to_string()
} else { } else {
@ -27,22 +31,16 @@ pub fn display_class<W: Write>(mut w: W, class: &ClassFile) -> Result<(), Box<dy
.interfaces .interfaces
.iter() .iter()
.map(|i| i.get(cp)) .map(|i| i.get(cp))
.collect::<Result<Vec<_>, ParseErr>>()?
.iter()
.map(|i| i.name_index.get(cp)) .map(|i| i.name_index.get(cp))
.collect::<Result<Vec<_>, ParseErr>>()? .collect::<Vec<_>>()
.join(",") .join(",")
) )
}, },
match class.super_class.get(cp)? {
None => "<none>",
Some(class) => &class.name_index.get(cp)?,
}
)?; )?;
writeln!(w, " Attributes:")?; writeln!(w, " Attributes:")?;
for attr in &class.attributes { for attr in &class.attributes {
writeln!(w, " {}", &attr.attribute_name_index.get(cp)?)?; writeln!(w, " {}", &attr.attribute_name_index.get(cp))?;
} }
writeln!(w)?; writeln!(w)?;
@ -51,8 +49,8 @@ pub fn display_class<W: Write>(mut w: W, class: &ClassFile) -> Result<(), Box<dy
writeln!( writeln!(
w, w,
" {} {}", " {} {}",
&field.descriptor_index.get(cp)?, &field.descriptor_index.get(cp),
&field.name_index.get(cp)? &field.name_index.get(cp)
)?; )?;
} }
writeln!(w)?; writeln!(w)?;
@ -62,8 +60,8 @@ pub fn display_class<W: Write>(mut w: W, class: &ClassFile) -> Result<(), Box<dy
writeln!( writeln!(
w, w,
" {} {}", " {} {}",
&method.descriptor_index.get(cp)?, &method.descriptor_index.get(cp),
&method.name_index.get(cp)?, &method.name_index.get(cp),
)?; )?;
} }

View file

@ -2,6 +2,7 @@ mod model;
#[cfg(test)] #[cfg(test)]
mod test; mod test;
use crate::cp_info::FromCpInfo;
pub use model::*; pub use model::*;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -26,7 +27,7 @@ struct Data<'a> {
pub fn parse_class_file(data: &[u1]) -> Result<ClassFile> { pub fn parse_class_file(data: &[u1]) -> Result<ClassFile> {
let mut data = Data::new(data); let mut data = Data::new(data);
ClassFile::parse(&mut data) ClassFile::parse(&mut data, &[])
} }
impl<'a> Data<'a> { impl<'a> Data<'a> {
@ -44,8 +45,11 @@ impl<'a> Data<'a> {
Ok(((self.u1()? as u2) << 8) | self.u1()? as u2) Ok(((self.u1()? as u2) << 8) | self.u1()? as u2)
} }
fn cp<T>(&mut self) -> Result<FromPool<T>> { /// Parses a u2 and validates it in the constant pool
Ok(self.u2()?.into()) fn cp<'pool, T: FromCpInfo<'pool>>(&mut self, pool: &'pool [CpInfo]) -> Result<FromPool<T>> {
let index = self.u2()?;
let _ = T::try_from_cp_info(pool, index)?;
Ok(index.into())
} }
fn u4(&mut self) -> Result<u4> { fn u4(&mut self) -> Result<u4> {
@ -84,16 +88,16 @@ impl<'a> Data<'a> {
} }
trait Parse { trait Parse {
fn parse(data: &mut Data) -> Result<Self> fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self>
where where
Self: Sized; Self: Sized;
} }
fn parse_vec<T: Parse, S: Into<usize>>(len: S, data: &mut Data) -> Result<Vec<T>> { fn parse_vec<T: Parse, S: Into<usize>>(len: S, data: &mut Data, cp: &[CpInfo]) -> Result<Vec<T>> {
let len = len.into(); let len = len.into();
let mut vec = Vec::with_capacity(len); let mut vec = Vec::with_capacity(len);
for _ in 0..len { for _ in 0..len {
vec.push(T::parse(data)?); vec.push(T::parse(data, cp)?);
} }
Ok(vec) Ok(vec)
} }
@ -101,7 +105,7 @@ fn parse_vec<T: Parse, S: Into<usize>>(len: S, data: &mut Data) -> Result<Vec<T>
macro_rules! parse_primitive { macro_rules! parse_primitive {
($($value:ident),*) => { ($($value:ident),*) => {
$(impl Parse for $value { $(impl Parse for $value {
fn parse(data: &mut Data) -> Result<Self> fn parse(data: &mut Data, _cp: &[CpInfo]) -> Result<Self>
where where
Self: Sized, Self: Sized,
{ {
@ -114,25 +118,26 @@ macro_rules! parse_primitive {
parse_primitive!(u1, u2, u4); parse_primitive!(u1, u2, u4);
impl<T> Parse for FromPool<T> { impl<T> Parse for FromPool<T> {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(data.u2()?.into()) Ok(data.u2()?.into())
} }
} }
impl Parse for ClassFile { impl Parse for ClassFile {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
let magic = data.u4()?; let magic = data.u4()?;
assert_eq!(magic, 0xCAFEBABE); assert_eq!(magic, 0xCAFEBABE);
let minor_version = data.u2()?; let minor_version = data.u2()?;
let major_version = data.u2()?; let major_version = data.u2()?;
let constant_pool = parse_vec(data.u2()? - 1, data)?; // the minus one is important let constant_pool = parse_vec(data.u2()? - 1, data, cp)?; // the minus one is important
let cp = &constant_pool;
let access_flags = data.u2()?; let access_flags = data.u2()?;
let this_class = data.cp()?; let this_class = data.cp(cp)?;
let super_class = data.cp()?; let super_class = data.cp(cp)?;
let interfaces = parse_vec(data.u2()?, data)?; let interfaces = parse_vec(data.u2()?, data, cp)?;
let fields = parse_vec(data.u2()?, data)?; let fields = parse_vec(data.u2()?, data, cp)?;
let methods = parse_vec(data.u2()?, data)?; let methods = parse_vec(data.u2()?, data, cp)?;
let attributes = parse_vec(data.u2()?, data)?; let attributes = parse_vec(data.u2()?, data, cp)?;
let mut class = Self { let mut class = Self {
magic, magic,
@ -153,41 +158,41 @@ impl Parse for ClassFile {
} }
impl Parse for CpInfo { impl Parse for CpInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
let tag = data.u1()?; let tag = data.u1()?;
Ok(match tag { Ok(match tag {
7 => Self { 7 => Self {
tag, tag,
inner: CpInfoInner::Class(cp_info::Class { inner: CpInfoInner::Class(cp_info::Class {
name_index: data.cp()?, name_index: data.cp(cp)?,
}), }),
}, },
9 => Self { 9 => Self {
tag, tag,
inner: CpInfoInner::Fieldref(cp_info::Fieldref { inner: CpInfoInner::Fieldref(cp_info::Fieldref {
class_index: data.cp()?, class_index: data.cp(cp)?,
name_and_type_index: data.cp()?, name_and_type_index: data.cp(cp)?,
}), }),
}, },
10 => Self { 10 => Self {
tag, tag,
inner: CpInfoInner::MethodRef(cp_info::MethodRef { inner: CpInfoInner::MethodRef(cp_info::MethodRef {
class_index: data.cp()?, class_index: data.cp(cp)?,
name_and_type_index: data.cp()?, name_and_type_index: data.cp(cp)?,
}), }),
}, },
11 => Self { 11 => Self {
tag, tag,
inner: CpInfoInner::InterfaceMethodref(cp_info::InterfaceMethodref { inner: CpInfoInner::InterfaceMethodref(cp_info::InterfaceMethodref {
class_index: data.cp()?, class_index: data.cp(cp)?,
name_and_type_index: data.cp()?, name_and_type_index: data.cp(cp)?,
}), }),
}, },
8 => Self { 8 => Self {
tag, tag,
inner: CpInfoInner::String(cp_info::String { inner: CpInfoInner::String(cp_info::String {
string_index: data.cp()?, string_index: data.cp(cp)?,
}), }),
}, },
3 => Self { 3 => Self {
@ -215,14 +220,14 @@ impl Parse for CpInfo {
12 => Self { 12 => Self {
tag, tag,
inner: CpInfoInner::NameAndType(cp_info::NameAndType { inner: CpInfoInner::NameAndType(cp_info::NameAndType {
name_index: data.cp()?, name_index: data.cp(cp)?,
descriptor_index: data.cp()?, descriptor_index: data.cp(cp)?,
}), }),
}, },
1 => Self { 1 => Self {
tag, tag,
inner: CpInfoInner::Utf8(cp_info::Utf8 { inner: CpInfoInner::Utf8(cp_info::Utf8 {
bytes: String::from_utf8(parse_vec(data.u2()?, data)?).map_err(|err| { bytes: String::from_utf8(parse_vec(data.u2()?, data, cp)?).map_err(|err| {
ParseErr(format!("Invalid utf8 in CpInfo::Utf8: {}", err)) ParseErr(format!("Invalid utf8 in CpInfo::Utf8: {}", err))
})?, })?,
}), }),
@ -232,9 +237,9 @@ impl Parse for CpInfo {
inner: CpInfoInner::MethodHandle(cp_info::MethodHandle { inner: CpInfoInner::MethodHandle(cp_info::MethodHandle {
reference_kind: data.u1()?, reference_kind: data.u1()?,
reference_index: match data.last_u1()? { reference_index: match data.last_u1()? {
1..=4 => cp_info::MethodHandleIndex::Field(data.cp()?), 1..=4 => cp_info::MethodHandleIndex::Field(data.cp(cp)?),
5..=8 => cp_info::MethodHandleIndex::Method(data.cp()?), 5..=8 => cp_info::MethodHandleIndex::Method(data.cp(cp)?),
9 => cp_info::MethodHandleIndex::Interface(data.cp()?), 9 => cp_info::MethodHandleIndex::Interface(data.cp(cp)?),
n => { n => {
return Err(ParseErr(format!( return Err(ParseErr(format!(
"Invalid MethodHandle reference kind: {}", "Invalid MethodHandle reference kind: {}",
@ -247,14 +252,14 @@ impl Parse for CpInfo {
16 => Self { 16 => Self {
tag, tag,
inner: CpInfoInner::MethodType(cp_info::MethodType { inner: CpInfoInner::MethodType(cp_info::MethodType {
descriptor_index: data.cp()?, descriptor_index: data.cp(cp)?,
}), }),
}, },
18 => Self { 18 => Self {
tag, tag,
inner: CpInfoInner::InvokeDynamic(cp_info::InvokeDynamic { inner: CpInfoInner::InvokeDynamic(cp_info::InvokeDynamic {
bootstrap_method_attr_index: data.u2()?, bootstrap_method_attr_index: data.u2()?,
name_and_type_index: data.cp()?, name_and_type_index: data.cp(cp)?,
}), }),
}, },
_ => Err(ParseErr(format!("Invalid CPInfo tag: {}", tag)))?, _ => Err(ParseErr(format!("Invalid CPInfo tag: {}", tag)))?,
@ -263,41 +268,41 @@ impl Parse for CpInfo {
} }
impl Parse for FieldInfo { impl Parse for FieldInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
access_flags: data.u2()?, access_flags: data.u2()?,
name_index: data.cp()?, name_index: data.cp(cp)?,
descriptor_index: data.cp()?, descriptor_index: data.cp(cp)?,
attributes: parse_vec(data.u2()?, data)?, attributes: parse_vec(data.u2()?, data, cp)?,
}) })
} }
} }
impl Parse for MethodInfo { impl Parse for MethodInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
access_flags: data.u2()?, access_flags: data.u2()?,
name_index: data.cp()?, name_index: data.cp(cp)?,
descriptor_index: data.cp()?, descriptor_index: data.cp(cp)?,
attributes: parse_vec(data.u2()?, data)?, attributes: parse_vec(data.u2()?, data, cp)?,
}) })
} }
} }
impl Parse for AttributeInfo { impl Parse for AttributeInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
attribute_name_index: data.cp()?, attribute_name_index: data.cp(cp)?,
attribute_length: data.u4()?, attribute_length: data.u4()?,
inner: AttributeInfoInner::Unknown { inner: AttributeInfoInner::Unknown {
attribute_content: parse_vec(data.last_u4()? as usize, data)?, attribute_content: parse_vec(data.last_u4()? as usize, data, cp)?,
}, },
}) })
} }
} }
impl Parse for AttributeCodeException { impl Parse for AttributeCodeException {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
start_pc: data.last_u2()?, start_pc: data.last_u2()?,
end_pc: data.last_u2()?, end_pc: data.last_u2()?,
@ -308,19 +313,19 @@ impl Parse for AttributeCodeException {
} }
impl Parse for StackMapFrame { impl Parse for StackMapFrame {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
let frame_type = data.u1()?; let frame_type = data.u1()?;
Ok(match frame_type { Ok(match frame_type {
0..=63 => Self::SameFrame { frame_type }, 0..=63 => Self::SameFrame { frame_type },
64..=127 => Self::SameLocals1StackItemFrame { 64..=127 => Self::SameLocals1StackItemFrame {
frame_type, frame_type,
stack: VerificationTypeInfo::parse(data)?, stack: VerificationTypeInfo::parse(data, cp)?,
}, },
247 => Self::SameLocals1StackItemFrameExtended { 247 => Self::SameLocals1StackItemFrameExtended {
frame_type, frame_type,
offset_delta: data.u2()?, offset_delta: data.u2()?,
stack: VerificationTypeInfo::parse(data)?, stack: VerificationTypeInfo::parse(data, cp)?,
}, },
246..=250 => Self::ChopFrame { 246..=250 => Self::ChopFrame {
frame_type, frame_type,
@ -333,13 +338,13 @@ impl Parse for StackMapFrame {
252..=254 => Self::AppendFrame { 252..=254 => Self::AppendFrame {
frame_type, frame_type,
offset_delta: data.u2()?, offset_delta: data.u2()?,
locals: parse_vec(data.last_u2()?, data)?, locals: parse_vec(data.last_u2()?, data, cp)?,
}, },
255 => Self::FullFrame { 255 => Self::FullFrame {
frame_type, frame_type,
offset_delta: data.u2()?, offset_delta: data.u2()?,
locals: parse_vec(data.u2()?, data)?, locals: parse_vec(data.u2()?, data, cp)?,
stack: parse_vec(data.u2()?, data)?, stack: parse_vec(data.u2()?, data, cp)?,
}, },
_ => Err(ParseErr(format!( _ => Err(ParseErr(format!(
"Invalid StackMapFrame type: {}", "Invalid StackMapFrame type: {}",
@ -350,7 +355,7 @@ impl Parse for StackMapFrame {
} }
impl Parse for VerificationTypeInfo { impl Parse for VerificationTypeInfo {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
let tag = data.u1()?; let tag = data.u1()?;
Ok(match tag { Ok(match tag {
0 => Self::Top { tag }, 0 => Self::Top { tag },
@ -377,18 +382,18 @@ impl Parse for VerificationTypeInfo {
} }
impl Parse for AttributeInnerClass { impl Parse for AttributeInnerClass {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
inner_class_info_index: data.cp()?, inner_class_info_index: data.cp(cp)?,
outer_class_info_index: data.cp()?, outer_class_info_index: data.cp(cp)?,
inner_class_name_index: data.cp()?, inner_class_name_index: data.cp(cp)?,
inner_class_access_flags: data.u2()?, inner_class_access_flags: data.u2()?,
}) })
} }
} }
impl Parse for AttributeLineNumber { impl Parse for AttributeLineNumber {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
start_pc: data.u2()?, start_pc: data.u2()?,
line_number: data.u2()?, line_number: data.u2()?,
@ -397,62 +402,64 @@ impl Parse for AttributeLineNumber {
} }
impl Parse for AttributeLocalVariableTable { impl Parse for AttributeLocalVariableTable {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
start_pc: data.u2()?, start_pc: data.u2()?,
length: data.u2()?, length: data.u2()?,
name_index: data.cp()?, name_index: data.cp(cp)?,
descriptor_or_signature_index: data.cp()?, descriptor_or_signature_index: data.cp(cp)?,
index: data.u2()?, index: data.u2()?,
}) })
} }
} }
impl Parse for Annotation { impl Parse for Annotation {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
type_index: data.cp()?, type_index: data.cp(cp)?,
num_element_value_pairs: data.u2()?, num_element_value_pairs: data.u2()?,
element_value_pairs: parse_vec(data.last_u2()?, data)?, element_value_pairs: parse_vec(data.last_u2()?, data, cp)?,
}) })
} }
} }
impl Parse for AnnotationElementValuePair { impl Parse for AnnotationElementValuePair {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
element_name_index: data.cp()?, element_name_index: data.cp(cp)?,
element_name_name: AnnotationElementValue::parse(data)?, element_name_name: AnnotationElementValue::parse(data, cp)?,
}) })
} }
} }
impl Parse for AnnotationElementValue { impl Parse for AnnotationElementValue {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
tag: data.u1()?, tag: data.u1()?,
value: AnnotationElementValueValue::parse(data)?, value: AnnotationElementValueValue::parse(data, cp)?,
}) })
} }
} }
impl Parse for AnnotationElementValueValue { impl Parse for AnnotationElementValueValue {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
let tag = data.last_u1()? as char; let tag = data.last_u1()? as char;
Ok(match tag { Ok(match tag {
'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' => { 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' => Self::ConstValueIndex {
Self::ConstValueIndex { index: data.cp()? } index: data.u2()?.into(),
} },
'e' => Self::EnumConstValue { 'e' => Self::EnumConstValue {
type_name_index: data.cp()?, type_name_index: data.cp(cp)?,
const_name_index: data.cp()?, const_name_index: data.cp(cp)?,
},
'c' => Self::ClassInfoIndex {
index: data.cp(cp)?,
}, },
'c' => Self::ClassInfoIndex { index: data.cp()? },
'@' => Self::AnnotationValue { '@' => Self::AnnotationValue {
annotation: Box::new(Annotation::parse(data)?), annotation: Box::new(Annotation::parse(data, cp)?),
}, },
'[' => Self::ArrayValue { '[' => Self::ArrayValue {
values: parse_vec(data.u2()?, data)?, values: parse_vec(data.u2()?, data, cp)?,
}, },
_ => Err(ParseErr(format!( _ => Err(ParseErr(format!(
"Invalid AnnotationElementValueValue tag: {}", "Invalid AnnotationElementValueValue tag: {}",
@ -463,18 +470,18 @@ impl Parse for AnnotationElementValueValue {
} }
impl Parse for ParameterAnnotation { impl Parse for ParameterAnnotation {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
annotations: parse_vec(data.u2()?, data)?, annotations: parse_vec(data.u2()?, data, cp)?,
}) })
} }
} }
impl Parse for BootstrapMethod { impl Parse for BootstrapMethod {
fn parse(data: &mut Data) -> Result<Self> { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result<Self> {
Ok(Self { Ok(Self {
bootstrap_method_ref: data.cp()?, bootstrap_method_ref: data.cp(cp)?,
bootstrap_arguments: parse_vec(data.u2()?, data)?, bootstrap_arguments: parse_vec(data.u2()?, data, cp)?,
}) })
} }
} }
@ -535,7 +542,7 @@ impl AttributeInfo {
} => (attribute_name_index, attribute_length, attribute_content), } => (attribute_name_index, attribute_length, attribute_content),
_ => unreachable!("Attribute already resolved"), _ => unreachable!("Attribute already resolved"),
}; };
let info = match pool.get((*index) as usize - 1) { let info = match pool.get((index.inner()) as usize - 1) {
Some(CpInfo { Some(CpInfo {
inner: CpInfoInner::Utf8(cp_info::Utf8 { bytes, .. }), inner: CpInfoInner::Utf8(cp_info::Utf8 { bytes, .. }),
.. ..
@ -554,7 +561,7 @@ impl AttributeInfo {
attribute_length: u32, attribute_length: u32,
name: &str, name: &str,
data: &mut Data, data: &mut Data,
pool: &[CpInfo], cp: &[CpInfo],
) -> Result<()> { ) -> Result<()> {
let _ = std::mem::replace( let _ = std::mem::replace(
self, self,
@ -563,7 +570,7 @@ impl AttributeInfo {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::ConstantValue { inner: AttributeInfoInner::ConstantValue {
constantvalue_index: data.cp()?, constantvalue_index: data.cp(cp)?,
}, },
}, },
"Code" => { "Code" => {
@ -573,9 +580,9 @@ impl AttributeInfo {
inner: AttributeInfoInner::Code { inner: AttributeInfoInner::Code {
max_stack: data.u2()?, max_stack: data.u2()?,
max_locals: data.u2()?, max_locals: data.u2()?,
code: parse_vec(data.u4()? as usize, data)?, code: parse_vec(data.u4()? as usize, data, cp)?,
exception_table: parse_vec(data.u2()?, data)?, exception_table: parse_vec(data.u2()?, data, cp)?,
attributes: parse_vec(data.u2()?, data)?, attributes: parse_vec(data.u2()?, data, cp)?,
}, },
}; };
if let AttributeInfoInner::Code { if let AttributeInfoInner::Code {
@ -584,7 +591,7 @@ impl AttributeInfo {
{ {
attributes attributes
.iter_mut() .iter_mut()
.map(|attr| attr.resolve_attribute(pool)) .map(|attr| attr.resolve_attribute(cp))
.collect::<Result<Vec<()>>>()?; .collect::<Result<Vec<()>>>()?;
} else { } else {
unreachable!() unreachable!()
@ -596,29 +603,29 @@ impl AttributeInfo {
attribute_length, attribute_length,
inner: AttributeInfoInner::StackMapTable { inner: AttributeInfoInner::StackMapTable {
number_of_entries: data.u2()?, number_of_entries: data.u2()?,
entries: parse_vec(data.last_u2()?, data)?, entries: parse_vec(data.last_u2()?, data, cp)?,
}, },
}, },
"Exceptions" => Self { "Exceptions" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::Exceptions { inner: AttributeInfoInner::Exceptions {
exception_index_table: parse_vec(data.u2()?, data)?, exception_index_table: parse_vec(data.u2()?, data, cp)?,
}, },
}, },
"InnerClasses" => Self { "InnerClasses" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::InnerClasses { inner: AttributeInfoInner::InnerClasses {
classes: parse_vec(data.u2()?, data)?, classes: parse_vec(data.u2()?, data, cp)?,
}, },
}, },
"EnclosingMethod" => Self { "EnclosingMethod" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::EnclosingMethod { inner: AttributeInfoInner::EnclosingMethod {
class_index: data.cp()?, class_index: data.cp(cp)?,
method_index: data.cp()?, method_index: data.cp(cp)?,
}, },
}, },
"Synthetic" => Self { "Synthetic" => Self {
@ -630,42 +637,42 @@ impl AttributeInfo {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::Signature { inner: AttributeInfoInner::Signature {
signature_index: data.cp()?, signature_index: data.cp(cp)?,
}, },
}, },
"SourceFile" => Self { "SourceFile" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::SourceFile { inner: AttributeInfoInner::SourceFile {
sourcefile_index: data.cp()?, sourcefile_index: data.cp(cp)?,
}, },
}, },
"SourceDebugExtension" => Self { "SourceDebugExtension" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::SourceDebugExtension { inner: AttributeInfoInner::SourceDebugExtension {
debug_extension: parse_vec(data.last_u2()?, data)?, debug_extension: parse_vec(data.last_u2()?, data, cp)?,
}, },
}, },
"LineNumberTable" => Self { "LineNumberTable" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::LineNumberTable { inner: AttributeInfoInner::LineNumberTable {
line_number_table: parse_vec(data.u2()?, data)?, line_number_table: parse_vec(data.u2()?, data, cp)?,
}, },
}, },
"LocalVariableTable" => Self { "LocalVariableTable" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::LocalVariableTable { inner: AttributeInfoInner::LocalVariableTable {
local_variable_table: parse_vec(data.u2()?, data)?, local_variable_table: parse_vec(data.u2()?, data, cp)?,
}, },
}, },
"LocalVariableTypeTable" => Self { "LocalVariableTypeTable" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::LocalVariableTypeTable { inner: AttributeInfoInner::LocalVariableTypeTable {
local_variable_table: parse_vec(data.u2()?, data)?, local_variable_table: parse_vec(data.u2()?, data, cp)?,
}, },
}, },
"Deprecated" => Self { "Deprecated" => Self {
@ -677,28 +684,28 @@ impl AttributeInfo {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::RuntimeVisibleAnnotations { inner: AttributeInfoInner::RuntimeVisibleAnnotations {
annotations: parse_vec(data.u2()?, data)?, annotations: parse_vec(data.u2()?, data, cp)?,
}, },
}, },
"RuntimeInvisibleAnnotations" => Self { "RuntimeInvisibleAnnotations" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::RuntimeInvisibleAnnotations { inner: AttributeInfoInner::RuntimeInvisibleAnnotations {
annotations: parse_vec(data.u2()?, data)?, annotations: parse_vec(data.u2()?, data, cp)?,
}, },
}, },
"RuntimeVisibleParameterAnnotations" => Self { "RuntimeVisibleParameterAnnotations" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::RuntimeVisibleParameterAnnotations { inner: AttributeInfoInner::RuntimeVisibleParameterAnnotations {
parameter_annotations: parse_vec(data.u1()?, data)?, parameter_annotations: parse_vec(data.u1()?, data, cp)?,
}, },
}, },
"RuntimeInvisibleParameterAnnotations" => Self { "RuntimeInvisibleParameterAnnotations" => Self {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::RuntimeInvisibleParameterAnnotations { inner: AttributeInfoInner::RuntimeInvisibleParameterAnnotations {
parameter_annotations: parse_vec(data.u1()?, data)?, parameter_annotations: parse_vec(data.u1()?, data, cp)?,
}, },
}, },
"AnnotationDefault" => Self { "AnnotationDefault" => Self {
@ -707,7 +714,7 @@ impl AttributeInfo {
inner: AttributeInfoInner::AnnotationDefault { inner: AttributeInfoInner::AnnotationDefault {
default_value: AnnotationElementValue { default_value: AnnotationElementValue {
tag: data.u1()?, tag: data.u1()?,
value: AnnotationElementValueValue::parse(data)?, value: AnnotationElementValueValue::parse(data, cp)?,
}, },
}, },
}, },
@ -715,7 +722,7 @@ impl AttributeInfo {
attribute_name_index, attribute_name_index,
attribute_length, attribute_length,
inner: AttributeInfoInner::BootstrapMethods { inner: AttributeInfoInner::BootstrapMethods {
bootstrap_methods: parse_vec(data.u2()?, data)?, bootstrap_methods: parse_vec(data.u2()?, data, cp)?,
}, },
}, },
name => return Err(ParseErr(format!("Invalid Attribute name: {}", name))), name => return Err(ParseErr(format!("Invalid Attribute name: {}", name))),

View file

@ -1,8 +1,12 @@
use super::*; use super::*;
use crate::ParseErr;
/// ///
/// An index into the constant pool of the class /// An index into the constant pool of the class
/// `T` -> What type the target value is supposed to be. Create an enum if multiple values can be there /// `T` -> What type the target value is supposed to be. Create an enum if multiple values can be there
///
/// The value this is pointing at must *always* be a entry of the correct type T
/// Type checking is done at parse time, so that the value can be get with minimal overhead
#[repr(transparent)] #[repr(transparent)]
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct FromPool<T> { pub struct FromPool<T> {
@ -13,14 +17,6 @@ pub struct FromPool<T> {
// could probably be derived if I chose a better marker // could probably be derived if I chose a better marker
impl<T: Clone> Copy for FromPool<T> {} impl<T: Clone> Copy for FromPool<T> {}
impl<T> std::ops::Deref for FromPool<T> {
type Target = u2;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> From<u2> for FromPool<T> { impl<T> From<u2> for FromPool<T> {
fn from(n: u2) -> Self { fn from(n: u2) -> Self {
Self { Self {
@ -30,40 +26,63 @@ impl<T> From<u2> for FromPool<T> {
} }
} }
pub trait FromCpInfo<'a> { impl<T> FromPool<T> {
type Target; #[inline]
fn from_cp_info(info: &'a CpInfo) -> Result<Self::Target, ParseErr>; pub const fn inner(&self) -> u2 {
} self.inner
impl<'a, T> FromCpInfo<'a> for Option<T>
where
T: FromCpInfo<'a, Target = &'a T>,
T: 'a,
{
type Target = Option<&'a T>;
fn from_cp_info(info: &'a CpInfo) -> Result<Self::Target, ParseErr> {
Ok(T::from_cp_info(info).ok())
} }
} }
impl<'a, T> FromPool<T> impl<'pool, T> FromPool<T>
where where
T: FromCpInfo<'a>, T: FromCpInfo<'pool>,
{ {
pub fn get(&self, pool: &'a [CpInfo]) -> Result<T::Target, ParseErr> { #[inline]
pub fn get(&self, pool: &'pool [CpInfo]) -> T::Target {
T::from_cp_info(&pool[self.inner as usize - 1]) T::from_cp_info(&pool[self.inner as usize - 1])
} }
} }
impl<'pool, T> FromPool<Option<T>>
where
T: FromCpInfo<'pool>,
{
#[inline]
pub fn maybe_get(&self, pool: &'pool [CpInfo]) -> Option<T::Target> {
if self.inner == 0 {
None
} else {
Some(T::from_cp_info(&pool[self.inner as usize - 1]))
}
}
}
pub trait FromCpInfo<'pool> {
type Target;
fn from_cp_info(info: &'pool CpInfo) -> Self::Target;
fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result<Self::Target, ParseErr>;
}
macro_rules! impl_try_from_cp { macro_rules! impl_try_from_cp {
($($name:ident),*) => { ($($name:ident),*) => {
$( $(
impl<'a> FromCpInfo<'a> for $name { impl<'pool> FromCpInfo<'pool> for $name {
type Target = &'a Self; type Target = &'pool Self;
fn from_cp_info(info: &'a CpInfo) -> Result<Self::Target, ParseErr> { #[inline]
fn from_cp_info(info: &'pool CpInfo) -> Self::Target {
match &info.inner { match &info.inner {
CpInfoInner::$name(class) => class,
_kind => unreachable!(),
}
}
#[inline]
fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result<Self::Target, ParseErr> {
if index == 0 {
return Err(ParseErr("Index must not be 0".to_string()));
}
match &info[index as usize - 1].inner {
CpInfoInner::$name(class) => Ok(class), CpInfoInner::$name(class) => Ok(class),
kind => Err(ParseErr(format!( kind => Err(ParseErr(format!(
concat!("Expected '", stringify!($name), "', found '{:?}'"), concat!("Expected '", stringify!($name), "', found '{:?}'"),
@ -206,11 +225,23 @@ impl_try_from_cp!(
); );
// custom implementations // custom implementations
impl<'a> FromCpInfo<'a> for Utf8 { impl<'pool> FromCpInfo<'pool> for Utf8 {
type Target = &'a str; type Target = &'pool str;
fn from_cp_info(info: &'a CpInfo) -> Result<Self::Target, ParseErr> { #[inline]
fn from_cp_info(info: &'pool CpInfo) -> Self::Target {
match &info.inner { match &info.inner {
CpInfoInner::Utf8(class) => &class.bytes,
_ => unreachable!(),
}
}
#[inline]
fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result<Self::Target, ParseErr> {
if index == 0 {
return Err(ParseErr("Index must not be 0".to_string()));
}
match &info[index as usize - 1].inner {
CpInfoInner::Utf8(class) => Ok(&class.bytes), CpInfoInner::Utf8(class) => Ok(&class.bytes),
kind => Err(ParseErr(format!( kind => Err(ParseErr(format!(
concat!("Expected '", stringify!($name), "', found '{:?}'"), concat!("Expected '", stringify!($name), "', found '{:?}'"),

View file

@ -4,7 +4,6 @@
//! [The .class specs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html) //! [The .class specs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html)
#![allow(dead_code)] #![allow(dead_code)]
use crate::ParseErr;
use std::marker::PhantomData; use std::marker::PhantomData;
/// All of the Constants in the Constant Pool /// All of the Constants in the Constant Pool