Skip to content
Permalink
Browse files
Switch to borrowed strings in constant pool
  • Loading branch information
Storyyeller committed Dec 18, 2016
1 parent 8f35ae0 commit f9a22c97a53957102b1208ea7408bbcbbc0eba10
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 82 deletions.
@@ -13,6 +13,7 @@
// limitations under the License.
use std::collections::HashSet;
// use std::fmt;
use std::ops::Deref;
use std::str;

use strings::*;
@@ -21,7 +22,7 @@ use dalvik::{DalvikInstruction, parse_bytecode};

const NO_INDEX: u32 = 0xFFFFFFFF;

fn type_list<'a>(dex: &'a DexFile<'a>, off: u32, parse_cls_desc: bool) -> Vec<&'a bstr> {
fn type_list<'a>(dex: &DexFileNoProtos<'a>, off: u32, parse_cls_desc: bool) -> Vec<&'a bstr> {
if off == 0 { return Vec::new(); }

let mut st = dex.stream(off);
@@ -89,7 +90,7 @@ pub struct FieldId<'a> {
pub desc: &'a bstr,
}
impl<'a> FieldId<'a> {
fn new(dex: &'a DexFile<'a>, field_idx: u32) -> FieldId<'a> {
fn new(dex: &DexFile<'a>, field_idx: u32) -> FieldId<'a> {
let mut st = dex.stream(dex.field_ids.off + field_idx*8);
FieldId{
cname: dex.cls_type(st.u16() as u32),
@@ -191,15 +192,30 @@ impl<'a> CodeItem<'a> {
}
}

fn parse_prototype<'a>(dex: &DexFileNoProtos<'a>, proto_idx: u32) -> (BString, Vec<&'a bstr>, &'a bstr) {
let mut st = dex.stream(dex.proto_ids.off + proto_idx * 12);
st.u32();
let return_type = dex.raw_type(st.u32());
let param_types = type_list(dex, st.u32(), false);

let mut desc = vec![b'('];
for part in &param_types {
desc.extend_from_slice(part);
}
desc.push(b')');
desc.extend_from_slice(return_type);
(desc, param_types, return_type)
}

pub struct MethodId<'a> {
pub cname: &'a bstr,
pub name: &'a bstr,
pub desc: BString,
pub desc: &'a bstr,
pub return_type: &'a bstr,
pub method_idx: u32,

proto_idx: u32,
cdesc: &'a bstr,
param_types: Vec<&'a bstr>,
}
impl<'a> MethodId<'a> {
fn new(dex: &'a DexFile<'a>, method_idx: u32) -> MethodId<'a> {
@@ -209,35 +225,24 @@ impl<'a> MethodId<'a> {
let proto_idx = st.u16() as u32;
let name = dex.string(st.u32());

st = dex.stream(dex.proto_ids.off + proto_idx * 12);
st.u32();
let return_type = dex.raw_type(st.u32());
let param_types = type_list(dex, st.u32(), false);

let mut desc = vec![b'('];
for part in &param_types {
desc.extend_from_slice(part);
}
desc.push(b')');
desc.extend_from_slice(return_type);

MethodId{
cname: cname,
name: name,
desc: desc,
return_type: return_type,
desc: &dex.proto(proto_idx).0,
return_type: dex.proto(proto_idx).2,
method_idx: method_idx,
proto_idx: proto_idx,

cdesc: dex.raw_type(cname_idx),
param_types: param_types,
}
}

pub fn spaced_param_types(&self, isstatic: bool) -> Vec<Option<&'a bstr>> {
let mut res = Vec::with_capacity(self.param_types.len() + 1);
pub fn spaced_param_types(&self, dex: &DexFile<'a>, isstatic: bool) -> Vec<Option<&'a bstr>> {
let param_types = &dex.proto(self.proto_idx).1;
let mut res = Vec::with_capacity(param_types.len() + 1);
if !isstatic { res.push(Some(self.cdesc)); }

for param in &self.param_types {
for param in param_types {
res.push(Some(param));
if param[0] == b'J' || param[0] == b'D' { res.push(None); }
}
@@ -350,19 +355,17 @@ impl SizeOff {
}
}

#[allow(dead_code)] //data is not used
pub struct DexFile<'a> {
pub struct DexFileNoProtos<'a> {
raw: &'a bstr,
string_ids: SizeOff,
type_ids: SizeOff,
proto_ids: SizeOff,
field_ids: SizeOff,
method_ids: SizeOff,
class_defs: SizeOff,
data: SizeOff,
}
impl<'a> DexFile<'a> {
pub fn new(data: &bstr) -> DexFile {
impl<'a> DexFileNoProtos<'a> {
pub fn new(data: &bstr) -> DexFileNoProtos {
let mut stream = Reader(data);
stream.read(36);
if stream.u32() != 0x70 {
@@ -375,24 +378,17 @@ impl<'a> DexFile<'a> {
SizeOff::new(&mut stream);
stream.u32();

DexFile {
DexFileNoProtos {
raw: data,
string_ids: SizeOff::new(&mut stream),
type_ids: SizeOff::new(&mut stream),
proto_ids: SizeOff::new(&mut stream),
field_ids: SizeOff::new(&mut stream),
method_ids: SizeOff::new(&mut stream),
class_defs: SizeOff::new(&mut stream),
data: SizeOff::new(&mut stream),
// data: SizeOff::new(&mut stream),
}
}
pub fn parse_classes(&'a self) -> Vec<DexClass<'a>> {
let mut classes = Vec::with_capacity(self.class_defs.size as usize);
for i in 0..self.class_defs.size {
classes.push(DexClass::new(&self, self.class_defs.off, i));
}
classes
}

fn stream(&self, offset: u32) -> Reader<'a> {
Reader(self.raw.split_at(offset as usize).1)
@@ -401,29 +397,58 @@ impl<'a> DexFile<'a> {
self.stream(i).u32()
}

pub fn string(&self, i: u32) -> &bstr {
pub fn string(&self, i: u32) -> &'a bstr {
let data_off = self.u32(self.string_ids.off + i*4);
let mut stream = self.stream(data_off);
stream.uleb128(); // Ignore decoded length
stream.cstr()
}

pub fn raw_type(&self, i: u32) -> &bstr {
pub fn raw_type(&self, i: u32) -> &'a bstr {
assert!(i < self.type_ids.size);
self.string(self.u32(self.type_ids.off + i*4))
}

pub fn cls_type(&self, i: u32) -> &bstr {
pub fn cls_type(&self, i: u32) -> &'a bstr {
let data = self.raw_type(i);
if data[0] == b'L' {
&data[1..data.len()-1]
} else { data }
}

fn cls_type_opt(&self, i: u32) -> Option<&bstr> {
fn cls_type_opt(&self, i: u32) -> Option<&'a bstr> {
if i == NO_INDEX { None } else { Some(self.cls_type(i)) }
}
}

pub struct DexFile<'a> {
dex: DexFileNoProtos<'a>,
protos: Vec<(BString, Vec<&'a bstr>, &'a bstr)>,
}
impl<'a> Deref for DexFile<'a> {
type Target = DexFileNoProtos<'a>;
fn deref(&self) -> &Self::Target { &self.dex }
}
impl<'a> DexFile<'a> {
pub fn new(data: &bstr) -> DexFile {
let dex = DexFileNoProtos::new(data);
let n = dex.proto_ids.size;
let mut protos = Vec::with_capacity(n as usize);
for i in 0..n {
protos.push(parse_prototype(&dex, i));
}
DexFile{dex: dex, protos: protos}
}

pub fn parse_classes(&'a self) -> Vec<DexClass<'a>> {
let mut classes = Vec::with_capacity(self.class_defs.size as usize);
for i in 0..self.class_defs.size {
classes.push(DexClass::new(&self, self.class_defs.off, i));
}
classes
}

pub fn field_id(&self, i: u32) -> FieldId { FieldId::new(self, i) }
pub fn method_id(&self, i: u32) -> MethodId { MethodId::new(self, i) }
}
fn proto(&self, i: u32) -> &(BString, Vec<&'a bstr>, &'a bstr) { &self.protos[i as usize] }
}
@@ -11,25 +11,23 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::borrow::Cow;
use std::collections::HashMap;
use std::ops::Deref;

use strings::*;
use byteio::Writer;
use dex::{FieldId, MethodId};
use error;

#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub struct ArgsUtf<'a>(Cow<'a, bstr>);
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub struct ArgsUtf<'a>(&'a bstr);
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub struct ArgsInd(u16);
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub struct ArgsInd2(u16, u16);
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub struct ArgsPrim(pub u64);

#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum Entry<'a> {
Class(ArgsInd),
Fieldref(ArgsInd2),
@@ -106,47 +104,44 @@ pub trait ConstantPool<'a> {
Some(self.insert_directly(entry, true))
}

fn _utf8(&mut self, s: Cow<'a, bstr>) -> u16 {
fn utf8(&mut self, s: &'a bstr) -> u16 {
if s.len() > 65535 {
error::classfile_limit_exceeded();
}
self.get(Utf8(ArgsUtf(s)))
}
fn utf8(&mut self, s: &'a bstr) -> u16 { self._utf8(s.into()) }

fn _class(&mut self, s: Cow<'a, bstr>) -> u16 {
let ind = self._utf8(s);
fn class(&mut self, s: &'a bstr) -> u16 {
let ind = self.utf8(s);
self.get(Class(ArgsInd(ind)))
}
fn class(&mut self, s: &'a bstr) -> u16 { self._class(s.into()) }

fn _string(&mut self, s: Cow<'a, bstr>) -> u16 {
let ind = self._utf8(s);
fn string(&mut self, s: &'a bstr) -> u16 {
let ind = self.utf8(s);
self.get(JString(ArgsInd(ind)))
}
fn string(&mut self, s: &'a bstr) -> u16 { self._string(s.into()) }

fn _nat(&mut self, name: Cow<'a, bstr>, desc: Cow<'a, bstr>) -> u16 {
let ind = self._utf8(name);
let ind2 = self._utf8(desc);
fn _nat(&mut self, name: &'a bstr, desc: &'a bstr) -> u16 {
let ind = self.utf8(name);
let ind2 = self.utf8(desc);
self.get(NameAndType(ArgsInd2(ind, ind2)))
}

fn field(&mut self, trip: &FieldId<'a>) -> u16 {
let ind = self.class(trip.cname);
let ind2 = self._nat(trip.name.into(), trip.desc.into());
let ind2 = self._nat(trip.name, trip.desc);
self.get(Fieldref(ArgsInd2(ind, ind2)))
}

fn method(&mut self, trip: MethodId<'a>) -> u16 {
let ind = self.class(trip.cname);
let ind2 = self._nat(trip.name.into(), trip.desc.into());
let ind2 = self._nat(trip.name, trip.desc);
self.get(Methodref(ArgsInd2(ind, ind2)))
}

fn imethod(&mut self, trip: MethodId<'a>) -> u16 {
let ind = self.class(trip.cname);
let ind2 = self._nat(trip.name.into(), trip.desc.into());
let ind2 = self._nat(trip.name, trip.desc);
self.get(InterfaceMethodref(ArgsInd2(ind, ind2)))
}

@@ -170,7 +165,7 @@ pub trait ConstantPool<'a> {
&NameAndType(ref args) => { stream.u8(12); stream.u16(args.0); stream.u16(args.1); },
&Utf8(ref args) => { stream.u8(1);
stream.u16(args.0.len() as u16);
stream.write(args.0.deref());
stream.write(args.0);
},
}
}
@@ -115,7 +115,7 @@ impl <'b, 'a> IRBlock<'b, 'a> {
} else {
// note - will throw if actual type is boolean[] but there's not
// much we can do in this case
self.pool._class(at.to_desc().into())
self.pool.class(at.to_desc())
};
self.u8u16(CHECKCAST, ind);
}
@@ -447,7 +447,7 @@ pub fn write_instruction<'b, 'a>(pool: &'b mut (ConstantPool<'a> + 'a), method:
let args = instr.args.as_ref().unwrap();
let rtype = called_id.return_type;

for (reg, desc) in args.iter().zip(called_id.spaced_param_types(isstatic)) {
for (reg, desc) in args.iter().zip(called_id.spaced_param_types(dex, isstatic)) {
if let Some(desc) = desc { // skip long/double tops
block.load_desc(*reg, desc);
}
@@ -64,7 +64,7 @@ fn write_methods<'a>(pool: &mut (ConstantPool<'a> + 'a), stream: &mut Writer, me
for method in methods {
stream.u16(method.access as u16 & flags::METHOD_FLAGS);
stream.u16(pool.utf8(method.id.name));
stream.u16(pool._utf8(method.id.desc.into()));
stream.u16(pool.utf8(method.id.desc));

match code_attrs.get(&method.id.method_idx) {
Some(data) => {
@@ -149,7 +149,7 @@ pub fn write_bytecode<'b, 'a>(pool: &'b mut (ConstantPool<'a> + 'a), method: &de
}

let isstatic = method.access as u16 & flags::ACC_STATIC != 0;
let arg_descs = method.id.spaced_param_types(isstatic);
let arg_descs = method.id.spaced_param_types(dex, isstatic);
let regoff = code.nregs - arg_descs.len() as u16;
let mut iargs = Vec::with_capacity(arg_descs.len());
for (i, optdesc) in arg_descs.iter().enumerate() {
@@ -83,23 +83,29 @@ impl T {
}
}

pub fn to_desc(self) -> BString {
// todo: return static slice?
pub fn to_desc(self) -> &'static bstr {
if let T::Array(dim, base) = self {
let mut res = vec![b'['; dim as usize];
res.push(match base {
Base::B => b'B',
Base::C => b'C',
Base::S => b'S',
Base::I => b'I',
Base::F => b'F',
Base::J => b'J',
Base::D => b'D',
});
res
let offset = 255-dim as usize;
match base {
Base::B => &BDESC[offset..],
Base::C => &CDESC[offset..],
Base::S => &SDESC[offset..],
Base::I => &IDESC[offset..],
Base::F => &FDESC[offset..],
Base::J => &JDESC[offset..],
Base::D => &DDESC[offset..],
}
} else { unreachable!(); }
}
}

static BDESC: &'static bstr = b"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[B";
static CDESC: &'static bstr = b"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[C";
static SDESC: &'static bstr = b"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[S";
static IDESC: &'static bstr = b"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[I";
static FDESC: &'static bstr = b"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[F";
static JDESC: &'static bstr = b"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[J";
static DDESC: &'static bstr = b"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[D";

pub const INVALID: T = T::Invalid;
pub const NULL: T = T::Null;

0 comments on commit f9a22c9

Please sign in to comment.