From 32358b2dd69e61ba17e32656fa1b16d7904df45a Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Thu, 2 Nov 2023 11:36:25 +1100 Subject: [PATCH] Simplify vm.run --- valuescript_compiler/src/asm.rs | 19 +++++- valuescript_compiler/src/compile.rs | 18 ++++++ valuescript_compiler/src/lib.rs | 2 +- valuescript_program_embed/src/main.rs | 91 ++++++++++++++------------- valuescript_vm/src/lib.rs | 2 +- valuescript_vm/src/virtual_machine.rs | 40 +++++++----- valuescript_wasm/src/lib.rs | 9 ++- vstc/src/run_command.rs | 9 ++- vstc/src/test_inputs.rs | 10 ++- 9 files changed, 132 insertions(+), 68 deletions(-) diff --git a/valuescript_compiler/src/asm.rs b/valuescript_compiler/src/asm.rs index ec4cb94..befa8ae 100644 --- a/valuescript_compiler/src/asm.rs +++ b/valuescript_compiler/src/asm.rs @@ -2,12 +2,15 @@ use std::{ collections::HashMap, fmt::Write, hash::{Hash as HashTrait, Hasher}, + rc::Rc, }; use num_bigint::BigInt; +use valuescript_vm::{vs_value::Val, Bytecode, DecoderMaker}; use crate::{ - assembler::ValueType, expression_compiler::CompiledExpression, instruction::RegisterVisitMut, + assemble, assembler::ValueType, expression_compiler::CompiledExpression, + instruction::RegisterVisitMut, parse_module, }; pub use crate::instruction::{Instruction, InstructionFieldMut}; @@ -329,6 +332,14 @@ pub struct Pointer { pub name: String, } +impl From<&str> for Pointer { + fn from(name: &str) -> Self { + Pointer { + name: name.to_string(), + } + } +} + impl StructuredFormattable for Pointer { fn structured_fmt(&self, sf: &mut StructuredFormatter<'_, '_>) -> std::fmt::Result { sf.write("@")?; @@ -854,3 +865,9 @@ impl Object { result } } + +pub fn inline(source: &str) -> Val { + let bytecode = Rc::new(Bytecode::new(assemble(&parse_module(source)))); + + bytecode.decoder(0).decode_val(&mut vec![]) +} diff --git a/valuescript_compiler/src/compile.rs b/valuescript_compiler/src/compile.rs index 543f100..88685b0 100644 --- a/valuescript_compiler/src/compile.rs +++ b/valuescript_compiler/src/compile.rs @@ -27,3 +27,21 @@ where result } + +pub fn compile_str(source: &str) -> CompileResult { + compile( + ResolvedPath { + path: "(str)".into(), + }, + |path| { + if path == "(str)" { + Ok(source.into()) + } else { + Err(format!( + "Unknown path {} (no filesystem access for compile_str)", + path + )) + } + }, + ) +} diff --git a/valuescript_compiler/src/lib.rs b/valuescript_compiler/src/lib.rs index 990ab52..69d9f30 100644 --- a/valuescript_compiler/src/lib.rs +++ b/valuescript_compiler/src/lib.rs @@ -24,8 +24,8 @@ mod visit_pointers; pub use assembler::assemble; pub use assembly_parser::parse_module; -pub use compile::compile; pub use compile::CompileResult; +pub use compile::{compile, compile_str}; pub use diagnostic::Diagnostic; pub use diagnostic::DiagnosticLevel; pub use gather_modules::gather_modules; diff --git a/valuescript_program_embed/src/main.rs b/valuescript_program_embed/src/main.rs index 27f59ca..8f1a04f 100644 --- a/valuescript_program_embed/src/main.rs +++ b/valuescript_program_embed/src/main.rs @@ -1,54 +1,57 @@ use std::{process::exit, rc::Rc}; -use valuescript_vm::{Bytecode, VirtualMachine}; +use valuescript_vm::{vs_value::Val, Bytecode, DecoderMaker, VirtualMachine}; pub fn main() { + let bytecode = Rc::new(Bytecode::new(vec![ + // + // This is the compiled bytecode for inputs/passing/projEuler/p28.ts. + // + // Using `RUSTFLAGS="-C opt-level=s" cargo build --release` it currently compiles to 534KiB. + // A program with just println!("Test") is 315KiB, so we might be able to get down to around + // 219KiB by simplifying the way we print the result. + // + // Since we're still in early development, the bytecode is subject to change, which means this + // bytecode might break. + // + // If you need to fix it, or use a different program, use vstc: + // vstc compile program.ts + // vstc assemble out.vsm + // # Output is in out.vsb. Use the xxd program (or otherwise) to see the bytes. + // + // Another option is to checkout the commit from when this was originally written: + // git checkout 4e77747ae67e0ef27f9841111058599c8e916a2f + // cargo build + // ./target/debug/valuescript_program_embed + // + 0x0d, 0x05, 0x00, 0x0a, 0x00, 0x0b, 0x08, 0x00, 0x21, 0x0d, 0x9c, 0x00, 0x09, 0x09, 0x06, 0x01, + 0x06, 0x09, 0x06, 0x19, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x7f, 0x40, 0x00, 0x02, + 0x05, 0x0e, 0x02, 0x06, 0x01, 0x03, 0x21, 0x0d, 0x9c, 0x00, 0x09, 0x09, 0x06, 0x01, 0x06, 0x03, + 0x06, 0x0d, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x7f, 0x40, 0x00, 0x02, 0x05, 0x0e, + 0x02, 0x06, 0x01, 0x04, 0x21, 0x0d, 0x9c, 0x00, 0x09, 0x09, 0x06, 0x01, 0x06, 0x05, 0x06, 0x11, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x7f, 0x40, 0x00, 0x02, 0x05, 0x0e, 0x02, 0x06, + 0x01, 0x05, 0x21, 0x0d, 0x9c, 0x00, 0x09, 0x09, 0x06, 0x01, 0x06, 0x07, 0x06, 0x15, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x7f, 0x40, 0x00, 0x02, 0x05, 0x0e, 0x02, 0x06, 0x01, 0x06, + 0x26, 0x09, 0x06, 0x01, 0x0e, 0x03, 0x0e, 0x04, 0x0e, 0x05, 0x0e, 0x06, 0x00, 0x08, 0x06, 0x72, + 0x65, 0x64, 0x75, 0x63, 0x65, 0x09, 0x0d, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x02, 0x26, + 0x0e, 0x02, 0x08, 0x06, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x09, 0x0d, 0x1e, 0x01, 0x00, 0x04, + 0x01, 0x06, 0x03, 0x05, 0x11, 0x0e, 0x05, 0x0e, 0x03, 0x06, 0x10, 0x0e, 0x06, 0x06, 0x28, 0x0e, + 0x06, 0xe1, 0x00, 0x21, 0x0d, 0xe6, 0x00, 0x09, 0x0e, 0x02, 0x00, 0x02, 0x24, 0x0e, 0x02, 0x06, + 0x02, 0x06, 0x04, 0x0e, 0x04, 0x0e, 0x06, 0x04, 0x01, 0x0e, 0x05, 0x06, 0x02, 0x05, 0x27, 0xb4, + 0x00, 0x01, 0x0e, 0x04, 0x00, 0x00, 0x0b, 0x09, 0x01, 0x24, 0x0e, 0x02, 0x06, 0x00, 0x03, 0x24, + 0x0e, 0x02, 0x06, 0x01, 0x04, 0x24, 0x0e, 0x02, 0x06, 0x02, 0x05, 0x06, 0x06, 0x03, 0x0e, 0x05, + 0x02, 0x06, 0x06, 0x03, 0x0e, 0x04, 0x06, 0x05, 0x0e, 0x02, 0x0e, 0x06, 0x07, 0x04, 0x0e, 0x07, + 0x0e, 0x03, 0x06, 0x01, 0x09, 0x0e, 0x04, 0x0e, 0x05, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x0b, 0x05, + 0x02, 0x04, 0x0e, 0x02, 0x0e, 0x03, 0x00, 0x00, + ])); + let mut vm = VirtualMachine::default(); + let result = vm.run( - Rc::new(Bytecode::new(vec![ - // - // This is the compiled bytecode for inputs/passing/projEuler/p28.ts. - // - // Using `RUSTFLAGS="-C opt-level=s" cargo build --release` it currently compiles to 534KiB. - // A program with just println!("Test") is 315KiB, so we might be able to get down to around - // 219KiB by simplifying the way we print the result. - // - // Since we're still in early development, the bytecode is subject to change, which means this - // bytecode might break. - // - // If you need to fix it, or use a different program, use vstc: - // vstc compile program.ts - // vstc assemble out.vsm - // # Output is in out.vsb. Use the xxd program (or otherwise) to see the bytes. - // - // Another option is to checkout the commit from when this was originally written: - // git checkout 4e77747ae67e0ef27f9841111058599c8e916a2f - // cargo build - // ./target/debug/valuescript_program_embed - // - 0x0d, 0x05, 0x00, 0x0a, 0x00, 0x0b, 0x08, 0x00, 0x21, 0x0d, 0x9c, 0x00, 0x09, 0x09, 0x06, - 0x01, 0x06, 0x09, 0x06, 0x19, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x7f, 0x40, - 0x00, 0x02, 0x05, 0x0e, 0x02, 0x06, 0x01, 0x03, 0x21, 0x0d, 0x9c, 0x00, 0x09, 0x09, 0x06, - 0x01, 0x06, 0x03, 0x06, 0x0d, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x7f, 0x40, - 0x00, 0x02, 0x05, 0x0e, 0x02, 0x06, 0x01, 0x04, 0x21, 0x0d, 0x9c, 0x00, 0x09, 0x09, 0x06, - 0x01, 0x06, 0x05, 0x06, 0x11, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x7f, 0x40, - 0x00, 0x02, 0x05, 0x0e, 0x02, 0x06, 0x01, 0x05, 0x21, 0x0d, 0x9c, 0x00, 0x09, 0x09, 0x06, - 0x01, 0x06, 0x07, 0x06, 0x15, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x7f, 0x40, - 0x00, 0x02, 0x05, 0x0e, 0x02, 0x06, 0x01, 0x06, 0x26, 0x09, 0x06, 0x01, 0x0e, 0x03, 0x0e, - 0x04, 0x0e, 0x05, 0x0e, 0x06, 0x00, 0x08, 0x06, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x09, - 0x0d, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x02, 0x26, 0x0e, 0x02, 0x08, 0x06, 0x72, - 0x65, 0x64, 0x75, 0x63, 0x65, 0x09, 0x0d, 0x1e, 0x01, 0x00, 0x04, 0x01, 0x06, 0x03, 0x05, - 0x11, 0x0e, 0x05, 0x0e, 0x03, 0x06, 0x10, 0x0e, 0x06, 0x06, 0x28, 0x0e, 0x06, 0xe1, 0x00, - 0x21, 0x0d, 0xe6, 0x00, 0x09, 0x0e, 0x02, 0x00, 0x02, 0x24, 0x0e, 0x02, 0x06, 0x02, 0x06, - 0x04, 0x0e, 0x04, 0x0e, 0x06, 0x04, 0x01, 0x0e, 0x05, 0x06, 0x02, 0x05, 0x27, 0xb4, 0x00, - 0x01, 0x0e, 0x04, 0x00, 0x00, 0x0b, 0x09, 0x01, 0x24, 0x0e, 0x02, 0x06, 0x00, 0x03, 0x24, - 0x0e, 0x02, 0x06, 0x01, 0x04, 0x24, 0x0e, 0x02, 0x06, 0x02, 0x05, 0x06, 0x06, 0x03, 0x0e, - 0x05, 0x02, 0x06, 0x06, 0x03, 0x0e, 0x04, 0x06, 0x05, 0x0e, 0x02, 0x0e, 0x06, 0x07, 0x04, - 0x0e, 0x07, 0x0e, 0x03, 0x06, 0x01, 0x09, 0x0e, 0x04, 0x0e, 0x05, 0x0e, 0x06, 0x00, 0x00, - 0x00, 0x0b, 0x05, 0x02, 0x04, 0x0e, 0x02, 0x0e, 0x03, 0x00, 0x00, - ])), None, - &[], + &mut Val::Undefined, + bytecode.decoder(0).decode_val(&mut vec![]), + vec![], ); match result { diff --git a/valuescript_vm/src/lib.rs b/valuescript_vm/src/lib.rs index 4b12174..7b95534 100644 --- a/valuescript_vm/src/lib.rs +++ b/valuescript_vm/src/lib.rs @@ -29,7 +29,7 @@ mod vs_storage_ptr; mod vs_symbol; pub mod vs_value; -pub use bytecode::Bytecode; +pub use bytecode::{Bytecode, DecoderMaker}; pub use string_methods::unicode_at; pub use virtual_machine::VirtualMachine; pub use vs_symbol::VsSymbol; diff --git a/valuescript_vm/src/virtual_machine.rs b/valuescript_vm/src/virtual_machine.rs index dd3306b..a49b363 100644 --- a/valuescript_vm/src/virtual_machine.rs +++ b/valuescript_vm/src/virtual_machine.rs @@ -1,9 +1,11 @@ +use std::mem::take; use std::rc::Rc; use crate::builtins::internal_error_builtin::ToInternalError; use crate::bytecode::Bytecode; use crate::bytecode::DecoderMaker; use crate::first_stack_frame::FirstStackFrame; +use crate::stack_frame::CallResult; use crate::stack_frame::FrameStepOk; use crate::stack_frame::StackFrame; use crate::vs_value::{LoadFunctionResult, Val, ValTrait}; @@ -25,27 +27,26 @@ impl Default for VirtualMachine { impl VirtualMachine { pub fn run( &mut self, - bytecode: Rc, step_limit: Option, - params: &[Val], + this: &mut Val, + fn_: Val, + args: Vec, ) -> Result { - let mut bd = bytecode.decoder(0); - - let main_fn = bd.decode_val(&mut Vec::new()); - - let mut frame = match main_fn.load_function() { + let mut frame = match fn_.load_function() { LoadFunctionResult::StackFrame(f) => f, _ => return Err("bytecode does start with function".to_internal_error()), }; - for p in params { - frame.write_param(p.clone()); + frame.write_param(take(this)); + + for a in args { + frame.write_param(a); } self.push(frame); - match step_limit { - Some(step_limit) => { + let res = match step_limit { + Some(step_limit) => 'b: { let mut step_count = 0; while step_count < step_limit { @@ -53,20 +54,29 @@ impl VirtualMachine { step_count += 1; if self.stack.is_empty() { - return Ok(self.frame.get_call_result().return_); + break 'b self.frame.get_call_result(); } } - Err("step limit reached".to_internal_error()) + return Err("step limit reached".to_internal_error()); } None => { while !self.stack.is_empty() { self.step()?; } - Ok(self.frame.get_call_result().return_) + self.frame.get_call_result() } - } + }; + + let CallResult { + return_, + this: updated_this, + } = res; + + *this = updated_this; + + Ok(return_) } pub fn step(&mut self) -> Result<(), Val> { diff --git a/valuescript_wasm/src/lib.rs b/valuescript_wasm/src/lib.rs index 0786b94..8cc3fac 100644 --- a/valuescript_wasm/src/lib.rs +++ b/valuescript_wasm/src/lib.rs @@ -8,7 +8,7 @@ use valuescript_compiler::{ }; use valuescript_vm::{ vs_value::{ToVal, Val}, - Bytecode, LoadFunctionResult, ValTrait, VirtualMachine, + Bytecode, DecoderMaker, LoadFunctionResult, ValTrait, VirtualMachine, }; // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global @@ -130,7 +130,12 @@ fn run_to_result(entry_point: &str, read_file: &js_sys::Function, args: &str) -> } }; - let vm_result = vm.run(bytecode, None, &val_args); + let vm_result = vm.run( + None, + &mut Val::Undefined, + bytecode.decoder(0).decode_val(&mut vec![]), + val_args, + ); RunResult { diagnostics: HashMap::default(), diff --git a/vstc/src/run_command.rs b/vstc/src/run_command.rs index 7393ccc..644ffec 100644 --- a/vstc/src/run_command.rs +++ b/vstc/src/run_command.rs @@ -1,8 +1,8 @@ use std::process::exit; use std::rc::Rc; -use valuescript_vm::vs_value::Val; use valuescript_vm::VirtualMachine; +use valuescript_vm::{vs_value::Val, DecoderMaker}; use crate::to_bytecode::{format_from_path, to_bytecode, RunFormat}; @@ -41,7 +41,12 @@ pub fn run_command(args: &Vec) { .map(|a| Val::String(Rc::from(a.clone()))) .collect(); - match vm.run(bytecode, None, &val_args) { + match vm.run( + None, + &mut Val::Undefined, + bytecode.decoder(0).decode_val(&mut vec![]), + val_args, + ) { Ok(Val::Undefined) => {} Ok(result) => { println!("{}", result.pretty()); diff --git a/vstc/src/test_inputs.rs b/vstc/src/test_inputs.rs index 30b2cf8..1cce556 100644 --- a/vstc/src/test_inputs.rs +++ b/vstc/src/test_inputs.rs @@ -9,8 +9,9 @@ mod tests { use valuescript_compiler::asm::Structured; use valuescript_compiler::compile; use valuescript_compiler::{assemble, parse_module}; - use valuescript_vm::VirtualMachine; + use valuescript_vm::vs_value::Val; use valuescript_vm::{Bytecode, ValTrait}; + use valuescript_vm::{DecoderMaker, VirtualMachine}; use crate::handle_diagnostics_cli::handle_diagnostics_cli; use crate::resolve_entry_path::resolve_entry_path; @@ -111,7 +112,12 @@ mod tests { let mut vm = VirtualMachine::default(); - let result = vm.run(bytecode, Some(2_000_000), &[]); + let result = vm.run( + Some(2_000_000), + &mut Val::Undefined, + bytecode.decoder(0).decode_val(&mut vec![]), + vec![], + ); let result_string = match result { Ok(val) => val.codify(),