classfile,passes: model RuntimeVisibleTypeAnnotations and AnnotationDefault
Type annotations (method- and code-level) and annotation defaults were passed through as Raw bytes with the original pool indices; the writer rebuilds the pool, so those indices pointed at the wrong utf8 or past the pool end. HotSpot tolerates the garbage (lazy reflection parsing), but ASM's ClassReader dies with ArrayIndexOutOfBoundsException while Paper's plugin converter reads every method - 76 of 275 LoParkour classes failed to convert. Target_info and type_path carry no pool references and stay opaque bytes; type descriptors and element values are modeled and rewritten by rename like plain annotations.
This commit is contained in:
parent
3f92b72c8b
commit
15cd31252e
14 changed files with 654 additions and 224 deletions
|
|
@ -1,7 +1,7 @@
|
|||
//! Annotation rewriting: class descriptors follow the mapping, string
|
||||
//! values are data and stay put.
|
||||
|
||||
use noxis_classfile::{Annotation, AnnotationValue};
|
||||
use noxis_classfile::{Annotation, AnnotationValue, TypeAnnotation};
|
||||
|
||||
use super::super::assign::{RenameMaps, rewrite_descriptor};
|
||||
|
||||
|
|
@ -19,6 +19,18 @@ pub(super) fn rewrite_parameter_annotations(params: &mut [Vec<Annotation>], maps
|
|||
}
|
||||
}
|
||||
|
||||
/// Type-use annotations (`RuntimeVisibleTypeAnnotations` and friends):
|
||||
/// the annotated type descriptor follows the mapping, the opaque
|
||||
/// `target_info`/`type_path` bytes carry no pool references at all.
|
||||
pub(super) fn rewrite_type_annotations(annos: &mut [TypeAnnotation], maps: &RenameMaps) {
|
||||
for anno in annos.iter_mut() {
|
||||
anno.descriptor = rewrite_descriptor(&anno.descriptor, &maps.classes);
|
||||
for (_, value) in anno.elements.iter_mut() {
|
||||
rewrite_value(value, maps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_annotation(anno: &mut Annotation, maps: &RenameMaps) {
|
||||
anno.descriptor = rewrite_descriptor(&anno.descriptor, &maps.classes);
|
||||
for (_, value) in anno.elements.iter_mut() {
|
||||
|
|
@ -26,7 +38,7 @@ fn rewrite_annotation(anno: &mut Annotation, maps: &RenameMaps) {
|
|||
}
|
||||
}
|
||||
|
||||
fn rewrite_value(value: &mut AnnotationValue, maps: &RenameMaps) {
|
||||
pub(super) fn rewrite_value(value: &mut AnnotationValue, maps: &RenameMaps) {
|
||||
match value {
|
||||
// The `'e'` tag: enum type descriptor moves, the constant name does not.
|
||||
AnnotationValue::Enum { descriptor, .. } => {
|
||||
|
|
|
|||
58
crates/noxis-passes/src/rename/rewrite/consts.rs
Normal file
58
crates/noxis-passes/src/rename/rewrite/consts.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
//! Constant-pool references: owners and descriptors follow the mapping.
|
||||
|
||||
use noxis_classfile::Const;
|
||||
|
||||
use super::super::assign::{RenameMaps, rewrite_descriptor};
|
||||
|
||||
/// A method reference (invoke/bootstrap/method-handle): the owner follows
|
||||
/// class renames, the name follows member renames, the descriptor is
|
||||
/// rewritten. Array owners (`[Lpkg/C;` - e.g. `clone` on arrays) name the
|
||||
/// element class inside a descriptor, so they take the descriptor path.
|
||||
pub(super) fn rewrite_method_ref(
|
||||
owner: &mut String,
|
||||
name: &mut String,
|
||||
descriptor: &mut String,
|
||||
maps: &RenameMaps,
|
||||
) {
|
||||
if owner.starts_with('[') {
|
||||
*owner = rewrite_descriptor(owner, &maps.classes);
|
||||
} else {
|
||||
if let Some(new_name) = maps.method(owner, name, descriptor) {
|
||||
*name = new_name;
|
||||
}
|
||||
if let Some(mapped) = maps.classes.get(owner.as_str()) {
|
||||
*owner = mapped.clone();
|
||||
}
|
||||
}
|
||||
*descriptor = rewrite_descriptor(descriptor, &maps.classes);
|
||||
}
|
||||
|
||||
/// A constant-pool reference inside code or bootstrap arguments: class
|
||||
/// literals (plain or array), method types, method handles, condy payloads.
|
||||
/// Anything else (numbers, strings) has no references to follow.
|
||||
pub(super) fn rewrite_const(value: &mut Const, maps: &RenameMaps) {
|
||||
match value {
|
||||
Const::Class(name) => {
|
||||
if name.starts_with('[') {
|
||||
*name = rewrite_descriptor(name, &maps.classes);
|
||||
} else if let Some(mapped) = maps.classes.get(name.as_str()) {
|
||||
*name = mapped.clone();
|
||||
}
|
||||
}
|
||||
Const::MethodType(descriptor) => {
|
||||
*descriptor = rewrite_descriptor(descriptor, &maps.classes);
|
||||
}
|
||||
Const::MethodHandle {
|
||||
owner,
|
||||
name,
|
||||
descriptor,
|
||||
..
|
||||
} => {
|
||||
rewrite_method_ref(owner, name, descriptor, maps);
|
||||
}
|
||||
Const::Dynamic { descriptor, .. } => {
|
||||
*descriptor = rewrite_descriptor(descriptor, &maps.classes);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,13 @@
|
|||
|
||||
mod annotations;
|
||||
mod code;
|
||||
mod consts;
|
||||
|
||||
use annotations::{rewrite_annotations, rewrite_parameter_annotations};
|
||||
use noxis_classfile::{Attribute, ClassFile, Const, StackMapFrame, VerificationType};
|
||||
use annotations::{
|
||||
rewrite_annotations, rewrite_parameter_annotations, rewrite_type_annotations, rewrite_value,
|
||||
};
|
||||
use consts::{rewrite_const, rewrite_method_ref};
|
||||
use noxis_classfile::{Attribute, ClassFile, StackMapFrame, VerificationType};
|
||||
use noxis_core::{Config, Context};
|
||||
|
||||
use super::assign::{RenameMaps, rewrite_descriptor};
|
||||
|
|
@ -151,6 +155,11 @@ fn rewrite_attributes(
|
|||
| Attribute::RuntimeInvisibleParameterAnnotations(params) => {
|
||||
rewrite_parameter_annotations(params, maps);
|
||||
}
|
||||
Attribute::RuntimeVisibleTypeAnnotations(annos)
|
||||
| Attribute::RuntimeInvisibleTypeAnnotations(annos) => {
|
||||
rewrite_type_annotations(annos, maps);
|
||||
}
|
||||
Attribute::AnnotationDefault(value) => rewrite_value(value, maps),
|
||||
Attribute::BootstrapMethods(methods) => {
|
||||
for bsm in methods.iter_mut() {
|
||||
rewrite_method_ref(&mut bsm.owner, &mut bsm.name, &mut bsm.descriptor, maps);
|
||||
|
|
@ -190,59 +199,6 @@ fn rewrite_attributes(
|
|||
}
|
||||
}
|
||||
|
||||
/// A method reference (invoke/bootstrap/method-handle): the owner follows
|
||||
/// class renames, the name follows member renames, the descriptor is
|
||||
/// rewritten. Array owners (`[Lpkg/C;` - e.g. `clone` on arrays) name the
|
||||
/// element class inside a descriptor, so they take the descriptor path.
|
||||
fn rewrite_method_ref(
|
||||
owner: &mut String,
|
||||
name: &mut String,
|
||||
descriptor: &mut String,
|
||||
maps: &RenameMaps,
|
||||
) {
|
||||
if owner.starts_with('[') {
|
||||
*owner = rewrite_descriptor(owner, &maps.classes);
|
||||
} else {
|
||||
if let Some(new_name) = maps.method(owner, name, descriptor) {
|
||||
*name = new_name;
|
||||
}
|
||||
if let Some(mapped) = maps.classes.get(owner.as_str()) {
|
||||
*owner = mapped.clone();
|
||||
}
|
||||
}
|
||||
*descriptor = rewrite_descriptor(descriptor, &maps.classes);
|
||||
}
|
||||
|
||||
/// A constant-pool reference inside code or bootstrap arguments: class
|
||||
/// literals (plain or array), method types, method handles, condy payloads.
|
||||
/// Anything else (numbers, strings) has no references to follow.
|
||||
fn rewrite_const(value: &mut Const, maps: &RenameMaps) {
|
||||
match value {
|
||||
Const::Class(name) => {
|
||||
if name.starts_with('[') {
|
||||
*name = rewrite_descriptor(name, &maps.classes);
|
||||
} else if let Some(mapped) = maps.classes.get(name.as_str()) {
|
||||
*name = mapped.clone();
|
||||
}
|
||||
}
|
||||
Const::MethodType(descriptor) => {
|
||||
*descriptor = rewrite_descriptor(descriptor, &maps.classes);
|
||||
}
|
||||
Const::MethodHandle {
|
||||
owner,
|
||||
name,
|
||||
descriptor,
|
||||
..
|
||||
} => {
|
||||
rewrite_method_ref(owner, name, descriptor, maps);
|
||||
}
|
||||
Const::Dynamic { descriptor, .. } => {
|
||||
*descriptor = rewrite_descriptor(descriptor, &maps.classes);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Имена классов внутри одного кадра (`Object(..)` в locals/stack).
|
||||
fn rewrite_frame(frame: &mut StackMapFrame, maps: &RenameMaps) {
|
||||
match frame {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue