1 Commits

Author SHA1 Message Date
6096bb431a Playing around with non enum based bytecode 2022-02-01 09:08:09 +01:00
2 changed files with 135 additions and 142 deletions

View File

@@ -2,40 +2,50 @@ use std::collections::HashMap;
use crate::ast::{Ast, Expr, Stmt, BinOpType}; use crate::ast::{Ast, Expr, Stmt, BinOpType};
pub mod op { type OpcodeSize = u32;
type OpSize = u32;
pub const PUSH: OpSize = 0; #[repr(u32)]
pub const POP: OpSize = 1; #[derive(Debug, Clone, Copy)]
pub const LOAD: OpSize = 2; pub enum OP {
pub const STORE: OpSize = 3; Push,
pub const ADD: OpSize = 4; Pop,
pub const SUB: OpSize = 5; Load,
pub const MUL: OpSize = 6; Store,
pub const DIV: OpSize = 7;
pub const MOD: OpSize = 8; Add,
pub const BOR: OpSize = 9; Subtract,
pub const BAND: OpSize = 10; Multiply,
pub const BXOR: OpSize = 11; Divide,
pub const SHL: OpSize = 12; Modulo,
pub const SHR: OpSize = 13; BOr,
pub const EQ: OpSize = 14; BAnd,
pub const NEQ: OpSize = 15; BXor,
pub const GT: OpSize = 16; Shl,
pub const GE: OpSize = 17; Shr,
pub const LT: OpSize = 18;
pub const LE: OpSize = 19; Eq,
pub const JUMP: OpSize = 20; Neq,
pub const JUMP_TRUE: OpSize = 21;
pub const JUMP_FALSE: OpSize = 22; Gt,
pub const PRINT: OpSize = 23; Ge,
pub const DBG_PRINT: OpSize = 24; Lt,
Le,
Jump,
JumpTrue,
JumpFalse,
Print,
DbgPrint,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Compiler { pub struct Compiler {
ops: Vec<u32>, ops: Vec<u32>,
global_vars: HashMap<String, u16>, global_vars: HashMap<String, u64>,
} }
impl Compiler { impl Compiler {
@@ -48,30 +58,26 @@ impl Compiler {
match stmt { match stmt {
Stmt::Expr(expr) => { Stmt::Expr(expr) => {
self.compile_expr(expr); self.compile_expr(expr);
self.ops.push(op::POP); self.ops.push(OP::Pop as OpcodeSize);
} }
Stmt::Let(name, rhs) => { Stmt::Let(name, rhs) => {
let id = self.global_vars.len() as u16; let id = self.global_vars.len() as u64;
self.global_vars.insert(name.clone(), id); self.global_vars.insert(name.clone(), id);
self.compile_expr(rhs); self.compile_expr(rhs);
self.gen_store(id); self.gen_store(id);
} }
Stmt::While(cond, body) => { Stmt::While(cond, body) => {
let idx_start = self.ops.len();
self.compile_expr(cond); self.compile_expr(cond);
self.ops.push(op::JUMP_FALSE); self.ops.push(OP::JumpFalse as OpcodeSize);
let idx_jmp = self.ops.len(); let idx_jmp = self.ops.len();
self.gen_i64(0); self.gen_i64(0);
let idx_start = self.ops.len();
self.compile(body); self.compile(body);
// check condition before loop jump self.ops.push(OP::Jump as OpcodeSize);
self.compile_expr(cond);
self.ops.push(op::JUMP_TRUE);
self.gen_i64(idx_start as i64); self.gen_i64(idx_start as i64);
self.overwrite_i64(idx_jmp, self.ops.len() as i64); self.overwrite_i64(idx_jmp, self.ops.len() as i64);
@@ -80,13 +86,13 @@ impl Compiler {
Stmt::If(cond, if_block, else_block) => { Stmt::If(cond, if_block, else_block) => {
self.compile_expr(cond); self.compile_expr(cond);
self.ops.push(op::JUMP_FALSE); self.ops.push(OP::JumpFalse as OpcodeSize);
let idx_if = self.ops.len(); let idx_if = self.ops.len();
self.gen_i64(0); self.gen_i64(0);
self.compile(if_block); self.compile(if_block);
self.ops.push(op::JUMP); self.ops.push(OP::Jump as OpcodeSize);
let idx_else = self.ops.len(); let idx_else = self.ops.len();
self.gen_i64(0); self.gen_i64(0);
@@ -99,11 +105,11 @@ impl Compiler {
}, },
Stmt::DbgPrint(expr) => { Stmt::DbgPrint(expr) => {
self.compile_expr(expr); self.compile_expr(expr);
self.ops.push(op::DBG_PRINT); self.ops.push(OP::DbgPrint as OpcodeSize);
} }
Stmt::Print(expr) => { Stmt::Print(expr) => {
self.compile_expr(expr); self.compile_expr(expr);
self.ops.push(op::PRINT); self.ops.push(OP::Print as OpcodeSize);
} }
} }
} }
@@ -116,7 +122,7 @@ impl Compiler {
pub fn compile_expr(&mut self, expr: &Expr) { pub fn compile_expr(&mut self, expr: &Expr) {
match expr { match expr {
Expr::I64(val) => { Expr::I64(val) => {
self.ops.push(op::PUSH); self.ops.push(OP::Push as OpcodeSize);
self.gen_i64(*val) self.gen_i64(*val)
} }
Expr::Ident(name) => { Expr::Ident(name) => {
@@ -149,44 +155,52 @@ impl Compiler {
self.compile_expr(rhs); self.compile_expr(rhs);
match bo { match bo {
BinOpType::Add => self.ops.push(op::ADD), BinOpType::Add => self.ops.push(OP::Add as OpcodeSize),
BinOpType::Sub => self.ops.push(op::SUB), BinOpType::Sub => self.ops.push(OP::Subtract as OpcodeSize),
BinOpType::Mul => self.ops.push(op::MUL), BinOpType::Mul => self.ops.push(OP::Multiply as OpcodeSize),
BinOpType::Div => self.ops.push(op::DIV), BinOpType::Div => self.ops.push(OP::Divide as OpcodeSize),
BinOpType::Mod => self.ops.push(op::MOD), BinOpType::Mod => self.ops.push(OP::Modulo as OpcodeSize),
BinOpType::BOr => self.ops.push(op::BOR), BinOpType::BOr => self.ops.push(OP::BOr as OpcodeSize),
BinOpType::BAnd => self.ops.push(op::BAND), BinOpType::BAnd => self.ops.push(OP::BAnd as OpcodeSize),
BinOpType::BXor => self.ops.push(op::BXOR), BinOpType::BXor => self.ops.push(OP::BXor as OpcodeSize),
BinOpType::Shl => self.ops.push(op::SHL), BinOpType::Shl => self.ops.push(OP::Shl as OpcodeSize),
BinOpType::Shr => self.ops.push(op::SHR), BinOpType::Shr => self.ops.push(OP::Shr as OpcodeSize),
BinOpType::Equ => self.ops.push(op::EQ), BinOpType::Equ => self.ops.push(OP::Eq as OpcodeSize),
BinOpType::Neq => self.ops.push(op::NEQ), BinOpType::Neq => self.ops.push(OP::Neq as OpcodeSize),
BinOpType::Gt => self.ops.push(op::GT), BinOpType::Gt => self.ops.push(OP::Gt as OpcodeSize),
BinOpType::Ge => self.ops.push(op::GE), BinOpType::Ge => self.ops.push(OP::Ge as OpcodeSize),
BinOpType::Lt => self.ops.push(op::LT), BinOpType::Lt => self.ops.push(OP::Lt as OpcodeSize),
BinOpType::Le => self.ops.push(op::LE), BinOpType::Le => self.ops.push(OP::Le as OpcodeSize),
BinOpType::Assign => unreachable!(), BinOpType::Assign => unreachable!(),
} }
} }
fn gen_i64(&mut self, val: i64) { fn gen_i64(&mut self, val: i64) {
self.ops.push((val & u32::MAX as i64) as u32); // for i in 0 .. 8 {
self.ops.push((val >> 32) as u32); // self.ops.push(((val >> i*8) & 0xff) as OpcodeSize);
// }
for i in 0 .. 2 {
self.ops.push(((val >> i*32) & 0xffffffff) as OpcodeSize);
}
} }
fn overwrite_i64(&mut self, idx: usize, val: i64) { fn overwrite_i64(&mut self, idx: usize, val: i64) {
self.ops[idx] = (val & u32::MAX as i64) as u32; // for i in 0 .. 8 {
self.ops[idx+1] = (val >> 32) as u32; // self.ops[idx+i] = ((val >> i*8) & 0xff) as OpcodeSize;
// }
for i in 0 .. 2 {
self.ops[idx+i] = ((val >> i*32) & 0xffffffff) as OpcodeSize;
}
} }
fn gen_load(&mut self, addr: u16) { fn gen_load(&mut self, addr: u64) {
self.ops.push(op::LOAD | (addr << 8) as u32); self.ops.push(OP::Load as OpcodeSize);
// self.gen_i64(addr as i64) self.gen_i64(addr as i64)
} }
fn gen_store(&mut self, addr: u16) { fn gen_store(&mut self, addr: u64) {
self.ops.push(op::STORE | (addr << 8) as u32); self.ops.push(OP::Store as OpcodeSize);
// self.gen_i64(addr as i64) self.gen_i64(addr as i64)
} }
} }

127
src/vm.rs
View File

@@ -1,4 +1,4 @@
use crate::{bytecode::op::*, interpreter::Value}; use crate::{bytecode::OP, interpreter::Value};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Vm { pub struct Vm {
@@ -10,19 +10,6 @@ pub struct Vm {
heap: Vec<Value>, heap: Vec<Value>,
} }
macro_rules! binop_stack {
($self:ident, $op:tt) => {
{
let rhs = $self.stack.pop().unwrap();
let lhs = $self.stack.last_mut().unwrap();
match (lhs, rhs) {
(Value::I64(lhs), Value::I64(rhs)) => *lhs = *lhs $op rhs,
_ => panic!("Invalid data for add"),
}
}
};
}
impl Vm { impl Vm {
pub fn new(prog: Vec<u32>) -> Self { pub fn new(prog: Vec<u32>) -> Self {
Self { Self {
@@ -32,20 +19,19 @@ impl Vm {
} }
pub fn run(&mut self) { pub fn run(&mut self) {
while let Some(op) = self.prog.get(self.ip).copied() { while let Some(op) = self.prog.get(self.ip).copied().map(|op| unsafe { std::mem::transmute::<u32, OP>(op) }) {
self.ip += 1; self.ip += 1;
match op & 0xff { match op {
PUSH => { OP::Push => {
let val = self.read_i64(); let val = self.read_i64();
self.stack.push(Value::I64(val)); self.stack.push(Value::I64(val));
} }
POP => { OP::Pop => {
self.stack.pop(); self.stack.pop();
} }
LOAD => { OP::Load => {
// let addr = self.read_i64() as usize; let addr = self.read_i64() as usize;
let addr = (op >> 8) as usize;
if let Some(val) = self.heap.get(addr) { if let Some(val) = self.heap.get(addr) {
self.stack.push(val.clone()); self.stack.push(val.clone());
@@ -53,28 +39,26 @@ impl Vm {
panic!("Trying to load from uninitialized heap"); panic!("Trying to load from uninitialized heap");
} }
} }
STORE => { OP::Store => {
let val = self let val = self
.stack .stack
.pop() .pop()
.expect("Trying to pop value from stack for storing"); .expect("Trying to pop value from stack for storing");
// let addr = self.read_i64() as usize; let addr = self.read_i64() as usize;
let addr = (op >> 8) as usize;
if self.heap.len() == addr { if self.heap.len() == addr {
self.heap.push(val); self.heap.push(val);
} else { } else {
self.heap[addr] = val; self.heap[addr] = val;
} }
} }
PRINT => { OP::Print => {
let val = self let val = self
.stack .stack
.pop() .pop()
.expect("Trying to pop value from stack for printing"); .expect("Trying to pop value from stack for printing");
print!("{}", val); print!("{}", val);
} }
DBG_PRINT => { OP::DbgPrint => {
let val = self let val = self
.stack .stack
.pop() .pop()
@@ -82,96 +66,91 @@ impl Vm {
print!("{:?}", val); print!("{:?}", val);
} }
ADD => { OP::Add => {
binop_stack!(self, +); let vals = self.pop2_i64();
// self.stack.push(Value::I64(vals.0 + vals.1)) self.stack.push(Value::I64(vals.0 + vals.1))
} }
SUB => { OP::Subtract => {
binop_stack!(self, -); let vals = self.pop2_i64();
// let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 - vals.1))
// self.stack.push(Value::I64(vals.0 - vals.1))
} }
MUL => { OP::Multiply => {
binop_stack!(self, *); let vals = self.pop2_i64();
// let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 * vals.1))
// self.stack.push(Value::I64(vals.0 * vals.1))
} }
DIV => { OP::Divide => {
binop_stack!(self, /); let vals = self.pop2_i64();
// let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 / vals.1))
// self.stack.push(Value::I64(vals.0 / vals.1))
} }
MOD => { OP::Modulo => {
binop_stack!(self, %); let vals = self.pop2_i64();
// let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 % vals.1))
// self.stack.push(Value::I64(vals.0 % vals.1))
} }
EQ => { OP::Eq => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack self.stack
.push(Value::I64(if vals.0 == vals.1 { 1 } else { 0 })) .push(Value::I64(if vals.0 == vals.1 { 1 } else { 0 }))
} }
NEQ => { OP::Neq => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack self.stack
.push(Value::I64(if vals.0 != vals.1 { 1 } else { 0 })) .push(Value::I64(if vals.0 != vals.1 { 1 } else { 0 }))
} }
GT => { OP::Gt => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack self.stack
.push(Value::I64(if vals.0 > vals.1 { 1 } else { 0 })) .push(Value::I64(if vals.0 > vals.1 { 1 } else { 0 }))
} }
GE => { OP::Ge => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack self.stack
.push(Value::I64(if vals.0 >= vals.1 { 1 } else { 0 })) .push(Value::I64(if vals.0 >= vals.1 { 1 } else { 0 }))
} }
LT => { OP::Lt => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack self.stack
.push(Value::I64(if vals.0 < vals.1 { 1 } else { 0 })) .push(Value::I64(if vals.0 < vals.1 { 1 } else { 0 }))
} }
LE => { OP::Le => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack self.stack
.push(Value::I64(if vals.0 <= vals.1 { 1 } else { 0 })) .push(Value::I64(if vals.0 <= vals.1 { 1 } else { 0 }))
} }
BOR => { OP::BOr => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 | vals.1)) self.stack.push(Value::I64(vals.0 | vals.1))
} }
BAND => { OP::BAnd => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 & vals.1)) self.stack.push(Value::I64(vals.0 & vals.1))
} }
BXOR => { OP::BXor => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 ^ vals.1)) self.stack.push(Value::I64(vals.0 ^ vals.1))
} }
SHL => { OP::Shl => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 << vals.1)) self.stack.push(Value::I64(vals.0 << vals.1))
} }
SHR => { OP::Shr => {
let vals = self.pop2_i64(); let vals = self.pop2_i64();
self.stack.push(Value::I64(vals.0 >> vals.1)) self.stack.push(Value::I64(vals.0 >> vals.1))
} }
JUMP => { OP::Jump => {
self.ip = self.read_i64() as usize; self.ip = self.read_i64() as usize;
} }
JUMP_TRUE => { OP::JumpTrue => {
let jmp_target = self.read_i64() as usize; let jmp_target = self.read_i64() as usize;
if !matches!(self.stack.pop(), Some(Value::I64(0))) { if !matches!(self.stack.pop(), Some(Value::I64(0))) {
self.ip = jmp_target; self.ip = jmp_target;
} }
} }
JUMP_FALSE => { OP::JumpFalse => {
let jmp_target = self.read_i64() as usize; let jmp_target = self.read_i64() as usize;
if matches!(self.stack.pop(), Some(Value::I64(0))) { if matches!(self.stack.pop(), Some(Value::I64(0))) {
self.ip = jmp_target; self.ip = jmp_target;
} }
} }
_ => panic!("Invalid opcode")
} }
} }
} }
@@ -186,22 +165,22 @@ impl Vm {
} }
fn read_i64(&mut self) -> i64 { fn read_i64(&mut self) -> i64 {
let mut val = if let Some(val) = self.prog.get(self.ip).copied() { let mut val = *self.prog.get(self.ip).unwrap() as i64;
val val |= (*self.prog.get(self.ip + 1).unwrap() as i64) << 32;
} else {
panic!("Expected Value as next OP")
} as i64;
self.ip += 1; // let mut bytes = [0; 8];
// bytes.copy_from_slice(&self.prog[self.ip..self.ip+8]);
// val = i64::from_le_bytes(bytes);
val |= (if let Some(val) = self.prog.get(self.ip).copied() { // for i in 0 .. 8 {
val // if let Some(tmp) = self.prog.get(self.ip + i).copied() {
} else { // val |= ((tmp as i64) << i*8) as i64;
panic!("Expected Value as next OP") // } else {
} as i64) // panic!("Expected Value as next OP")
<< 32; // }
// }
self.ip += 1; self.ip += 2;
val val
} }