From dbcec700e20d055c944f6aee8f034478739af254 Mon Sep 17 00:00:00 2001 From: Jason Williams Date: Fri, 9 Oct 2020 18:05:03 +0100 Subject: [PATCH 1/3] start --- boa/Cargo.toml | 3 + boa/src/context.rs | 42 +++++++++ boa/src/lib.rs | 1 + .../syntax/ast/node/operator/bin_op/mod.rs | 15 +++ boa/src/syntax/ast/node/statement_list/mod.rs | 18 ++++ boa/src/vm/compilation.rs | 19 ++++ boa/src/vm/instructions.rs | 30 ++++++ boa/src/vm/mod.rs | 92 +++++++++++++++++++ boa_cli/Cargo.toml | 5 +- boa_cli/src/main.rs | 3 + 10 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 boa/src/vm/compilation.rs create mode 100644 boa/src/vm/instructions.rs create mode 100644 boa/src/vm/mod.rs diff --git a/boa/Cargo.toml b/boa/Cargo.toml index 419c7f79d45..2067745bfb4 100644 --- a/boa/Cargo.toml +++ b/boa/Cargo.toml @@ -13,6 +13,9 @@ edition = "2018" [features] profiler = ["measureme", "once_cell"] +# Enable Bytecode generation & execution instead of tree walking +vm = [] + # Enable Boa's WHATWG console object implementation. console = [] diff --git a/boa/src/context.rs b/boa/src/context.rs index eba8a1336db..785e40ec478 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -23,6 +23,7 @@ use crate::{ Parser, }, value::{RcString, RcSymbol, Value}, + vm::compilation::CodeGen, BoaProfiler, Executable, Result, }; use std::result::Result as StdResult; @@ -30,6 +31,9 @@ use std::result::Result as StdResult; #[cfg(feature = "console")] use crate::builtins::console::Console; +#[cfg(feature = "vm")] +use crate::vm::instructions::Instruction; + /// Store a builtin constructor (such as `Object`) and its corresponding prototype. #[derive(Debug, Clone)] pub struct StandardConstructor { @@ -196,6 +200,10 @@ pub struct Context { /// Cached standard objects and their prototypes standard_objects: StandardObjects, + + /// Holds instructions for ByteCode generation + #[cfg(feature = "vm")] + instruction_stack: Vec, } impl Default for Context { @@ -212,6 +220,8 @@ impl Default for Context { well_known_symbols, iterator_prototypes: IteratorPrototypes::default(), standard_objects: Default::default(), + #[cfg(feature = "vm")] + instruction_stack: vec![], }; // Add new builtIns to Context Realm @@ -649,6 +659,33 @@ impl Context { execution_result } + /// Evaluates the given code by compiling down to bytecode, then interpreting the bytecode into a value + /// + /// # Examples + /// ``` + ///# use boa::Context; + /// let mut context = Context::new(); + /// + /// let value = context.eval_bytecode("1 + 3").unwrap(); + /// + /// assert!(value.is_number()); + /// assert_eq!(value.as_number().unwrap(), 4.0); + /// ``` + pub fn eval_bytecode(&mut self, src: &str) -> std::result::Result<(), &str> { + let main_timer = BoaProfiler::global().start_event("Main", "Main"); + + let result = match Self::parser_expr(src) { + Ok(ref expr) => expr.compile(self), + Err(e) => panic!(e), + }; + + // The main_timer needs to be dropped before the BoaProfiler is. + drop(main_timer); + BoaProfiler::global().drop(); + + Err("not implemented") + } + /// Returns a structure that contains the JavaScript well known symbols. /// /// # Examples @@ -676,4 +713,9 @@ impl Context { pub fn standard_objects(&self) -> &StandardObjects { &self.standard_objects } + + // Add a new instruction + pub fn add_instruction(&mut self) { + self.instruction_stack.push(919); + } } diff --git a/boa/src/lib.rs b/boa/src/lib.rs index a302e468c74..9775714eedf 100644 --- a/boa/src/lib.rs +++ b/boa/src/lib.rs @@ -53,6 +53,7 @@ pub mod property; pub mod realm; pub mod syntax; pub mod value; +pub mod vm; pub mod context; diff --git a/boa/src/syntax/ast/node/operator/bin_op/mod.rs b/boa/src/syntax/ast/node/operator/bin_op/mod.rs index db8985eec2a..0eabc353abf 100644 --- a/boa/src/syntax/ast/node/operator/bin_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/bin_op/mod.rs @@ -4,6 +4,7 @@ use crate::{ node::Node, op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp}, }, + vm::compilation::CodeGen, Context, Result, Value, }; use gc::{Finalize, Trace}; @@ -185,6 +186,20 @@ impl Executable for BinOp { } } +impl CodeGen for BinOp { + fn compile(&self, ctx: &mut Context) -> std::result::Result<(), &str> { + match self.op() { + op::BinOp::Num(op) => { + self.lhs().compile(ctx); + self.rhs().compile(ctx); + } + _ => unimplemented!(), + } + + Err("Fail") + } +} + impl fmt::Display for BinOp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} {} {}", self.lhs, self.op, self.rhs) diff --git a/boa/src/syntax/ast/node/statement_list/mod.rs b/boa/src/syntax/ast/node/statement_list/mod.rs index 4c8ab7cd274..a01236c6bf8 100644 --- a/boa/src/syntax/ast/node/statement_list/mod.rs +++ b/boa/src/syntax/ast/node/statement_list/mod.rs @@ -3,6 +3,7 @@ use crate::{ exec::{Executable, InterpreterState}, syntax::ast::node::Node, + vm::compilation::CodeGen, BoaProfiler, Context, Result, Value, }; use gc::{unsafe_empty_trace, Finalize, Trace}; @@ -94,6 +95,23 @@ impl Executable for StatementList { } } +impl CodeGen for StatementList { + fn compile(&self, ctx: &mut Context) -> std::result::Result<(), &str> { + let _timer = BoaProfiler::global().start_event("StatementList", "codeGen"); + + // https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation + // The return value is uninitialized, which means it defaults to Value::Undefined + let mut obj = Value::default(); + ctx.executor() + .set_current_state(InterpreterState::Executing); + for (i, item) in self.statements().iter().enumerate() { + item.compile(ctx)?; + } + + Ok(()) + } +} + impl From for StatementList where T: Into>, diff --git a/boa/src/vm/compilation.rs b/boa/src/vm/compilation.rs new file mode 100644 index 00000000000..24a5eb9b86f --- /dev/null +++ b/boa/src/vm/compilation.rs @@ -0,0 +1,19 @@ +use super::*; +use crate::{syntax::ast::Node, Context}; +use std::result::Result; + +#[derive(Debug, Default)] +pub(crate) struct Compiler { + res: Vec, + next_free: u8, +} + +pub(crate) trait CodeGen { + fn compile(&self, ctx: &mut Context) -> Result<(), &str>; +} + +impl CodeGen for Node { + fn compile(&self, compiler: &mut Context) -> Result<(), &str> { + unimplemented!(); + } +} diff --git a/boa/src/vm/instructions.rs b/boa/src/vm/instructions.rs new file mode 100644 index 00000000000..261ff5af8dd --- /dev/null +++ b/boa/src/vm/instructions.rs @@ -0,0 +1,30 @@ +use crate::Value; + +use super::Reg; +use std::fmt::{Debug, Error, Formatter}; + +#[derive(Clone)] +pub(crate) enum Instruction { + /// Loads a value into a register + Ld(Reg, Value), + + /// Loads a value into the accumulator + Lda(Value), + + /// Binds a value from a register to an ident + Bind(Reg, String), + + /// Adds the values from destination and source and stores the result in destination + Add { dest: Reg, src: Reg }, +} + +impl Debug for Instruction { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + match self { + Self::Ld(r, v) => write!(f, "Ld\t{}\t\t{}", r, format!("{:p}", v)), + Self::Bind(r, v) => write!(f, "Bind\t{}\t\t{}", r, format!("{:p}", v)), + Self::Add { dest, src } => write!(f, "Add\t{}\t\t{}", dest, src), + _ => write!(f, "unimplemented"), + } + } +} diff --git a/boa/src/vm/mod.rs b/boa/src/vm/mod.rs new file mode 100644 index 00000000000..baf7c85991d --- /dev/null +++ b/boa/src/vm/mod.rs @@ -0,0 +1,92 @@ +use self::instructions::Instruction; +use crate::{realm::Realm, Value}; +use std::fmt::{Display, Formatter, Result}; + +pub(crate) mod compilation; +pub(crate) mod instructions; + +// === Misc +#[derive(Copy, Clone, Debug, Default)] +pub struct Reg(u8); + +impl Display for Reg { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.0) + } +} + +// === Execution +#[derive(Debug)] +pub struct VM { + realm: Realm, + accumulator: Value, + regs: Vec, // TODO: find a possible way of this being an array +} + +impl VM { + /// Sets a register's value to `undefined` and returns its previous one + fn clear(&mut self, reg: Reg) -> Value { + let v = self.regs[reg.0 as usize].clone(); + self.regs[reg.0 as usize] = Value::undefined(); + v + } + + pub fn new(realm: Realm) -> Self { + VM { + realm, + accumulator: Value::undefined(), + regs: vec![Value::undefined(); 8], + } + } + + fn set(&mut self, reg: Reg, val: Value) { + self.regs[reg.0 as usize] = val; + } + + fn set_accumulator(&mut self, val: Value) { + self.accumulator = val; + } + + // pub fn run(&mut self, instrs: &[Instruction]) -> super::Result { + // let mut idx = 0; + + // while idx < instrs.len() { + // match &instrs[idx] { + // Instruction::Ld(r, v) => self.set(*r, v.clone()), + + // Instruction::Lda(v) => self.set_accumulator(v.clone()), + + // Instruction::Bind(r, ident) => { + // let val = self.clear(*r); + + // if self.realm.environment.has_binding(ident) { + // self.realm.environment.set_mutable_binding(ident, val, true); + // } else { + // self.realm.environment.create_mutable_binding( + // ident.clone(), // fix + // true, + // VariableScope::Function, + // ); + // self.realm.environment.initialize_binding(ident, val); + // } + // } + + // Instruction::Add { dest, src } => { + // let l = self.clear(*dest); + // let r = self.clear(*src); + + // self.set(*dest, l + r); + // } + + // _ => { + // dbg!(&instrs[idx]); + // panic!(); + // } + // } + + // idx += 1; + // } + + // Ok(Ok(self.clear(Reg(0)))) + // } +} diff --git a/boa_cli/Cargo.toml b/boa_cli/Cargo.toml index a238f2338fa..7afd80532b9 100644 --- a/boa_cli/Cargo.toml +++ b/boa_cli/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" default-run = "boa" [dependencies] -Boa = { path = "../boa", features = ["serde", "console"] } +Boa = { path = "../boa", features = ["serde", "console", "vm"] } rustyline = "6.3.0" rustyline-derive = "0.3.1" structopt = "0.3.20" @@ -21,6 +21,9 @@ colored = "2.0.0" regex = "1.4.0" lazy_static = "1.4.0" +# [features] +# vm = ["Boa/vm"] + [target.x86_64-unknown-linux-gnu.dependencies] jemallocator = "0.3.2" diff --git a/boa_cli/src/main.rs b/boa_cli/src/main.rs index 8ca8fb8f7ef..4dcfd5c7662 100644 --- a/boa_cli/src/main.rs +++ b/boa_cli/src/main.rs @@ -31,6 +31,9 @@ use rustyline::{config::Config, error::ReadlineError, EditMode, Editor}; use std::{fs::read_to_string, path::PathBuf}; use structopt::{clap::arg_enum, StructOpt}; +#[cfg(feature = "vm")] +use boa::vm::VM; + mod helper; #[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))] From 0655b3ef595769dba73c2360e096c4f66cf6d98e Mon Sep 17 00:00:00 2001 From: jasonwilliams Date: Mon, 12 Oct 2020 21:25:41 +0100 Subject: [PATCH 2/3] Generating instructions into a stack --- .vscode/tasks.json | 9 +++++---- boa/src/context.rs | 16 ++++++++++------ boa/src/syntax/ast/node/operator/bin_op/mod.rs | 9 ++++++--- boa/src/syntax/ast/node/statement_list/mod.rs | 7 ++----- boa/src/vm/compilation.rs | 13 ++++++++----- boa/src/vm/instructions.rs | 12 ++++++++---- boa_cli/src/main.rs | 5 +---- 7 files changed, 40 insertions(+), 31 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7592103972a..87324c151d6 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,14 +12,15 @@ "kind": "build", "isDefault": true }, + "presentation": { + "clear": true + }, "options": { "env": { - "RUST_BACKTRACE": "full" + "RUST_BACKTRACE": "1" } }, - "presentation": { - "clear": true - } + "problemMatcher": [] }, { "type": "process", diff --git a/boa/src/context.rs b/boa/src/context.rs index 785e40ec478..ce077b5e6e1 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -23,7 +23,6 @@ use crate::{ Parser, }, value::{RcString, RcSymbol, Value}, - vm::compilation::CodeGen, BoaProfiler, Executable, Result, }; use std::result::Result as StdResult; @@ -32,6 +31,7 @@ use std::result::Result as StdResult; use crate::builtins::console::Console; #[cfg(feature = "vm")] +use crate::vm::compilation::CodeGen; use crate::vm::instructions::Instruction; /// Store a builtin constructor (such as `Object`) and its corresponding prototype. @@ -674,9 +674,13 @@ impl Context { pub fn eval_bytecode(&mut self, src: &str) -> std::result::Result<(), &str> { let main_timer = BoaProfiler::global().start_event("Main", "Main"); - let result = match Self::parser_expr(src) { - Ok(ref expr) => expr.compile(self), - Err(e) => panic!(e), + let parsing_result = Parser::new(src.as_bytes()) + .parse_all() + .map_err(|e| e.to_string()); + + let execution_result = match parsing_result { + Ok(statement_list) => statement_list.compile(self), + Err(e) => (), }; // The main_timer needs to be dropped before the BoaProfiler is. @@ -715,7 +719,7 @@ impl Context { } // Add a new instruction - pub fn add_instruction(&mut self) { - self.instruction_stack.push(919); + pub fn add_instruction(&mut self, instr: Instruction) { + self.instruction_stack.push(instr); } } diff --git a/boa/src/syntax/ast/node/operator/bin_op/mod.rs b/boa/src/syntax/ast/node/operator/bin_op/mod.rs index 0eabc353abf..b551656326c 100644 --- a/boa/src/syntax/ast/node/operator/bin_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/bin_op/mod.rs @@ -5,6 +5,7 @@ use crate::{ op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp}, }, vm::compilation::CodeGen, + vm::instructions::Instruction, Context, Result, Value, }; use gc::{Finalize, Trace}; @@ -187,16 +188,18 @@ impl Executable for BinOp { } impl CodeGen for BinOp { - fn compile(&self, ctx: &mut Context) -> std::result::Result<(), &str> { + fn compile(&self, ctx: &mut Context) { match self.op() { op::BinOp::Num(op) => { self.lhs().compile(ctx); self.rhs().compile(ctx); + match op { + NumOp::Add => ctx.add_instruction(Instruction::Add), + _ => unimplemented!(), + } } _ => unimplemented!(), } - - Err("Fail") } } diff --git a/boa/src/syntax/ast/node/statement_list/mod.rs b/boa/src/syntax/ast/node/statement_list/mod.rs index a01236c6bf8..ec6f81d9a28 100644 --- a/boa/src/syntax/ast/node/statement_list/mod.rs +++ b/boa/src/syntax/ast/node/statement_list/mod.rs @@ -96,19 +96,16 @@ impl Executable for StatementList { } impl CodeGen for StatementList { - fn compile(&self, ctx: &mut Context) -> std::result::Result<(), &str> { + fn compile(&self, ctx: &mut Context) { let _timer = BoaProfiler::global().start_event("StatementList", "codeGen"); // https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation // The return value is uninitialized, which means it defaults to Value::Undefined - let mut obj = Value::default(); ctx.executor() .set_current_state(InterpreterState::Executing); for (i, item) in self.statements().iter().enumerate() { - item.compile(ctx)?; + item.compile(ctx); } - - Ok(()) } } diff --git a/boa/src/vm/compilation.rs b/boa/src/vm/compilation.rs index 24a5eb9b86f..77b059a0f72 100644 --- a/boa/src/vm/compilation.rs +++ b/boa/src/vm/compilation.rs @@ -1,6 +1,5 @@ use super::*; -use crate::{syntax::ast::Node, Context}; -use std::result::Result; +use crate::{syntax::ast::Const, syntax::ast::Node, Context}; #[derive(Debug, Default)] pub(crate) struct Compiler { @@ -9,11 +8,15 @@ pub(crate) struct Compiler { } pub(crate) trait CodeGen { - fn compile(&self, ctx: &mut Context) -> Result<(), &str>; + fn compile(&self, ctx: &mut Context); } impl CodeGen for Node { - fn compile(&self, compiler: &mut Context) -> Result<(), &str> { - unimplemented!(); + fn compile(&self, ctx: &mut Context) { + match *self { + Node::BinOp(ref op) => op.compile(ctx), + Node::Const(Const::Int(num)) => ctx.add_instruction(Instruction::Int32(num)), + _ => unimplemented!(), + } } } diff --git a/boa/src/vm/instructions.rs b/boa/src/vm/instructions.rs index 261ff5af8dd..b3b47f92eb7 100644 --- a/boa/src/vm/instructions.rs +++ b/boa/src/vm/instructions.rs @@ -4,7 +4,10 @@ use super::Reg; use std::fmt::{Debug, Error, Formatter}; #[derive(Clone)] -pub(crate) enum Instruction { +pub enum Instruction { + // Loads an i32 onto the stack + Int32(i32), + /// Loads a value into a register Ld(Reg, Value), @@ -15,15 +18,16 @@ pub(crate) enum Instruction { Bind(Reg, String), /// Adds the values from destination and source and stores the result in destination - Add { dest: Reg, src: Reg }, + Add, } impl Debug for Instruction { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { match self { - Self::Ld(r, v) => write!(f, "Ld\t{}\t\t{}", r, format!("{:p}", v)), + Self::Add => write!(f, "Add"), + Self::Int32(i) => write!(f, "Int32\t{}", format!("{}", i)), Self::Bind(r, v) => write!(f, "Bind\t{}\t\t{}", r, format!("{:p}", v)), - Self::Add { dest, src } => write!(f, "Add\t{}\t\t{}", dest, src), + Self::Ld(r, v) => write!(f, "Ld\t{}\t\t{}", r, format!("{:p}", v)), _ => write!(f, "unimplemented"), } } diff --git a/boa_cli/src/main.rs b/boa_cli/src/main.rs index 4dcfd5c7662..8638361cbc3 100644 --- a/boa_cli/src/main.rs +++ b/boa_cli/src/main.rs @@ -152,10 +152,7 @@ pub fn main() -> Result<(), std::io::Error> { eprintln!("{}", e); } } else { - match engine.eval(&buffer) { - Ok(v) => println!("{}", v.display()), - Err(v) => eprintln!("Uncaught {}", v.display()), - } + engine.eval_bytecode(&buffer).unwrap(); } } From 7d74ec0c6d83499c8f9d8a8bc7cea6f6576d2720 Mon Sep 17 00:00:00 2001 From: jasonwilliams Date: Mon, 12 Oct 2020 22:44:02 +0100 Subject: [PATCH 3/3] basic bytecode interpreter working --- boa/src/context.rs | 20 ++++--- boa/src/vm/instructions.rs | 22 ++------ boa/src/vm/mod.rs | 104 +++++++++++-------------------------- boa_cli/src/main.rs | 5 +- 4 files changed, 52 insertions(+), 99 deletions(-) diff --git a/boa/src/context.rs b/boa/src/context.rs index ce077b5e6e1..9354ff0bbb4 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -23,6 +23,7 @@ use crate::{ Parser, }, value::{RcString, RcSymbol, Value}, + vm::VM, BoaProfiler, Executable, Result, }; use std::result::Result as StdResult; @@ -247,6 +248,10 @@ impl Context { &mut self.realm } + pub fn instructions_mut(&mut self) -> &mut Vec { + &mut self.instruction_stack + } + pub fn executor(&mut self) -> &mut Interpreter { &mut self.executor } @@ -671,23 +676,24 @@ impl Context { /// assert!(value.is_number()); /// assert_eq!(value.as_number().unwrap(), 4.0); /// ``` - pub fn eval_bytecode(&mut self, src: &str) -> std::result::Result<(), &str> { + pub fn eval_bytecode(&mut self, src: &str) -> Result { let main_timer = BoaProfiler::global().start_event("Main", "Main"); let parsing_result = Parser::new(src.as_bytes()) .parse_all() .map_err(|e| e.to_string()); - let execution_result = match parsing_result { - Ok(statement_list) => statement_list.compile(self), - Err(e) => (), - }; - + let statement_list = parsing_result.expect("unable to get statementList"); + // Generate Bytecode and place it into instruction_stack + statement_list.compile(self); + // Interpret the Bytecode + let mut vm = VM::new(self); + let result = vm.run(); // The main_timer needs to be dropped before the BoaProfiler is. drop(main_timer); BoaProfiler::global().drop(); - Err("not implemented") + result } /// Returns a structure that contains the JavaScript well known symbols. diff --git a/boa/src/vm/instructions.rs b/boa/src/vm/instructions.rs index b3b47f92eb7..1307dbb5eb8 100644 --- a/boa/src/vm/instructions.rs +++ b/boa/src/vm/instructions.rs @@ -1,24 +1,12 @@ -use crate::Value; - -use super::Reg; use std::fmt::{Debug, Error, Formatter}; -#[derive(Clone)] +#[derive(Clone, Copy)] pub enum Instruction { - // Loads an i32 onto the stack - Int32(i32), - - /// Loads a value into a register - Ld(Reg, Value), - - /// Loads a value into the accumulator - Lda(Value), - - /// Binds a value from a register to an ident - Bind(Reg, String), - /// Adds the values from destination and source and stores the result in destination Add, + + // Loads an i32 onto the stack + Int32(i32), } impl Debug for Instruction { @@ -26,8 +14,6 @@ impl Debug for Instruction { match self { Self::Add => write!(f, "Add"), Self::Int32(i) => write!(f, "Int32\t{}", format!("{}", i)), - Self::Bind(r, v) => write!(f, "Bind\t{}\t\t{}", r, format!("{:p}", v)), - Self::Ld(r, v) => write!(f, "Ld\t{}\t\t{}", r, format!("{:p}", v)), _ => write!(f, "unimplemented"), } } diff --git a/boa/src/vm/mod.rs b/boa/src/vm/mod.rs index baf7c85991d..98ad59b2f9c 100644 --- a/boa/src/vm/mod.rs +++ b/boa/src/vm/mod.rs @@ -1,92 +1,50 @@ use self::instructions::Instruction; -use crate::{realm::Realm, Value}; -use std::fmt::{Display, Formatter, Result}; +use crate::{Context, Value}; pub(crate) mod compilation; pub(crate) mod instructions; -// === Misc -#[derive(Copy, Clone, Debug, Default)] -pub struct Reg(u8); - -impl Display for Reg { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - write!(f, "{}", self.0) - } -} - // === Execution #[derive(Debug)] -pub struct VM { - realm: Realm, - accumulator: Value, - regs: Vec, // TODO: find a possible way of this being an array +pub struct VM<'a> { + ctx: &'a mut Context, + instructions: Vec, + stack: Vec, + stack_pointer: usize, } -impl VM { - /// Sets a register's value to `undefined` and returns its previous one - fn clear(&mut self, reg: Reg) -> Value { - let v = self.regs[reg.0 as usize].clone(); - self.regs[reg.0 as usize] = Value::undefined(); - v - } - - pub fn new(realm: Realm) -> Self { +impl<'a> VM<'a> { + pub fn new(ctx: &'a mut Context) -> Self { + let instr = ctx.instructions_mut().clone(); VM { - realm, - accumulator: Value::undefined(), - regs: vec![Value::undefined(); 8], + ctx, + instructions: instr, + stack: vec![], + stack_pointer: 0, } } - fn set(&mut self, reg: Reg, val: Value) { - self.regs[reg.0 as usize] = val; - } - - fn set_accumulator(&mut self, val: Value) { - self.accumulator = val; - } - - // pub fn run(&mut self, instrs: &[Instruction]) -> super::Result { - // let mut idx = 0; - - // while idx < instrs.len() { - // match &instrs[idx] { - // Instruction::Ld(r, v) => self.set(*r, v.clone()), - - // Instruction::Lda(v) => self.set_accumulator(v.clone()), + pub fn run(&mut self) -> super::Result { + let mut idx = 0; - // Instruction::Bind(r, ident) => { - // let val = self.clear(*r); + while idx < self.instructions.len() { + match self.instructions[idx] { + Instruction::Int32(i) => self.stack.push(Value::Integer(i)), + Instruction::Add => { + let r = self.stack.pop().unwrap(); + let l = self.stack.pop().unwrap(); + let val = l.add(&r, self.ctx)?; - // if self.realm.environment.has_binding(ident) { - // self.realm.environment.set_mutable_binding(ident, val, true); - // } else { - // self.realm.environment.create_mutable_binding( - // ident.clone(), // fix - // true, - // VariableScope::Function, - // ); - // self.realm.environment.initialize_binding(ident, val); - // } - // } + self.stack.push(val); + } - // Instruction::Add { dest, src } => { - // let l = self.clear(*dest); - // let r = self.clear(*src); + _ => unimplemented!(), + } - // self.set(*dest, l + r); - // } - - // _ => { - // dbg!(&instrs[idx]); - // panic!(); - // } - // } - - // idx += 1; - // } + idx += 1; + } - // Ok(Ok(self.clear(Reg(0)))) - // } + let res = self.stack.pop().unwrap(); + Ok(res) + } } diff --git a/boa_cli/src/main.rs b/boa_cli/src/main.rs index 8638361cbc3..25a20b49c38 100644 --- a/boa_cli/src/main.rs +++ b/boa_cli/src/main.rs @@ -152,7 +152,10 @@ pub fn main() -> Result<(), std::io::Error> { eprintln!("{}", e); } } else { - engine.eval_bytecode(&buffer).unwrap(); + match engine.eval_bytecode(&buffer) { + Ok(v) => println!("{}", v.display()), + Err(v) => eprintln!("Uncaught {}", v.display()), + } } }