compute ins_size ans outs_size on the go

This commit is contained in:
Jean-Marie 'Histausse' Mineau 2025-03-04 09:57:21 +01:00
parent ff2d630352
commit bcc9354526
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
5 changed files with 58 additions and 30 deletions

View file

@ -2769,8 +2769,6 @@ impl Apk {
}
Ok(Code {
registers_size: code_item.registers_size,
ins_size: code_item.ins_size,
outs_size: code_item.outs_size,
parameter_names,
insns,
})

View file

@ -9,8 +9,8 @@ use std::collections::{HashMap, HashSet};
use pyo3::prelude::*;
use crate::{
ins::Instruction, DexString, IdField, IdMethod, IdMethodType, IdType, MethodHandle, Result,
Visitable, VisitableMut, Visitor, VisitorMut,
ins::Instruction, DexString, IdField, IdMethod, IdMethodType, IdType, Method, MethodHandle,
Result, Visitable, VisitableMut, Visitor, VisitorMut,
};
// TODO: make this easy to edit/manipulate, maybe move to Method
@ -25,14 +25,6 @@ pub struct Code {
/// The number of registers used by the code
#[cfg_attr(feature = "python", pyo3(get))]
pub registers_size: u16,
// TODO: what does it means? is it computable?
/// The number of words of incoming arguments to the method
#[cfg_attr(feature = "python", pyo3(get))]
pub ins_size: u16,
// TODO: what does it means? is it computable?
/// The number of words of outgoing argument space
#[cfg_attr(feature = "python", pyo3(get))]
pub outs_size: u16,
/// The names of the parameters if given
#[cfg_attr(feature = "python", pyo3(get))]
pub parameter_names: Option<Vec<Option<DexString>>>,
@ -47,8 +39,6 @@ impl PartialEq for Code {
let comparable_self = self.semantic_comparable().unwrap();
let comparable_other = other.semantic_comparable().unwrap();
(comparable_self.registers_size == comparable_other.registers_size)
&& (comparable_self.ins_size == comparable_other.ins_size)
&& (comparable_self.outs_size == comparable_other.outs_size)
&& (comparable_self.insns == comparable_other.insns)
}
}
@ -68,20 +58,46 @@ impl Code {
#[cfg_attr(feature = "python", pyo3(signature = (registers_size, ins_size, outs_size, insns, parameter_names=None)))]
pub fn new(
registers_size: u16,
ins_size: u16,
outs_size: u16,
insns: Vec<Instruction>,
parameter_names: Option<Vec<Option<DexString>>>,
) -> Self {
Self {
registers_size,
ins_size,
outs_size,
insns,
parameter_names,
}
}
/// Compute the `ins_size` field. This is the number of register parameters, including the
/// `this` parameter for non-static methods.
/// This information is stored in the code item in dex files, but is not computable from the code
/// (as opposed to `outs_size`). The [`Method`] struct is needed to compute it.
pub fn ins_size(&self, method: &Method) -> u16 {
method.ins_size()
}
/// Compute the `outs_size` field. This is the number of registers needed to call other
/// function.
pub fn outs_size(&self) -> u16 {
let mut outs = 0;
for ins in &self.insns {
match ins {
Instruction::InvokeVirtual { args, .. }
| Instruction::InvokeSuper { args, .. }
| Instruction::InvokeDirect { args, .. }
| Instruction::InvokeStatic { args, .. }
| Instruction::InvokeInterface { args, .. }
| Instruction::InvokePolymorphic { args, .. }
| Instruction::InvokeCustom { args, .. } => {
if args.len() > outs {
outs = args.len();
}
}
_ => (),
}
}
outs as u16
}
pub fn __str__(&self) -> String {
self.__repr__()
}

View file

@ -54,7 +54,7 @@ impl MethodCFG<'_> {
return HashMap::new();
}
// Initialize the entry block from function signature:
let mut i = (code.registers_size - code.ins_size) as usize;
let mut i = (code.registers_size - code.ins_size(&self.method)) as usize;
if !self.method.is_static {
end_block_reg_tys[0][i] = RegType::Object; // 'this'
i += 1;

View file

@ -406,7 +406,7 @@ impl DexWriter {
///
/// This is currently a stub that probably serialize invalid references to data.
fn insert_code_item(&mut self, method_id: IdMethod, direct_methods: bool) -> Result<()> {
let code = if direct_methods {
let method = if direct_methods {
self.class_defs
.get(&method_id.class_)
.unwrap()
@ -414,10 +414,6 @@ impl DexWriter {
.direct_methods
.get(&method_id)
.unwrap()
.code
.as_ref()
.unwrap()
.clone()
} else {
self.class_defs
.get(&method_id.class_)
@ -426,11 +422,10 @@ impl DexWriter {
.virtual_methods
.get(&method_id)
.unwrap()
.code
.as_ref()
.unwrap()
.clone()
};
let code = method.code.as_ref().unwrap().clone();
let ins_size = code.ins_size(&method);
let outs_size = code.outs_size();
// Estimate instructions addresses
let mut min_addr = 0;
let mut max_addr = 0;
@ -864,9 +859,9 @@ impl DexWriter {
};
let item = CodeItem {
registers_size: code.registers_size,
ins_size: code.ins_size,
outs_size: code.outs_size,
debug_info_off, // linked in link_debug_info()
ins_size,
outs_size,
insns,
tries,
handlers,

View file

@ -294,6 +294,25 @@ impl Method {
.iter()
.any(|list| !list.is_empty())
}
/// Compute the `ins_size` field. This is the number of register parameters, including the
/// `this` parameter for non-static methods.
/// This information is stored in the code item in dex files, but is not computable from the code
/// (as opposed to `outs_size`). The [`Method`] struct is needed to compute it.
pub fn ins_size(&self) -> u16 {
let mut ins = 0;
if !self.is_static {
ins += 1; // this
}
for param in &self.descriptor.proto.parameters {
if param.is_long() || param.is_double() {
ins += 2;
} else {
ins += 1;
}
}
ins
}
}
impl<V: Visitor> Visitable<V> for Method {