classfile,passes,jar: model PermittedSubclasses, normalize interface flags, name class in write errors
This commit is contained in:
parent
e9d5e44b9e
commit
9a33cef9b1
11 changed files with 299 additions and 85 deletions
|
|
@ -47,6 +47,12 @@ pub(super) fn convert(attr: &RtAttr, pool: &ConstantPool<'_>) -> Result<Attribut
|
|||
.map(|index| class_name(pool, *index))
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
RtAttr::PermittedSubclasses { class_indexes, .. } => Attribute::PermittedSubclasses(
|
||||
class_indexes
|
||||
.iter()
|
||||
.map(|index| class_name(pool, *index))
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
RtAttr::EnclosingMethod {
|
||||
class_index,
|
||||
method_index,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,21 @@ use super::pool::{class_name, utf8};
|
|||
use crate::error::ClassfileError;
|
||||
use crate::model::{Attribute, ClassFile, Code, Field, Method, Version};
|
||||
|
||||
/// JVMS 4.1: an interface implies `ABSTRACT` and ignores `SUPER`. Some
|
||||
/// compilers emit a bare `0x200` that HotSpot tolerates, but the strict
|
||||
/// backend verifier rejects it on write (after widening, as `0x201`) - so
|
||||
/// normalize once on parse. Interfaces are abstract by definition: no
|
||||
/// behaviour changes.
|
||||
fn normalize_class_flags(flags: u16) -> u16 {
|
||||
const INTERFACE: u16 = 0x0200;
|
||||
const SUPER: u16 = 0x0020;
|
||||
const ABSTRACT: u16 = 0x0400;
|
||||
if flags & INTERFACE == 0 {
|
||||
return flags;
|
||||
}
|
||||
(flags | ABSTRACT) & !SUPER
|
||||
}
|
||||
|
||||
/// Parse `.class` bytes into our IR.
|
||||
pub(crate) fn parse_class(bytes: &[u8]) -> Result<ClassFile, ClassfileError> {
|
||||
let rt = RtClass::from_bytes(bytes).map_err(|e| ClassfileError::Parse(e.to_string()))?;
|
||||
|
|
@ -25,7 +40,7 @@ pub(crate) fn parse_class(bytes: &[u8]) -> Result<ClassFile, ClassfileError> {
|
|||
minor: rt.version.minor(),
|
||||
major: rt.version.major(),
|
||||
},
|
||||
access_flags: rt.access_flags.bits(),
|
||||
access_flags: normalize_class_flags(rt.access_flags.bits()),
|
||||
this_class: class_name(pool, rt.this_class)?,
|
||||
super_class: optional_class(pool, rt.super_class)?,
|
||||
interfaces,
|
||||
|
|
|
|||
|
|
@ -145,6 +145,13 @@ pub(super) fn convert(attr: &Attribute, pool: &mut Pool) -> Result<RtAttr, Class
|
|||
.map(|name| pool.class(name))
|
||||
.collect::<Result<_, _>>()?,
|
||||
},
|
||||
Attribute::PermittedSubclasses(classes) => RtAttr::PermittedSubclasses {
|
||||
name_index: pool.utf8("PermittedSubclasses")?,
|
||||
class_indexes: classes
|
||||
.iter()
|
||||
.map(|name| pool.class(name))
|
||||
.collect::<Result<_, _>>()?,
|
||||
},
|
||||
Attribute::ConstantValue(value) => RtAttr::ConstantValue {
|
||||
name_index: pool.utf8("ConstantValue")?,
|
||||
constant_value_index: pool.constant(value)?,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ pub enum Attribute {
|
|||
NestHost(String),
|
||||
/// `NestMembers`: the member classes of this nest host (JVMS §4.7.29).
|
||||
NestMembers(Vec<String>),
|
||||
/// `PermittedSubclasses`: who may extend a sealed class (JVMS §4.7.31).
|
||||
/// Stored as names: pool indices go stale when the pool is rebuilt.
|
||||
PermittedSubclasses(Vec<String>),
|
||||
/// A field's `ConstantValue` (`static final`): a value from the pool.
|
||||
ConstantValue(Const),
|
||||
/// `BootstrapMethods` for `invokedynamic` (lambdas): method + arguments.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue