Skip to content

Commit

Permalink
create dedicated bytecode_offset crate
Browse files Browse the repository at this point in the history
  • Loading branch information
codehag committed Apr 8, 2020
1 parent fc6db80 commit 7b590b5
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 57 deletions.
3 changes: 3 additions & 0 deletions crates/emitter/scripts/update_opcodes.py
Expand Up @@ -389,6 +389,9 @@ def generate_emit_methods(out_f, opcodes, types):
assert len(params) == 1
assert params[0][0] == 'u32'
params[0] = ('GCThingIndex', params[0][1])
elif 'JOF_JUMP' in opcode.format_:
assert params[0][0] == 'i32'
params[0] = ('BytecodeOffsetDiff', params[0][1])
else:
assert int(opcode.nuses) != -1

Expand Down
60 changes: 60 additions & 0 deletions crates/emitter/src/bytecode_offset.rs
@@ -0,0 +1,60 @@
/// For tracking bytecode offsets in jumps
#[derive(Clone, Copy, PartialEq, Debug)]
#[must_use]
pub struct BytecodeOffset {
pub offset: usize,
}

impl BytecodeOffset {
fn new(offset: usize) -> Self {
Self { offset }
}

/// diff_from is useful for finding the offset between two bytecodes. This is usually
/// used for jumps and jump_targets.
///
/// For a forward jump, self will be a larger number, and start will be smaller
/// the output will be a positive number. for a backward jump, the reverse
/// will be true, and the number will be negative. So it is important to use this api
/// consistently in both cases.
///
/// Examples:
/// let offset_diff: BytecodeOffsetDiff = forward_jump_target_offset.diff_from(jump)
/// let offset_diff: BytecodeOffsetDiff = backward_jump_target_offset.diff_from(jump)
pub fn diff_from(self, start: BytecodeOffset) -> BytecodeOffsetDiff {
BytecodeOffsetDiff::new(self, start)
}
}

impl From<BytecodeOffset> for usize {
fn from(offset: BytecodeOffset) -> usize {
offset.offset
}
}

impl From<usize> for BytecodeOffset {
fn from(offset: usize) -> BytecodeOffset {
BytecodeOffset::new(offset)
}
}

pub struct BytecodeOffsetDiff {
diff: i32,
}

impl BytecodeOffsetDiff {
fn new(end: BytecodeOffset, start: BytecodeOffset) -> Self {
let diff = (end.offset as i128 - start.offset as i128) as i32;
Self { diff }
}

pub fn uninitialized() -> Self {
Self { diff: 0i32 }
}
}

impl From<BytecodeOffsetDiff> for i32 {
fn from(offset: BytecodeOffsetDiff) -> i32 {
offset.diff
}
}
7 changes: 3 additions & 4 deletions crates/emitter/src/control_structures.rs
@@ -1,6 +1,5 @@
use super::emitter::BytecodeOffset;
use super::emitter::BytecodeOffsetDiff;
use crate::ast_emitter::AstEmitter;
use crate::bytecode_offset::{BytecodeOffset, BytecodeOffsetDiff};
use crate::emitter::EmitError;
use crate::emitter::InstructionWriter;

Expand Down Expand Up @@ -39,7 +38,7 @@ trait Jump {
// and four bytes are used in order to save memory. We are not using that
// here, so instead we are using a placeholder offset set to 0, which will
// be updated later in patch_and_emit_jump_target.
let placeholder_offset = BytecodeOffsetDiff{ diff: 0 };
let placeholder_offset = BytecodeOffsetDiff::uninitialized();
match self.jump_kind() {
JumpKind::Coalesce { .. } => {
emitter.emit.coalesce(placeholder_offset);
Expand Down Expand Up @@ -186,7 +185,7 @@ impl LoopControl {

pub fn emit_end_target(self, emit: &mut InstructionWriter) {
let offset = emit.bytecode_offset();
let diff = BytecodeOffsetDiff::new(self.head, offset);
let diff = self.head.diff_from(offset);

emit.goto_(diff);

Expand Down
79 changes: 27 additions & 52 deletions crates/emitter/src/emitter.rs
Expand Up @@ -5,6 +5,7 @@
// Most of this functionality isn't used yet.
#![allow(dead_code)]

use crate::bytecode_offset::{BytecodeOffset, BytecodeOffsetDiff};
use crate::compilation_info::CompilationInfo;
use crate::gcthings::{GCThing, GCThingIndex, GCThingList};
use crate::opcode::Opcode;
Expand Down Expand Up @@ -99,42 +100,6 @@ pub enum SrcNoteType {
#[allow(non_camel_case_types)]
pub type u24 = u32;

/// For tracking bytecode offsets in jumps
#[derive(Clone, Copy, PartialEq, Debug)]
#[must_use]
pub struct BytecodeOffset {
pub offset: usize,
}

impl BytecodeOffset {
fn new(offset: usize) -> Self {
Self { offset }
}

pub fn end(self, emit: &InstructionWriter) -> usize {
// find the offset after the end of bytecode associated with this offset.
let target_opcode = Opcode::try_from(emit.bytecode[self.offset]).unwrap();
self.offset + target_opcode.instruction_length()
}
}

impl From<BytecodeOffset> for usize {
fn from(offset: BytecodeOffset) -> usize {
offset.offset
}
}

pub struct BytecodeOffsetDiff {
pub diff: i32,
}

impl BytecodeOffsetDiff {
pub fn new(offset1: BytecodeOffset, offset2: BytecodeOffset) -> Self {
let diff = (offset1.offset as f64 - offset2.offset as f64) as i32;
Self { diff }
}
}

/// Low-level bytecode emitter.
pub struct InstructionWriter {
bytecode: Vec<u8>,
Expand Down Expand Up @@ -236,7 +201,7 @@ impl InstructionWriter {
scope_notes: ScopeNoteList::new(),
regexps: RegExpList::new(),
last_jump_target_offset: None,
main_offset: BytecodeOffset::new(0),
main_offset: BytecodeOffset::from(0usize),
max_fixed_slots: FrameSlot::new(0),
stack_depth: 0,
maximum_stack_depth: 0,
Expand Down Expand Up @@ -325,6 +290,10 @@ impl InstructionWriter {
self.write_i32(offset);
}

fn write_bytecode_offset_diff(&mut self, offset: BytecodeOffsetDiff) {
self.write_i32(i32::from(offset));
}

fn write_f64(&mut self, val: f64) {
self.bytecode
.extend_from_slice(&val.to_bits().to_le_bytes());
Expand Down Expand Up @@ -401,6 +370,12 @@ impl InstructionWriter {
self.last_jump_target_offset = Some(target);
}

fn get_end_of_bytecode(&mut self, offset: BytecodeOffset) -> usize {
// find the offset after the end of bytecode associated with this offset.
let target_opcode = Opcode::try_from(self.bytecode[offset.offset]).unwrap();
offset.offset + target_opcode.instruction_length()
}

pub fn get_atom_index(&mut self, value: SourceAtomSetIndex) -> ScriptAtomSetIndex {
self.atoms.insert(value)
}
Expand All @@ -410,7 +385,7 @@ impl InstructionWriter {
let last_jump = self.last_jump_target_offset;
match last_jump {
Some(offset) => {
if offset.end(self) != target.offset {
if self.get_end_of_bytecode(offset) != target.offset {
self.jump_target();
self.set_last_jump_target_offset(target);
} else {
Expand All @@ -429,14 +404,14 @@ impl InstructionWriter {
}

pub fn patch_jump_to_target(&mut self, target: BytecodeOffset, jump: BytecodeOffset) {
let diff = BytecodeOffsetDiff::new(target, jump).diff as i32;
let diff = target.diff_from(jump).into();
let index = jump.offset + 1;
// FIXME: Use native endian instead of little endian
LittleEndian::write_i32(&mut self.bytecode[index..index + 4], diff);
}

pub fn bytecode_offset(&mut self) -> BytecodeOffset {
BytecodeOffset::new(self.bytecode.len())
BytecodeOffset::from(self.bytecode.len())
}

pub fn stack_depth(&self) -> usize {
Expand Down Expand Up @@ -1068,42 +1043,42 @@ impl InstructionWriter {

pub fn goto_(&mut self, offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::Goto);
self.write_i32(offset.diff);
self.write_bytecode_offset_diff(offset);
}

pub fn if_eq(&mut self, forward_offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::IfEq);
self.write_i32(forward_offset.diff);
self.write_bytecode_offset_diff(forward_offset);
}

pub fn if_ne(&mut self, offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::IfNe);
self.write_i32(offset.diff);
self.write_bytecode_offset_diff(offset);
}

pub fn and_(&mut self, forward_offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::And);
self.write_i32(forward_offset.diff);
self.write_bytecode_offset_diff(forward_offset);
}

pub fn or_(&mut self, forward_offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::Or);
self.write_i32(forward_offset.diff);
self.write_bytecode_offset_diff(forward_offset);
}

pub fn coalesce(&mut self, forward_offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::Coalesce);
self.write_i32(forward_offset.diff);
self.write_bytecode_offset_diff(forward_offset);
}

pub fn case_(&mut self, forward_offset: i32) {
pub fn case_(&mut self, forward_offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::Case);
self.write_i32(forward_offset);
self.write_bytecode_offset_diff(forward_offset);
}

pub fn default_(&mut self, forward_offset: i32) {
pub fn default_(&mut self, forward_offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::Default);
self.write_i32(forward_offset);
self.write_bytecode_offset_diff(forward_offset);
}

pub fn return_(&mut self) {
Expand Down Expand Up @@ -1158,9 +1133,9 @@ impl InstructionWriter {
self.write_u24(resume_index);
}

pub fn gosub(&mut self, forward_offset: i32) {
pub fn gosub(&mut self, forward_offset: BytecodeOffsetDiff) {
self.emit_op(Opcode::Gosub);
self.write_i32(forward_offset);
self.write_bytecode_offset_diff(forward_offset);
}

pub fn finally(&mut self) {
Expand Down
1 change: 1 addition & 0 deletions crates/emitter/src/lib.rs
@@ -1,6 +1,7 @@
mod array_emitter;
mod ast_emitter;
mod block_emitter;
mod bytecode_offset;
mod compilation_info;
mod control_structures;
mod dis;
Expand Down
2 changes: 1 addition & 1 deletion crates/emitter/src/scope_notes.rs
@@ -1,4 +1,4 @@
use crate::emitter::BytecodeOffset;
use crate::bytecode_offset::BytecodeOffset;
use crate::gcthings::GCThingIndex;

/// Maps to js::ScopeNote in m-c/js/src/vm//JSScript.h.
Expand Down

0 comments on commit 7b590b5

Please sign in to comment.