classfile,core: pick frame compact form by byte delta; honor --no-* flags
StackMapTable compact-vs-extended selection used the instruction delta, but JVM validity requires the byte offset delta <= 63. Track byte offsets in convert_frames and branch on byte_delta while keeping the instruction delta stored (ristretto re-derives bytes). Pipeline::run ignored config.disable, so --no-* CLI flags had no effect; gate each pass on config.is_enabled.
This commit is contained in:
parent
c3b8d4dd62
commit
a2e4c69210
3 changed files with 56 additions and 17 deletions
|
|
@ -1,7 +1,9 @@
|
|||
//! Кадры `StackMapTable` при записи: вариант в вариант, дельты как есть.
|
||||
//! Кадры `StackMapTable` при записи: вариант в вариант, дельты по инструкциям.
|
||||
//!
|
||||
//! Наш IR хранит кадры в номерах инструкций (как backend после чтения) —
|
||||
//! backend сам пересчитает их в байты при `to_bytes`.
|
||||
//! Наш IR хранит `offset_delta` в номерах инструкций; backend при `to_bytes`
|
||||
//! сам пересчитает их в байты. Компактный формат (`Same`/`SameLocals`) годен
|
||||
//! только когда **байтовая** дельта ≤ 63 — иначе нужен расширенный вариант.
|
||||
//! Выбор делаем по байтовой дельте: байты считаются от layout текущего метода.
|
||||
|
||||
use ristretto_classfile::attributes::{StackFrame as RtFrame, VerificationType as RtType};
|
||||
|
||||
|
|
@ -9,37 +11,70 @@ use super::super::pool::Pool;
|
|||
use crate::error::ClassfileError;
|
||||
use crate::format::{StackMapFrame, VerificationType};
|
||||
|
||||
/// Байтовое смещение начала инструкции (для расчёта дельт кадров).
|
||||
type ByteOf<'a> = &'a (dyn Fn(u32) -> Result<u16, ClassfileError> + 'a);
|
||||
|
||||
/// Кадры IR → кадры backend'а (индексные дельты — как есть).
|
||||
pub(super) fn convert_frames(
|
||||
frames: &[StackMapFrame],
|
||||
pool: &mut Pool,
|
||||
byte_of: ByteOf<'_>,
|
||||
) -> Result<Vec<RtFrame>, ClassfileError> {
|
||||
frames
|
||||
.iter()
|
||||
.map(|frame| build_frame(frame, pool))
|
||||
.collect()
|
||||
let mut out = Vec::with_capacity(frames.len());
|
||||
let mut first = true;
|
||||
let mut last_instruction: u32 = 0;
|
||||
let mut last_byte: u16 = 0;
|
||||
for frame in frames {
|
||||
let delta = frame_delta(frame);
|
||||
let instruction = if first {
|
||||
delta
|
||||
} else {
|
||||
last_instruction + delta + 1
|
||||
};
|
||||
let byte = byte_of(instruction)?;
|
||||
// Байтовая дельта относительно конца предыдущего кадра.
|
||||
let byte_delta = if first {
|
||||
byte
|
||||
} else {
|
||||
byte.checked_sub(last_byte)
|
||||
.and_then(|d| d.checked_sub(1))
|
||||
.ok_or_else(|| ClassfileError::Write("кадры не по порядку".into()))?
|
||||
};
|
||||
out.push(build_frame(frame, pool, byte_delta)?);
|
||||
last_instruction = instruction;
|
||||
last_byte = byte;
|
||||
first = false;
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn build_frame(frame: &StackMapFrame, pool: &mut Pool) -> Result<RtFrame, ClassfileError> {
|
||||
/// `byte_delta` — истинная байтовая дельта; компактный вид годен лишь при ≤ 63.
|
||||
fn build_frame(
|
||||
frame: &StackMapFrame,
|
||||
pool: &mut Pool,
|
||||
byte_delta: u16,
|
||||
) -> Result<RtFrame, ClassfileError> {
|
||||
let delta = frame_delta(frame);
|
||||
let offset = u16::try_from(delta)
|
||||
let extended = u16::try_from(delta)
|
||||
.map_err(|_| ClassfileError::Write(format!("дельта кадра {delta} вне u16")))?;
|
||||
Ok(match frame {
|
||||
StackMapFrame::Same { .. } => {
|
||||
if delta <= 63 {
|
||||
if byte_delta <= 63 {
|
||||
// Backend при verify()/to_bytes читает frame_type как дельту по
|
||||
// ИНСТРУКЦИЯМ и сам пересчитает её в байты (≤ 63 — влезает).
|
||||
RtFrame::SameFrame {
|
||||
frame_type: delta as u8,
|
||||
}
|
||||
} else {
|
||||
RtFrame::SameFrameExtended {
|
||||
frame_type: 251,
|
||||
offset_delta: offset,
|
||||
offset_delta: extended,
|
||||
}
|
||||
}
|
||||
}
|
||||
StackMapFrame::SameLocals { local, .. } => {
|
||||
let stack = vec![vtype(local, pool)?];
|
||||
if delta <= 63 {
|
||||
if byte_delta <= 63 {
|
||||
RtFrame::SameLocals1StackItemFrame {
|
||||
frame_type: 64 + delta as u8,
|
||||
stack,
|
||||
|
|
@ -47,14 +82,14 @@ fn build_frame(frame: &StackMapFrame, pool: &mut Pool) -> Result<RtFrame, Classf
|
|||
} else {
|
||||
RtFrame::SameLocals1StackItemFrameExtended {
|
||||
frame_type: 247,
|
||||
offset_delta: offset,
|
||||
offset_delta: extended,
|
||||
stack,
|
||||
}
|
||||
}
|
||||
}
|
||||
StackMapFrame::Chop { count, .. } => RtFrame::ChopFrame {
|
||||
frame_type: 251u8.wrapping_sub(*count),
|
||||
offset_delta: offset,
|
||||
offset_delta: extended,
|
||||
},
|
||||
StackMapFrame::Append { locals, .. } => {
|
||||
let count = u8::try_from(locals.len()).map_err(|_| {
|
||||
|
|
@ -67,13 +102,13 @@ fn build_frame(frame: &StackMapFrame, pool: &mut Pool) -> Result<RtFrame, Classf
|
|||
}
|
||||
RtFrame::AppendFrame {
|
||||
frame_type: 251 + count,
|
||||
offset_delta: offset,
|
||||
offset_delta: extended,
|
||||
locals: types(locals, pool)?,
|
||||
}
|
||||
}
|
||||
StackMapFrame::Full { locals, stack, .. } => RtFrame::FullFrame {
|
||||
frame_type: 255,
|
||||
offset_delta: offset,
|
||||
offset_delta: extended,
|
||||
locals: types(locals, pool)?,
|
||||
stack: types(stack, pool)?,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub(super) fn convert_code(code: &Code, pool: &mut Pool) -> Result<RtAttr, Class
|
|||
resolve: &resolve,
|
||||
byte_of: &byte_of,
|
||||
};
|
||||
let frames = convert_frames(&code.frames, pool)?;
|
||||
let frames = convert_frames(&code.frames, pool, &byte_of)?;
|
||||
let mut attributes = Vec::with_capacity(code.attributes.len() + 1);
|
||||
for attr in &code.attributes {
|
||||
attributes.push(match attr {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue