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 после чтения) —
|
//! Наш IR хранит `offset_delta` в номерах инструкций; backend при `to_bytes`
|
||||||
//! backend сам пересчитает их в байты при `to_bytes`.
|
//! сам пересчитает их в байты. Компактный формат (`Same`/`SameLocals`) годен
|
||||||
|
//! только когда **байтовая** дельта ≤ 63 — иначе нужен расширенный вариант.
|
||||||
|
//! Выбор делаем по байтовой дельте: байты считаются от layout текущего метода.
|
||||||
|
|
||||||
use ristretto_classfile::attributes::{StackFrame as RtFrame, VerificationType as RtType};
|
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::error::ClassfileError;
|
||||||
use crate::format::{StackMapFrame, VerificationType};
|
use crate::format::{StackMapFrame, VerificationType};
|
||||||
|
|
||||||
|
/// Байтовое смещение начала инструкции (для расчёта дельт кадров).
|
||||||
|
type ByteOf<'a> = &'a (dyn Fn(u32) -> Result<u16, ClassfileError> + 'a);
|
||||||
|
|
||||||
/// Кадры IR → кадры backend'а (индексные дельты — как есть).
|
/// Кадры IR → кадры backend'а (индексные дельты — как есть).
|
||||||
pub(super) fn convert_frames(
|
pub(super) fn convert_frames(
|
||||||
frames: &[StackMapFrame],
|
frames: &[StackMapFrame],
|
||||||
pool: &mut Pool,
|
pool: &mut Pool,
|
||||||
|
byte_of: ByteOf<'_>,
|
||||||
) -> Result<Vec<RtFrame>, ClassfileError> {
|
) -> Result<Vec<RtFrame>, ClassfileError> {
|
||||||
frames
|
let mut out = Vec::with_capacity(frames.len());
|
||||||
.iter()
|
let mut first = true;
|
||||||
.map(|frame| build_frame(frame, pool))
|
let mut last_instruction: u32 = 0;
|
||||||
.collect()
|
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 delta = frame_delta(frame);
|
||||||
let offset = u16::try_from(delta)
|
let extended = u16::try_from(delta)
|
||||||
.map_err(|_| ClassfileError::Write(format!("дельта кадра {delta} вне u16")))?;
|
.map_err(|_| ClassfileError::Write(format!("дельта кадра {delta} вне u16")))?;
|
||||||
Ok(match frame {
|
Ok(match frame {
|
||||||
StackMapFrame::Same { .. } => {
|
StackMapFrame::Same { .. } => {
|
||||||
if delta <= 63 {
|
if byte_delta <= 63 {
|
||||||
|
// Backend при verify()/to_bytes читает frame_type как дельту по
|
||||||
|
// ИНСТРУКЦИЯМ и сам пересчитает её в байты (≤ 63 — влезает).
|
||||||
RtFrame::SameFrame {
|
RtFrame::SameFrame {
|
||||||
frame_type: delta as u8,
|
frame_type: delta as u8,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RtFrame::SameFrameExtended {
|
RtFrame::SameFrameExtended {
|
||||||
frame_type: 251,
|
frame_type: 251,
|
||||||
offset_delta: offset,
|
offset_delta: extended,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StackMapFrame::SameLocals { local, .. } => {
|
StackMapFrame::SameLocals { local, .. } => {
|
||||||
let stack = vec![vtype(local, pool)?];
|
let stack = vec![vtype(local, pool)?];
|
||||||
if delta <= 63 {
|
if byte_delta <= 63 {
|
||||||
RtFrame::SameLocals1StackItemFrame {
|
RtFrame::SameLocals1StackItemFrame {
|
||||||
frame_type: 64 + delta as u8,
|
frame_type: 64 + delta as u8,
|
||||||
stack,
|
stack,
|
||||||
|
|
@ -47,14 +82,14 @@ fn build_frame(frame: &StackMapFrame, pool: &mut Pool) -> Result<RtFrame, Classf
|
||||||
} else {
|
} else {
|
||||||
RtFrame::SameLocals1StackItemFrameExtended {
|
RtFrame::SameLocals1StackItemFrameExtended {
|
||||||
frame_type: 247,
|
frame_type: 247,
|
||||||
offset_delta: offset,
|
offset_delta: extended,
|
||||||
stack,
|
stack,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StackMapFrame::Chop { count, .. } => RtFrame::ChopFrame {
|
StackMapFrame::Chop { count, .. } => RtFrame::ChopFrame {
|
||||||
frame_type: 251u8.wrapping_sub(*count),
|
frame_type: 251u8.wrapping_sub(*count),
|
||||||
offset_delta: offset,
|
offset_delta: extended,
|
||||||
},
|
},
|
||||||
StackMapFrame::Append { locals, .. } => {
|
StackMapFrame::Append { locals, .. } => {
|
||||||
let count = u8::try_from(locals.len()).map_err(|_| {
|
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 {
|
RtFrame::AppendFrame {
|
||||||
frame_type: 251 + count,
|
frame_type: 251 + count,
|
||||||
offset_delta: offset,
|
offset_delta: extended,
|
||||||
locals: types(locals, pool)?,
|
locals: types(locals, pool)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StackMapFrame::Full { locals, stack, .. } => RtFrame::FullFrame {
|
StackMapFrame::Full { locals, stack, .. } => RtFrame::FullFrame {
|
||||||
frame_type: 255,
|
frame_type: 255,
|
||||||
offset_delta: offset,
|
offset_delta: extended,
|
||||||
locals: types(locals, pool)?,
|
locals: types(locals, pool)?,
|
||||||
stack: types(stack, pool)?,
|
stack: types(stack, pool)?,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ pub(super) fn convert_code(code: &Code, pool: &mut Pool) -> Result<RtAttr, Class
|
||||||
resolve: &resolve,
|
resolve: &resolve,
|
||||||
byte_of: &byte_of,
|
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);
|
let mut attributes = Vec::with_capacity(code.attributes.len() + 1);
|
||||||
for attr in &code.attributes {
|
for attr in &code.attributes {
|
||||||
attributes.push(match attr {
|
attributes.push(match attr {
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,10 @@ impl Pipeline {
|
||||||
|
|
||||||
for pass in &self.passes {
|
for pass in &self.passes {
|
||||||
let id = pass.id();
|
let id = pass.id();
|
||||||
|
if !ctx.config.is_enabled(id) {
|
||||||
|
tracing::info!(target: "noxis", pass = %id, "пасс выключен — пропущен");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
tracing::info!(target: "noxis", pass = %id, "пасс запущен");
|
tracing::info!(target: "noxis", pass = %id, "пасс запущен");
|
||||||
let result = pass.apply(ctx, program)?;
|
let result = pass.apply(ctx, program)?;
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue