Hide instruction encoding behind isa::Instructions::push()

This commit is contained in:
Will Glynn 2018-10-07 13:31:42 -05:00
parent 14857145d1
commit f928cc8188
2 changed files with 54 additions and 44 deletions

View File

@ -93,6 +93,22 @@ pub struct Target {
pub drop_keep: DropKeep, pub drop_keep: DropKeep,
} }
/// A relocation entry that specifies.
#[derive(Debug)]
pub enum Reloc {
/// Patch the destination of the branch instruction (br, br_eqz, br_nez)
/// at the specified pc.
Br {
pc: u32,
},
/// Patch the specified destination index inside of br_table instruction at
/// the specified pc.
BrTable {
pc: u32,
idx: usize,
},
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Instruction { pub enum Instruction {
/// Push a local variable or an argument from the specified depth. /// Push a local variable or an argument from the specified depth.
@ -303,11 +319,32 @@ pub struct Instructions {
} }
impl Instructions { impl Instructions {
pub fn new<I>(instructions: I) -> Self pub fn with_capacity(capacity: usize) -> Self {
where I: IntoIterator<Item=Instruction>
{
Instructions { Instructions {
vec: instructions.into_iter().collect() vec: Vec::with_capacity(capacity),
}
}
pub fn current_pc(&self) -> u32 {
self.vec.len() as u32
}
pub fn push(&mut self, instruction: Instruction) {
self.vec.push(instruction);
}
pub fn patch_relocation(&mut self, reloc: Reloc, dst_pc: u32) {
match reloc {
Reloc::Br { pc } => match self.vec[pc as usize] {
Instruction::Br(ref mut target)
| Instruction::BrIfEqz(ref mut target)
| Instruction::BrIfNez(ref mut target) => target.dst_pc = dst_pc,
_ => panic!("branch relocation points to a non-branch instruction"),
},
Reloc::BrTable { pc, idx } => match self.vec[pc as usize] {
Instruction::BrTable(ref mut targets) => targets[idx].dst_pc = dst_pc,
_ => panic!("brtable relocation points to not brtable instruction"),
}
} }
} }

View File

@ -1406,7 +1406,7 @@ impl<'a> FunctionValidationContext<'a> {
} }
fn into_code(self) -> isa::Instructions { fn into_code(self) -> isa::Instructions {
isa::Instructions::new(self.sink.into_inner()) self.sink.into_inner()
} }
} }
@ -1626,22 +1626,6 @@ struct Target {
drop_keep: isa::DropKeep, drop_keep: isa::DropKeep,
} }
/// A relocation entry that specifies.
#[derive(Debug)]
enum Reloc {
/// Patch the destination of the branch instruction (br, br_eqz, br_nez)
/// at the specified pc.
Br {
pc: u32,
},
/// Patch the specified destination index inside of br_table instruction at
/// the specified pc.
BrTable {
pc: u32,
idx: usize,
},
}
/// Identifier of a label. /// Identifier of a label.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct LabelId(usize); struct LabelId(usize);
@ -1653,23 +1637,23 @@ enum Label {
} }
struct Sink { struct Sink {
ins: Vec<isa::Instruction>, ins: isa::Instructions,
labels: Vec<(Label, Vec<Reloc>)>, labels: Vec<(Label, Vec<isa::Reloc>)>,
} }
impl Sink { impl Sink {
fn with_instruction_capacity(capacity: usize) -> Sink { fn with_instruction_capacity(capacity: usize) -> Sink {
Sink { Sink {
ins: Vec::with_capacity(capacity), ins: isa::Instructions::with_capacity(capacity),
labels: Vec::new(), labels: Vec::new(),
} }
} }
fn cur_pc(&self) -> u32 { fn cur_pc(&self) -> u32 {
self.ins.len() as u32 self.ins.current_pc()
} }
fn pc_or_placeholder<F: FnOnce() -> Reloc>(&mut self, label: LabelId, reloc_creator: F) -> u32 { fn pc_or_placeholder<F: FnOnce() -> isa::Reloc>(&mut self, label: LabelId, reloc_creator: F) -> u32 {
match self.labels[label.0] { match self.labels[label.0] {
(Label::Resolved(dst_pc), _) => dst_pc, (Label::Resolved(dst_pc), _) => dst_pc,
(Label::NotResolved, ref mut unresolved) => { (Label::NotResolved, ref mut unresolved) => {
@ -1690,7 +1674,7 @@ impl Sink {
drop_keep, drop_keep,
} = target; } = target;
let pc = self.cur_pc(); let pc = self.cur_pc();
let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc }); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc });
self.ins.push(isa::Instruction::Br(isa::Target { self.ins.push(isa::Instruction::Br(isa::Target {
dst_pc, dst_pc,
drop_keep: drop_keep.into(), drop_keep: drop_keep.into(),
@ -1703,7 +1687,7 @@ impl Sink {
drop_keep, drop_keep,
} = target; } = target;
let pc = self.cur_pc(); let pc = self.cur_pc();
let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc }); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc });
self.ins.push(isa::Instruction::BrIfEqz(isa::Target { self.ins.push(isa::Instruction::BrIfEqz(isa::Target {
dst_pc, dst_pc,
drop_keep: drop_keep.into(), drop_keep: drop_keep.into(),
@ -1716,7 +1700,7 @@ impl Sink {
drop_keep, drop_keep,
} = target; } = target;
let pc = self.cur_pc(); let pc = self.cur_pc();
let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc }); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc });
self.ins.push(isa::Instruction::BrIfNez(isa::Target { self.ins.push(isa::Instruction::BrIfNez(isa::Target {
dst_pc, dst_pc,
drop_keep: drop_keep.into(), drop_keep: drop_keep.into(),
@ -1729,7 +1713,7 @@ impl Sink {
let pc = self.cur_pc(); let pc = self.cur_pc();
let mut isa_targets = Vec::new(); let mut isa_targets = Vec::new();
for (idx, &Target { label, drop_keep }) in targets.iter().chain(iter::once(&default)).enumerate() { for (idx, &Target { label, drop_keep }) in targets.iter().chain(iter::once(&default)).enumerate() {
let dst_pc = self.pc_or_placeholder(label, || Reloc::BrTable { pc, idx }); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::BrTable { pc, idx });
isa_targets.push( isa_targets.push(
isa::Target { isa::Target {
dst_pc, dst_pc,
@ -1766,26 +1750,15 @@ impl Sink {
// particular label. // particular label.
let unresolved_rels = mem::replace(&mut self.labels[label.0].1, Vec::new()); let unresolved_rels = mem::replace(&mut self.labels[label.0].1, Vec::new());
for reloc in unresolved_rels { for reloc in unresolved_rels {
match reloc { self.ins.patch_relocation(reloc, dst_pc);
Reloc::Br { pc } => match self.ins[pc as usize] {
isa::Instruction::Br(ref mut target)
| isa::Instruction::BrIfEqz(ref mut target)
| isa::Instruction::BrIfNez(ref mut target) => target.dst_pc = dst_pc,
_ => panic!("branch relocation points to a non-branch instruction"),
},
Reloc::BrTable { pc, idx } => match self.ins[pc as usize] {
isa::Instruction::BrTable(ref mut targets) => targets[idx].dst_pc = dst_pc,
_ => panic!("brtable relocation points to not brtable instruction"),
}
}
} }
// Mark this label as resolved. // Mark this label as resolved.
self.labels[label.0] = (Label::Resolved(dst_pc), Vec::new()); self.labels[label.0] = (Label::Resolved(dst_pc), Vec::new());
} }
/// Consume this Sink and returns isa::Instruction. /// Consume this Sink and returns isa::Instructions.
fn into_inner(self) -> Vec<isa::Instruction> { fn into_inner(self) -> isa::Instructions {
// At this moment all labels should be resolved. // At this moment all labels should be resolved.
assert!({ assert!({
self.labels.iter().all(|(state, unresolved)| self.labels.iter().all(|(state, unresolved)|