From 81a45ef870efa1a3b5a8e0169b75f6396e08a5f2 Mon Sep 17 00:00:00 2001 From: Sokhibjon Orzikulov Date: Sat, 3 Aug 2024 18:33:54 +0500 Subject: [PATCH] porting from gitlab --- .github/workflows/test.yml | 22 ++ .gitignore | 12 + .rustfmt.toml | 1 + Cargo.toml | 23 ++ LICENSE | 21 ++ bytecode/Cargo.toml | 11 + bytecode/src/assembler.rs | 48 +++ bytecode/src/lib.rs | 26 ++ bytecode/src/main.rs | 21 ++ bytecode/src/opcode.rs | 36 ++ bytecode/src/parser.rs | 127 +++++++ readme.md | 3 + src/error.rs | 46 +++ src/frame.rs | 127 +++++++ src/function.rs | 135 ++++++++ src/index.rs | 1 + src/jit/cpu/mod.rs | 53 +++ src/jit/cpu/universal/mod.rs | 2 + src/jit/cpu/universal/param.rs | 5 + src/jit/cpu/universal/reg.rs | 90 +++++ src/jit/mod.rs | 1 + src/lib.rs | 23 ++ src/machine.rs | 599 +++++++++++++++++++++++++++++++++ src/main.rs | 42 +++ src/object.rs | 84 +++++ src/object_info.rs | 123 +++++++ src/object_pool.rs | 123 +++++++ src/opcodes.rs | 255 ++++++++++++++ src/static_root.rs | 34 ++ src/string.rs | 39 +++ src/value.rs | 183 ++++++++++ 31 files changed, 2316 insertions(+) create mode 100755 .github/workflows/test.yml create mode 100755 .gitignore create mode 100755 .rustfmt.toml create mode 100755 Cargo.toml create mode 100755 LICENSE create mode 100755 bytecode/Cargo.toml create mode 100755 bytecode/src/assembler.rs create mode 100755 bytecode/src/lib.rs create mode 100755 bytecode/src/main.rs create mode 100755 bytecode/src/opcode.rs create mode 100755 bytecode/src/parser.rs create mode 100755 readme.md create mode 100755 src/error.rs create mode 100755 src/frame.rs create mode 100755 src/function.rs create mode 100755 src/index.rs create mode 100755 src/jit/cpu/mod.rs create mode 100755 src/jit/cpu/universal/mod.rs create mode 100755 src/jit/cpu/universal/param.rs create mode 100755 src/jit/cpu/universal/reg.rs create mode 100755 src/jit/mod.rs create mode 100755 src/lib.rs create mode 100755 src/machine.rs create mode 100755 src/main.rs create mode 100755 src/object.rs create mode 100755 src/object_info.rs create mode 100755 src/object_pool.rs create mode 100755 src/opcodes.rs create mode 100755 src/static_root.rs create mode 100755 src/string.rs create mode 100755 src/value.rs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100755 index 0000000..f89a23b --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,22 @@ +name: Test [Bulut] + +on: [push, pull_request] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Build + run: cargo build --release --verbose + + - name: Run lint + run: cargo clippy --verbose + + - name: Run tests + run: cargo test --verbose diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..b1b6b5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Generated by Cargo +# will have compiled files and executables +target + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +.idea \ No newline at end of file diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100755 index 0000000..7f81904 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +use_field_init_shorthand = true \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100755 index 0000000..a5fe879 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "bulut" +version = "0.3.0" +edition = "2021" +homepage = "https://osmon.dev" +documentation = "https://wiki.osmon.dev" +repository = "https://github.com/osmon-lang/bulut" +description = "Lightweight and fast Virtual Machine built for Osmon Programming Language" +authors = ["Yuri Katsuki "] +readme = "readme.md" +keywords = ["vm","register","register-based", "uzbek"] +license = "Apache-2.0" +exclude = ["target"] + +[profile.dev] + +[profile.release] +lto = true + +[dependencies] +time = "0.1.40" +libc = "0.2.43" +colored = "1.6.1" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..c5a6711 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Osmon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/bytecode/Cargo.toml b/bytecode/Cargo.toml new file mode 100755 index 0000000..a6249bd --- /dev/null +++ b/bytecode/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "osmon_bytecode" +version = "0.1.0" +authors = ["UwUssimo Robinson "] +edition = "2018" +description = "Library used for encoding/decoding osmon instructions" +license = "MIT" +keywords = ["codegen","vm","encoding","decoding"] + +[dependencies] +bulut = { path = ".." } diff --git a/bytecode/src/assembler.rs b/bytecode/src/assembler.rs new file mode 100755 index 0000000..e8f8eb3 --- /dev/null +++ b/bytecode/src/assembler.rs @@ -0,0 +1,48 @@ +use bulut::opcodes::Instruction; +use crate::opcode::{Opcode,Size}; +use crate::encode; + +#[derive(Clone,Debug)] +pub struct Assembler { + pub instructions: Vec, + pub code: Vec, +} + +impl Assembler { + pub fn new(code: Vec) -> Assembler { + Assembler { + instructions: code, + code: vec![] + } + } + + pub fn translate(&mut self) { + let mut ip = 0; + while ip < self.instructions.len() { + let instruction = self.instructions[ip].clone(); + + match instruction { + Instruction::LoadInt(reg,val) => { + self.code.push(Opcode::LoadI); + self.code.push(reg as u8); + self.code.extend_from_slice(&encode!(val;i32)); + } + Instruction::Move(reg,reg2) => { + self.code.push(Opcode::Move); + self.code.push(reg as u8); + self.code.push(reg2 as u8); + } + Instruction::LoadLong(reg,val) => { + self.code.push(Opcode::LoadL); + self.code.push(reg as u8); + self.code.extend_from_slice(&encode!(val;i64)); + } + _ => unimplemented!(), + } + + ip += 1; + } + self.code.push(self.instructions.len() as u8); + } +} + diff --git a/bytecode/src/lib.rs b/bytecode/src/lib.rs new file mode 100755 index 0000000..dfd6e37 --- /dev/null +++ b/bytecode/src/lib.rs @@ -0,0 +1,26 @@ +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +extern crate bulut; + + +pub mod opcode; +pub mod parser; +pub mod assembler; + +#[macro_export] +macro_rules! encode { + ($v:expr; $t: ty) => { + unsafe { + ::std::mem::transmute::<$t,[u8;::std::mem::size_of::<$t>()]>($v) + } + }; +} + +#[macro_export] +macro_rules! decode { + ($arr: expr; $t: ty) => { + unsafe { + ::std::mem::transmute::<[u8;::std::mem::size_of::<$t>()],$t>($arr) + } + }; +} diff --git a/bytecode/src/main.rs b/bytecode/src/main.rs new file mode 100755 index 0000000..237dfc7 --- /dev/null +++ b/bytecode/src/main.rs @@ -0,0 +1,21 @@ +extern crate osmon_bytecode; +extern crate bulut; +use osmon_bytecode::parser::Parser; +use osmon_bytecode::assembler::Assembler; +use bulut::opcodes::Instruction; + +fn main() { + let mut assembler = Assembler::new(vec![ + Instruction::LoadInt(1,12), + Instruction::Move(1,2), + ]); + + assembler.translate(); + + println!("{:?}",assembler.code); + + let mut parser = Parser::new(&assembler.code); + let code = parser.parse(); + println!("{:?}",code); + +} diff --git a/bytecode/src/opcode.rs b/bytecode/src/opcode.rs new file mode 100755 index 0000000..f77ad19 --- /dev/null +++ b/bytecode/src/opcode.rs @@ -0,0 +1,36 @@ +pub mod Opcode { + pub const LoadI: u8 = 0x1; + pub const LoadF: u8 = 0x2; + pub const LoadL: u8 = 0x3; + pub const LoadD: u8 = 0x4; + + pub const LoadG: u8 = 0xa1; + pub const LoadAt: u8 = 0xa2; + pub const StoreAt: u8 = 0xa3; + pub const Ret: u8 = 0xa4; + pub const Ret0: u8 = 0xa5; + pub const Call: u8 = 0xa6; + pub const StoreG: u8 = 0xa7; + pub const Move: u8 = 0xa8; + + pub const Label: u8 = 0xa9; + pub const Goto: u8 = 0xe1; + pub const GotoT: u8 = 0xe2; + pub const GotoF: u8 = 0xe3; + + pub fn to_string<'a>(op: u8) -> &'a str { + match op { + LoadI => "LoadI", + Move => "Move", + _ => "", + } + } +} + +pub mod Size { + pub const Float: u32 = ::std::mem::size_of::() as u32; + pub const Double: u32 = ::std::mem::size_of::() as u32; + pub const Int: u32 = ::std::mem::size_of::() as u32; + pub const Long: u32 = ::std::mem::size_of::() as u32; + pub const Bool: u32 = ::std::mem::size_of::() as u32; +} diff --git a/bytecode/src/parser.rs b/bytecode/src/parser.rs new file mode 100755 index 0000000..e6097f0 --- /dev/null +++ b/bytecode/src/parser.rs @@ -0,0 +1,127 @@ +use bulut::opcodes::Instruction; +use super::opcode::{Opcode,Size}; +use super::decode; + +#[derive(Clone,Debug)] +pub struct Parser<'a> { + pub code: &'a [u8], + pub parsed_code: Vec, + pub ip: usize, +} + + +impl<'a> Parser<'a> { + pub fn new(code: &'a [u8]) -> Parser<'a> { + Parser { + code, + parsed_code: vec![], + ip: 0, + } + } + + pub fn read_next(&mut self) -> u8 { + if self.ip < self.code.len() { + let op = self.code[self.ip]; + + self.ip += 1; + op + } else { + + 0x0 + } + } + pub fn parse(&mut self) -> Vec { + let size = *self.code.last().unwrap() as usize; + let mut ip = 0; + while ip < size { + if self.ip >= self.code.len() { + break; + } + self.parse_opcode(); + ip += 1; + + } + + self.parsed_code.clone() + } + + pub fn parse_opcode(&mut self) { + let op = &self.read_next(); + println!("{:?}",Opcode::to_string(op.clone())); + match op { + &Opcode::Move => { + let r1 = self.read_next(); + let r2 = self.read_next(); + self.parsed_code.push(Instruction::Move(r1 as usize,r2 as usize)); + } + + &Opcode::LoadI => { + + let register = self.read_next() as usize; + + let array = { + let mut array = [0u8;Size::Int as usize]; + let mut i = 0; + while i < Size::Int { + let idx = self.read_next(); + array[i as usize] = idx; + i += 1; + } + array + }; + + let int = decode!(array;i32); + self.parsed_code.push(Instruction::LoadInt(register,int)); + }, + + &Opcode::LoadL => { + let register = self.read_next() as usize; + + let array = { + let mut array = [0u8;Size::Long as usize]; + for i in 0..Size::Long as usize { + array[i] = self.read_next(); + } + array + }; + + let long = decode!(array;i64); + self.parsed_code.push(Instruction::LoadLong(register,long)); + } + &Opcode::LoadF => { + let register = self.read_next() as usize; + + let array = { + let mut array = [0u8;Size::Float as usize]; + for i in 0..Size::Float as usize { + array[i] = self.read_next(); + } + array + }; + + let float = decode!(array;f32); + self.parsed_code.push(Instruction::LoadFloat(register,float)); + } + &Opcode::Label => { + let label_id = self.read_next() as usize; + + self.parsed_code.push(Instruction::Label(label_id)); + } + + &Opcode::GotoF => { + let reg = self.read_next(); + let lbl_id = self.read_next(); + + self.parsed_code.push(Instruction::GotoF(reg as usize,lbl_id as usize)); + } + + &Opcode::Goto => { + let lbl_id = self.read_next(); + + self.parsed_code.push(Instruction::Goto(lbl_id as usize)); + } + + _ => {} + } + } +} diff --git a/readme.md b/readme.md new file mode 100755 index 0000000..1a1f370 --- /dev/null +++ b/readme.md @@ -0,0 +1,3 @@ +# Bulut VM + +Osmon Dasturlash Tilining virtual mashinasi. Osmondan keltirilgan buyruq registrlar yordamida dasturni ishga tushurish. diff --git a/src/error.rs b/src/error.rs new file mode 100755 index 0000000..f9f47ea --- /dev/null +++ b/src/error.rs @@ -0,0 +1,46 @@ +use std::error::Error; + +#[derive(Debug)] +pub enum VmError { + RuntimeError(String), + LabelNotFound(usize), + GlobalNotFound(usize), + Expected(String, String), +} + +impl VmError { + fn as_str(&self) -> String { + match self.deref() { + VmError::RuntimeError(cause) => format!("Runtime Error: `{}`", cause), + VmError::LabelNotFound(id) => format!("Label `{}` not found", id), + VmError::GlobalNotFound(id) => format!("Global `{}` not found", id), + VmError::Expected(expected, found) => { + format!("Expected `{}` found `{}`", expected, found) + } + } + } +} + +impl Error for VmError { + fn description(&self) -> &str { + match self { + VmError::Expected(_, _) => "Expected: ", + VmError::GlobalNotFound(_) => "GlobalNotFound:", + VmError::LabelNotFound(_) => "LabelNotFound:", + VmError::RuntimeError(_) => "RuntimeError:", + } + } + + fn cause(&self) -> Option<&dyn Error> { + None + } +} + +use std::fmt; +use std::ops::Deref; + +impl fmt::Display for VmError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} diff --git a/src/frame.rs b/src/frame.rs new file mode 100755 index 0000000..dd5d2bb --- /dev/null +++ b/src/frame.rs @@ -0,0 +1,127 @@ +use crate::{opcodes::Instruction, value::Value}; + +///CallFrame +/// Stores register values, instructions, registers and arguments stack +#[derive(Clone, Debug, Default)] +pub struct CallFrame { + /// pointer to current block + pub ip: usize, + /// Instructions + pub code: Vec, + /// registers stored in stack, default size of `stack` is 256 + pub stack: Vec, + /// `arguments stack`: used by Call instruction + pub arg_stack: Vec, +} + +/// CallStack +/// Stores frames +#[derive(Clone, Debug)] +pub struct CallStack { + pub frames: Vec, + pub n_frames: usize, + pub limit: Option, +} + +impl CallStack { + pub fn new(len: usize) -> CallStack { + let mut frames = Vec::with_capacity(len); + for _ in 0..len { + frames.push(CallFrame::new()); + } + + CallStack { + frames, + n_frames: 1, + limit: None, + } + } + + pub fn push(&mut self) { + if self.n_frames >= self.frames.len() { + panic!("Virtual stack overflow"); + } + if let Some(limit) = self.limit { + if self.n_frames >= limit { + panic!("Maximum stack depth exceeded"); + } + } + + self.n_frames += 1; + } + + /// Reset last frame + pub fn pop(&mut self) { + if self.n_frames == 0 { + panic!("Virtual stack underflow"); + } + self.frames[self.n_frames - 1].reset(); + self.n_frames -= 1; + } + /// Get top frame + pub fn top(&self) -> &CallFrame { + if self.n_frames == 0 { + panic!("Virtual stack underflow"); + } + &self.frames[self.n_frames - 1] + } + /// Get &mut CallFrame + pub fn top_mut(&mut self) -> &mut CallFrame { + if self.n_frames == 0 { + panic!("Virtual stack underflow"); + } + &mut self.frames[self.n_frames - 1] + } +} + +///Fiber +/// Should be used in future +/// +/// Fiber must need to store upvalues and have a object pool +#[derive(Clone, Debug)] +pub struct Fiber { + pub frames: Vec, +} + +impl CallFrame { + pub fn new() -> CallFrame { + let mut vec = Vec::with_capacity(256); + for _ in 0..256 { + vec.push(Value::Null); + } + + CallFrame { + ip: 0, + + code: vec![], + stack: vec, + arg_stack: vec![], + } + } + + pub fn get(&self, r: usize) -> Value { + self.stack[r] + } + + pub fn set(&mut self, r: usize, v: Value) { + self.stack[r] = v; + } + + pub fn init_with_args(&mut self, args: &[Value]) { + for arg in args { + self.arg_stack.push(*arg); + } + } + + pub fn reset(&mut self) { + for i in 0..self.stack.len() { + self.stack[i] = Value::Null; + } + self.arg_stack.clear(); + self.code.clear(); + } + + pub fn jit_run(&mut self) -> Value { + Value::Null + } +} diff --git a/src/function.rs b/src/function.rs new file mode 100755 index 0000000..e20df01 --- /dev/null +++ b/src/function.rs @@ -0,0 +1,135 @@ +use crate::{machine::Machine, object::Object, opcodes::*, value::Value}; +use std::any::Any; + +#[derive(Debug)] +pub enum Function { + Virtual(VirtualFunction), + Native(NativeFunction), +} + +impl Clone for Function { + fn clone(&self) -> Function { + match self { + Function::Virtual(vf) => Function::Virtual(vf.clone()), + Function::Native(_) => panic!("Cannot clone native func"), + } + } +} + +impl crate::object::ObjectAddon for Function { + fn typename(&self, _: &mut Machine) -> String { + "Func".into() + } + + fn to_String(&self, _m: &mut Machine) -> String { + String::from("function") + } + + fn as_function(&self) -> &Function { + self + } +} + +impl Object for Function { + /// Call object + fn call(&self, m: &mut Machine, args: Vec) -> Value { + match self { + Function::Virtual(ref vf) => { + //println!("{:?}",args); + let func = vf.clone(); + // println!("{:?}",args[0].to_String(m)); + m.last_frame_mut().stack[0] = args[0]; + m.last_frame_mut().stack[..args.len()].copy_from_slice(&args[..]); + let code = func.code; + let v = m.run_code(code); + match v { + Ok(v) => v, + Err(e) => { + eprintln!("{}", e); + panic!(""); + } + } + } + + Function::Native(nv) => nv.0(m, args), + } + } + + fn load_at(&self, m: &mut Machine, _args: Vec, dest: usize) { + let _this = _args[0]; + let val = if let Value::Object(id) = &_args[1] { + m.pool.get(*id) + } else { + panic!("Exptected object") + }; + + let fname: &str = &val.to_String(m); + + match fname { + "disassemble" => { + let code = if let Function::Virtual(vf) = self { + vf.code.toString() + } else { + "".to_string() + }; + let obj = m.pool.allocate(Box::new(code)); + let code = vec![Instruction::LoadConst(1, obj), Instruction::Ret(1)]; + let func = Function::from(code); + let obj = m.pool.allocate(Box::new(func)); + m.set(dest, Value::Object(obj)); + } + f => panic!("Unknown field `{}`", f), + } + } + + fn as_any(&self) -> &dyn Any { + self as &dyn Any + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self as &mut dyn Any + } + + /// Get Object Id's(Used for GC) W.I.P + fn get_children(&self) -> Vec { + vec![] + } +} + +#[derive(Clone, Debug)] +pub struct VirtualFunction { + pub code: Vec, + pub argc: usize, +} + +impl Function { + pub fn from_instructions(code: Vec, args: usize) -> Function { + Function::Virtual(VirtualFunction { code, argc: args }) + } + + pub fn from_native(f: Box) -> Value + Send>) -> Function { + Function::Native(NativeFunction(f)) + } +} + +impl From> for Function { + fn from(f: Vec) -> Function { + Function::Virtual(VirtualFunction { code: f, argc: 0 }) + } +} + +pub struct NativeFunction(pub Box) -> Value + Send>); + +impl NativeFunction { + pub fn invoke(&self, m: &mut Machine, args: Vec) -> Value { + self.0(m, args) + } +} + +use std::fmt; + +impl fmt::Debug for NativeFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "") + } +} diff --git a/src/index.rs b/src/index.rs new file mode 100755 index 0000000..1791f2f --- /dev/null +++ b/src/index.rs @@ -0,0 +1 @@ +pub const CALL: u8 = 0; diff --git a/src/jit/cpu/mod.rs b/src/jit/cpu/mod.rs new file mode 100755 index 0000000..26c8de3 --- /dev/null +++ b/src/jit/cpu/mod.rs @@ -0,0 +1,53 @@ +pub mod universal; + +pub const REG_COUNT: usize = 16; + +pub struct State { + pub pc: usize, + pub sp: usize, + pub ra: usize, + + pub regs: [usize; REG_COUNT], +} + +use std::fmt; + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + println!("State:"); + println!("\t pc = {:?}", self.pc as *const u8); + println!("\t sp = {:?}", self.sp as *const u8); + println!("\t ra = {:?}", self.ra as *const u8); + for (ind, &val) in self.regs.iter().enumerate() { + println!("R[{:2}] = {:-20?} {:-20}", ind, val as *const u8, val) + } + write!(f, "") + } +} + +/// Register +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Reg(pub u8); + +impl From for u32 { + fn from(reg: Reg) -> u32 { + reg.0 as u32 + } +} + +/// Float register +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct FReg(pub u8); + +impl From for u32 { + fn from(reg: FReg) -> u32 { + reg.0 as u32 + } +} + +pub enum Memory { + Local(i32), + Base(Reg, i32), + Index(Reg, Reg, i32, i32), + Offset(Reg, i32, i32), +} diff --git a/src/jit/cpu/universal/mod.rs b/src/jit/cpu/universal/mod.rs new file mode 100755 index 0000000..2049d7d --- /dev/null +++ b/src/jit/cpu/universal/mod.rs @@ -0,0 +1,2 @@ +pub mod param; +pub mod reg; diff --git a/src/jit/cpu/universal/param.rs b/src/jit/cpu/universal/param.rs new file mode 100755 index 0000000..f4db09f --- /dev/null +++ b/src/jit/cpu/universal/param.rs @@ -0,0 +1,5 @@ +pub static OFFSTET: isize = 16; + +pub fn next_param_offset(param_offset: isize) -> isize { + param_offset + 8 +} diff --git a/src/jit/cpu/universal/reg.rs b/src/jit/cpu/universal/reg.rs new file mode 100755 index 0000000..8596470 --- /dev/null +++ b/src/jit/cpu/universal/reg.rs @@ -0,0 +1,90 @@ +use crate::jit::cpu::{FReg, Reg}; + +pub const REG_COUNT: usize = 16; +pub static REG_PARAMS: [Reg; 6] = [RDI, RSI, RDX, RCX, R8, R9]; +pub static SCRATCH: [Reg; 3] = [R9, R8, RDI]; + +pub const REG_RESULT: Reg = RAX; +pub const REG_TMP1: Reg = R10; +pub const REG_TMP2: Reg = R11; +pub const REG_SP: Reg = RSP; +pub const REG_FP: Reg = RBP; +pub const REG_THREAD: Reg = R15; + +pub const RAX: Reg = Reg(0); +pub const RCX: Reg = Reg(1); +pub const RDX: Reg = Reg(2); +pub const RBX: Reg = Reg(3); +pub const RSP: Reg = Reg(4); +pub const RBP: Reg = Reg(5); +pub const RSI: Reg = Reg(6); +pub const RDI: Reg = Reg(7); + +pub const R8: Reg = Reg(8); +pub const R9: Reg = Reg(9); +pub const R10: Reg = Reg(10); +pub const R11: Reg = Reg(11); +pub const R12: Reg = Reg(12); +pub const R13: Reg = Reg(13); +pub const R14: Reg = Reg(14); +pub const R15: Reg = Reg(15); + +pub const RIP: Reg = Reg(16); + +pub const FREG_RESULT: FReg = XMM0; +pub const FREG_TMP1: FReg = XMM1; + +pub static FREG_PARAMS: [FReg; 8] = [XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7]; + +pub const XMM0: FReg = FReg(0); +pub const XMM1: FReg = FReg(1); +pub const XMM2: FReg = FReg(2); +pub const XMM3: FReg = FReg(3); +pub const XMM4: FReg = FReg(4); +pub const XMM5: FReg = FReg(5); +pub const XMM6: FReg = FReg(6); +pub const XMM7: FReg = FReg(7); +pub const XMM8: FReg = FReg(8); +pub const XMM9: FReg = FReg(9); +pub const XMM10: FReg = FReg(10); +pub const XMM11: FReg = FReg(11); +pub const XMM12: FReg = FReg(12); +pub const XMM13: FReg = FReg(13); +pub const XMM14: FReg = FReg(14); +pub const XMM15: FReg = FReg(15); + +impl Reg { + // these four register need sometimes special treatment: e.g. because of bl vs bh + // for byte operations + pub fn is_basic_reg(self) -> bool { + self == RAX || self == RBX || self == RCX || self == RDX + } + + pub fn int(self) -> u8 { + assert_ne!(self, RIP); + + self.0 + } + + pub fn msb(self) -> u8 { + assert_ne!(self, RIP); + + (self.int() >> 3) & 0x01 + } + + pub fn and7(self) -> u8 { + assert_ne!(self, RIP); + + self.int() & 0x07 + } +} + +impl FReg { + pub fn msb(self) -> u8 { + (self.0 >> 3) & 0x01 + } + + pub fn and7(self) -> u8 { + self.0 & 0x07 + } +} diff --git a/src/jit/mod.rs b/src/jit/mod.rs new file mode 100755 index 0000000..3bfb62f --- /dev/null +++ b/src/jit/mod.rs @@ -0,0 +1 @@ +pub mod cpu; diff --git a/src/lib.rs b/src/lib.rs new file mode 100755 index 0000000..a3fec9a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,23 @@ +#![warn(rust_2018_idioms)] +#![allow(non_snake_case)] + +pub mod error; +pub mod frame; +pub mod function; +pub mod index; +pub mod jit; +pub mod machine; +pub mod object; +pub mod object_info; +pub mod object_pool; +pub mod opcodes; +pub mod static_root; +pub mod string; +pub mod value; + +use time; + +pub mod prelude { + #[allow(unused_imports)] + use super::*; +} diff --git a/src/machine.rs b/src/machine.rs new file mode 100755 index 0000000..21bef1b --- /dev/null +++ b/src/machine.rs @@ -0,0 +1,599 @@ +use crate::error::VmError; +use crate::{frame::*, object::ObjectAddon, object_pool::ObjectPool, opcodes::*, value::Value}; +use std::collections::HashMap; + +macro_rules! for_c { + ($v:ident = $v1:expr; $e:expr;$ex:expr, $b: block) => { + let mut $v = $v1; + while $e { + $b + $ex + } + }; +} + +///Machine that executes code +#[derive(Default)] +pub struct Machine { + pub stack: Vec, + pub pool: ObjectPool, + pub globals: HashMap, + pub labels: HashMap, +} + +impl Machine { + pub fn new() -> Machine { + Machine { + stack: Vec::with_capacity(4096), + pool: ObjectPool::new(), + globals: HashMap::new(), + labels: HashMap::new(), + } + } + /// Get last frame in CallStack + pub fn last_frame(&self) -> &CallFrame { + self.stack.last().unwrap() + } + + /// Get mutable reference to last frame in CallStack + pub fn last_frame_mut(&mut self) -> &mut CallFrame { + self.stack.last_mut().unwrap() + } + /// Get value for register + pub fn get(&mut self, rnum: usize) -> Value { + self.last_frame().get(rnum) + } + + /// Set `this` value + pub fn set_this(&mut self, v: Value) { + self.last_frame_mut().stack[0] = v; + } + /// Set R(r) = v + pub fn set(&mut self, r: usize, v: Value) { + self.last_frame_mut().set(r, v); + } + /// Update instruction pointer + pub fn dispatch(&mut self) { + self.last_frame_mut().ip += 1; + } + /// Invoke callable object + pub fn invoke(&mut self, callable: Value, args: Vec) -> Value { + let id = match callable { + Value::Object(id) => id, + v => { + panic!("Not callable {:?}", v); + } + }; + + let obj = self.pool.get(id); + self.stack.push(CallFrame::new()); + + self.last_frame_mut().init_with_args(&args.as_slice()); + obj.call(self, args) + } + /// Goto + pub fn branch(&mut self, idx: usize) { + self.last_frame_mut().ip = idx; + } + /// Run instructions + pub fn run_code(&mut self, code: Vec) -> Result { + for_c!(i = 0;i < code.len();i += 1, { + if let Instruction::Label(lbl_id) = code[i] { + + self.labels.insert(lbl_id, i); + + }; + }); + + self.last_frame_mut().code = code; + self.last_frame_mut().ip = 0; + + self.execute_op() + } + /// Execute all opcodes in current frame + pub fn execute_op(&mut self) -> Result { + let mut returns = false; + let mut ret = Value::Null; + let start = super::time::PreciseTime::now(); + + while self.last_frame().ip < self.last_frame().code.len() { + if returns { + break; + } + + let opcode = self.last_frame().code[self.last_frame().ip].clone(); + self.last_frame_mut().ip += 1; + //println!("{:?}",self.last_frame().code[self.last_frame().ip]); + match &opcode { + Instruction::Label(_label_id) => {} + + Instruction::LoadArg(r1) => { + let value = self.get(*r1); + self.last_frame_mut().arg_stack.push(value); + } + + Instruction::LoadBool(dest, boolean) => { + self.set(*dest, Value::Bool(*boolean)); + } + + Instruction::LoadInt(dest, int) => { + self.set(*dest, Value::Int(*int)); + } + + Instruction::LoadString(r1, ref string) => { + let string = string.to_string(); + let object_id = self.pool.allocate(Box::new(string)); + self.set(*r1, Value::Object(object_id)); + } + + Instruction::LoadDouble(dest, double) => { + self.set(*dest, Value::Double(*double)); + } + + Instruction::LoadLong(dest, long) => { + self.set(*dest, Value::Long(*long)); + } + + Instruction::LoadFloat(dest, float) => { + self.set(*dest, Value::Float(*float)); + } + + Instruction::Isa(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + let n = v2.typename(self); + println!("{:?}", v2.typename(self)); + let result = v1.isa(n, self); + self.set(*dest, Value::Bool(result)); + } + + Instruction::Add(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Int(i + i2), + (Value::Float(f), Value::Float(f2)) => Value::Float(f + f2), + (Value::Long(i), Value::Long(i2)) => Value::Long(i + i2), + (Value::Double(f), Value::Double(f2)) => Value::Double(f + f2), + (Value::Int(i), Value::Long(i2)) => Value::Long((i as i64) + i2), + (Value::Long(i), Value::Int(i2)) => Value::Long(i + (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Double((f as f64) + f2), + (Value::Double(f), Value::Float(f2)) => Value::Double(f + (f2 as f64)), + (Value::Long(l), v) => Value::Long(l + v.to_long(self)), + (Value::Int(i), v) => Value::Int(i + v.to_int(self)), + (Value::Double(d), v) => Value::Double(d + v.to_double(self)), + (Value::Float(f), v) => Value::Float(f + v.to_float(self)), + (v, Value::Null) => v, + (Value::Null, v) => v, + v => panic!("{:?}", v), + }; + + self.set(*dest, result); + } + + Instruction::Call(dest, r2, argc) => { + let args = { + let mut temp: Vec = vec![]; + let this = self + .last_frame_mut() + .arg_stack + .pop() + .expect("Expected this value"); + + temp.push(this); + + for _ in 0..*argc { + let v = self.last_frame_mut().arg_stack.pop(); + + match v { + None => temp.push(Value::Null), // if less arguments are passed then fill the holes with Null values + Some(v) => temp.push(v), + }; + } + + temp + }; + + let value = self.get(*r2); + let v = self.invoke(value, args); + self.stack.pop(); + self.set(*dest, v); + } + Instruction::Sub(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Int(i - i2), + (Value::Float(f), Value::Float(f2)) => Value::Float(f - f2), + (Value::Long(i), Value::Long(i2)) => Value::Long(i - i2), + (Value::Double(f), Value::Double(f2)) => Value::Double(f - f2), + (Value::Int(i), Value::Long(i2)) => Value::Long((i as i64) - i2), + (Value::Long(i), Value::Int(i2)) => Value::Long(i - (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Double((f as f64) - f2), + (Value::Double(f), Value::Float(f2)) => Value::Double(f - (f2 as f64)), + (Value::Long(l), v) => Value::Long(l - v.to_long(self)), + (Value::Int(i), v) => Value::Int(i - v.to_int(self)), + (Value::Double(d), v) => Value::Double(d - v.to_double(self)), + (Value::Float(f), v) => Value::Float(f - v.to_float(self)), + (v, Value::Null) => v, + (Value::Null, v) => v, + _ => unimplemented!(), + }; + + self.set(*dest, result); + } + + Instruction::Div(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Int(i / i2), + (Value::Float(f), Value::Float(f2)) => Value::Float(f / f2), + (Value::Long(i), Value::Long(i2)) => Value::Long(i / i2), + (Value::Double(f), Value::Double(f2)) => Value::Double(f / f2), + (Value::Int(i), Value::Long(i2)) => Value::Long((i as i64) / i2), + (Value::Long(i), Value::Int(i2)) => Value::Long(i / (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Double((f as f64) / f2), + (Value::Double(f), Value::Float(f2)) => Value::Double(f / (f2 as f64)), + (Value::Long(l), v) => Value::Long(l / v.to_long(self)), + (Value::Int(i), v) => Value::Int(i / v.to_int(self)), + (Value::Double(d), v) => Value::Double(d / v.to_double(self)), + (Value::Float(f), v) => Value::Float(f / v.to_float(self)), + (v, Value::Null) => v, + (Value::Null, v) => v, + _ => unimplemented!(), + }; + + self.set(*dest, result); + } + + Instruction::Mul(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Int(i * i2), + (Value::Float(f), Value::Float(f2)) => Value::Float(f * f2), + (Value::Long(i), Value::Long(i2)) => Value::Long(i * i2), + (Value::Double(f), Value::Double(f2)) => Value::Double(f * f2), + (Value::Int(i), Value::Long(i2)) => Value::Long((i as i64) * i2), + (Value::Long(i), Value::Int(i2)) => Value::Long(i * (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Double((f as f64) * f2), + (Value::Double(f), Value::Float(f2)) => Value::Double(f * (f2 as f64)), + (Value::Long(l), v) => Value::Long(l * v.to_long(self)), + (Value::Int(i), v) => Value::Int(i * v.to_int(self)), + (Value::Double(d), v) => Value::Double(d * v.to_double(self)), + (Value::Float(f), v) => Value::Float(f * v.to_float(self)), + (v, Value::Null) => v, + (Value::Null, v) => v, + v => panic!("Cannot mul {:?}", v), + }; + + self.set(*dest, result); + } + + Instruction::LoadConst(r1, idx) => { + self.set(*r1, Value::Object(*idx)); + } + + Instruction::Not(r1, r2) => { + let v = self.get(*r2); + let result = Value::Bool(v.not(self)); + self.set(*r1, result); + } + + Instruction::Gt(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Bool(i > i2), + (Value::Long(i), Value::Long(i2)) => Value::Bool(i > i2), + (Value::Float(f), Value::Float(f2)) => Value::Bool(f > f2), + (Value::Double(f), Value::Double(f2)) => Value::Bool(f > f2), + (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) > i2), + (Value::Long(i), Value::Int(i2)) => Value::Bool(i > (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) > f2), + (Value::Double(f), Value::Float(f2)) => Value::Bool(f > (f2 as f64)), + (Value::Long(l), v) => Value::Bool(l > v.to_long(self)), + (Value::Int(i), v) => Value::Bool(i > v.to_int(self)), + (Value::Double(d), v) => Value::Bool(d > v.to_double(self)), + (Value::Float(f), v) => Value::Bool(f > v.to_float(self)), + (v, Value::Null) => v, + (Value::Null, v) => v, + v => panic!("{:?}", v), + }; + + self.set(*dest, result); + } + Instruction::Ge(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Bool(i >= i2), + (Value::Long(i), Value::Long(i2)) => Value::Bool(i >= i2), + (Value::Float(f), Value::Float(f2)) => Value::Bool(f >= f2), + (Value::Double(f), Value::Double(f2)) => Value::Bool(f >= f2), + (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) >= i2), + (Value::Long(i), Value::Int(i2)) => Value::Bool(i >= (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) >= f2), + (Value::Double(f), Value::Float(f2)) => Value::Bool(f >= (f2 as f64)), + (Value::Long(l), v) => Value::Bool(l >= v.to_long(self)), + (Value::Int(i), v) => Value::Bool(i >= v.to_int(self)), + (Value::Double(d), v) => Value::Bool(d >= v.to_double(self)), + (Value::Float(f), v) => Value::Bool(f >= v.to_float(self)), + (v, Value::Null) => v, + (Value::Null, v) => v, + _ => unimplemented!(), + }; + + self.set(*dest, result); + } + + Instruction::Le(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Bool(i <= i2), + (Value::Long(i), Value::Long(i2)) => Value::Bool(i <= i2), + (Value::Float(f), Value::Float(f2)) => Value::Bool(f <= f2), + (Value::Double(f), Value::Double(f2)) => Value::Bool(f <= f2), + (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) <= i2), + (Value::Long(i), Value::Int(i2)) => Value::Bool(i <= (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) <= f2), + (Value::Double(f), Value::Float(f2)) => Value::Bool(f <= (f2 as f64)), + (Value::Long(l), v) => Value::Bool(l <= v.to_long(self)), + (Value::Int(i), v) => Value::Bool(i <= v.to_int(self)), + (Value::Double(d), v) => Value::Bool(d <= v.to_double(self)), + (Value::Float(f), v) => Value::Bool(f <= v.to_float(self)), + (v, Value::Null) => v, + (Value::Null, v) => v, + v => panic!("Unimplemented {:?}", v), + }; + + self.set(*dest, result); + } + + Instruction::Lt(dest, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Bool(i < i2), + (Value::Long(i), Value::Long(i2)) => Value::Bool(i < i2), + (Value::Float(f), Value::Float(f2)) => Value::Bool(f < f2), + (Value::Double(f), Value::Double(f2)) => Value::Bool(f < f2), + (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) < i2), + (Value::Long(i), Value::Int(i2)) => Value::Bool(i < (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) < f2), + (Value::Double(f), Value::Float(f2)) => Value::Bool(f < (f2 as f64)), + (Value::Long(l), v) => Value::Bool(l < v.to_long(self)), + (Value::Int(i), v) => Value::Bool(i < v.to_int(self)), + (Value::Double(d), v) => Value::Bool(d < v.to_double(self)), + (Value::Float(f), v) => Value::Bool(f < v.to_float(self)), + (v, Value::Null) => v, + (Value::Null, v) => v, + (v, v1) => panic!("{:?} < {:?}", v.to_String(self), v1.to_String(self)), + }; + + self.set(*dest, result); + } + Instruction::BitAnd(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Long(l), Value::Long(l1)) => Value::Long(l & l1), + (Value::Int(i), Value::Int(i2)) => Value::Int(i & i2), + v => panic!("BitAnd cannot be aplied to {:?}", v), + }; + self.set(*r3, result); + } + Instruction::BitOr(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Long(l), Value::Long(l1)) => Value::Long(l | l1), + (Value::Int(i), Value::Int(i2)) => Value::Int(i | i2), + v => panic!("BitOr cannot be aplied to {:?}", v), + }; + self.set(*r3, result); + } + Instruction::BitXor(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Long(l), Value::Long(l1)) => Value::Long(l ^ l1), + (Value::Int(i), Value::Int(i2)) => Value::Int(i ^ i2), + v => panic!("BitOr cannot be aplied to {:?}", v), + }; + self.set(*r3, result); + } + Instruction::Shl(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Long(l), Value::Long(l1)) => Value::Long(l << l1), + (Value::Int(i), Value::Int(i2)) => Value::Int(i << i2), + v => panic!("BitOr cannot be aplied to {:?}", v), + }; + self.set(*r3, result); + } + Instruction::Shr(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Long(l), Value::Long(l1)) => Value::Long(l >> l1), + (Value::Int(i), Value::Int(i2)) => Value::Int(i >> i2), + v => panic!("BitOr cannot be aplied to {:?}", v), + }; + self.set(*r3, result); + } + Instruction::And(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Bool(b), Value::Bool(b2)) => Value::Bool(b && b2), + v => panic!("And cannot be aplied to {:?}", v), + }; + + self.set(*r3, result); + } + Instruction::Or(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + + let result = match (v1, v2) { + (Value::Bool(b), Value::Bool(b2)) => Value::Bool(b || b2), + v => panic!("Or cannot be aplied to {:?}", v), + }; + + self.set(*r3, result); + } + Instruction::Eq(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Bool(i == i2), + (Value::Long(i), Value::Long(i2)) => Value::Bool(i == i2), + (Value::Float(f), Value::Float(f2)) => Value::Bool(f == f2), + (Value::Double(f), Value::Double(f2)) => Value::Bool(f == f2), + (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) == i2), + (Value::Long(i), Value::Int(i2)) => Value::Bool(i == (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) == f2), + (Value::Double(f), Value::Float(f2)) => Value::Bool(f == (f2 as f64)), + (Value::Long(l), v) => Value::Bool(l == v.to_long(self)), + (Value::Int(i), v) => Value::Bool(i == v.to_int(self)), + (Value::Double(d), v) => Value::Bool(d == v.to_double(self)), + (Value::Float(f), v) => Value::Bool(f == v.to_float(self)), + (_v, Value::Null) => Value::Bool(false), + (Value::Null, _v) => Value::Bool(false), + _ => unimplemented!(), + }; + + self.set(*r3, result); + } + + Instruction::Neq(r3, r1, r2) => { + let (v1, v2) = (self.get(*r1), self.get(*r2)); + let result = match (v1, v2) { + (Value::Int(i), Value::Int(i2)) => Value::Bool(i != i2), + (Value::Long(i), Value::Long(i2)) => Value::Bool(i != i2), + (Value::Float(f), Value::Float(f2)) => Value::Bool(f != f2), + (Value::Double(f), Value::Double(f2)) => Value::Bool(f != f2), + (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) != i2), + (Value::Long(i), Value::Int(i2)) => Value::Bool(i == (i2 as i64)), + (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) != f2), + (Value::Double(f), Value::Float(f2)) => Value::Bool(f != (f2 as f64)), + (Value::Long(l), v) => Value::Bool(l != v.to_long(self)), + (Value::Int(i), v) => Value::Bool(i != v.to_int(self)), + (Value::Double(d), v) => Value::Bool(d != v.to_double(self)), + (Value::Float(f), v) => Value::Bool(f != v.to_float(self)), + (_v, Value::Null) => Value::Bool(false), + (Value::Null, _v) => Value::Bool(false), + _ => unimplemented!(), + }; + + self.set(*r3, result); + } + + Instruction::Goto(lbl_id) => { + if self.labels.contains_key(lbl_id) { + let idx = &self.labels[lbl_id]; + self.branch(*idx + 1); + } else { + return Err(VmError::LabelNotFound(*lbl_id)); + } + } + + Instruction::GotoF(r1, lbl_id) => match self.get(*r1) { + Value::Bool(b) => { + if !b { + if self.labels.contains_key(lbl_id) { + let idx = &self.labels[lbl_id]; + self.branch(*idx + 1); + } else { + return Err(VmError::LabelNotFound(*lbl_id)); + } + } + } + + _v => return Err(VmError::RuntimeError("GotoF exptected Bool value".into())), + }, + + Instruction::Jump(idx) => { + self.branch(*idx); + } + + Instruction::LoadGlobal(r1, index) => { + if self.globals.contains_key(index) { + let value = &self.globals[index]; + self.set(*r1, *value); + } else { + return Err(VmError::GlobalNotFound(*index)); + } + } + + Instruction::StoreGlobal(r1, index) => { + let value = self.get(*r1); + self.globals.insert(*index, value); + } + + Instruction::JumpF(r1, idx) => { + let v = self.get(*r1); + if let Value::Bool(b) = v { + if !b { + self.branch(*idx); + } + } else { + return Err(VmError::RuntimeError( + "Expected Bool value; Op JumpF".into(), + )); + } + } + + Instruction::Move(r1, r2) => { + let v = self.get(*r2); + + self.last_frame_mut().stack[*r1] = v; + } + + Instruction::Ret(idx) => { + ret = self.get(*idx); + returns = true; + } + + Instruction::Ret0 => { + returns = true; + } + + Instruction::LoadAt(r1, r2, r3) => { + let v2 = self.get(*r2); + let v3 = self.get(*r3); + + if let Value::Object(obj_id) = v2 { + let obj = self.pool.get(obj_id); + let this = self.get(*r2); + obj.load_at(self, vec![this, v3], *r1); + } else { + return Err(VmError::Expected( + "Value::Object".into(), + format!("{:?}", v2), + )); + } + } + + Instruction::StoreAt(r1, r2, r3) => { + let value = self.get(*r1); + let target = self.get(*r2); + let key = self.get(*r3); + if let Value::Object(obj_id) = &target { + let obj = self.pool.get(*obj_id); + obj.store_at(self, vec![target, key, value], 0); + } else { + return Err(VmError::Expected( + "Value::Object".into(), + format!("{:?}", &target), + )); + } + } + + v => panic!("{:?}", v), + } + } + let end = super::time::PreciseTime::now(); + + let _result = start.to(end).num_milliseconds(); + + Ok(ret) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100755 index 0000000..ec5b749 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,42 @@ +extern crate bulut; + +use bulut::{function::Function, machine::Machine, opcodes::Instruction, value::Value}; + +fn main() { + let mut machine = Machine::new(); + let string = machine.pool.allocate(Box::new(String::from("disassemble"))); + + let code = vec![ + Instruction::LoadInt(2, 2), + Instruction::Add(2, 1, 2), + Instruction::Ret(2), + ]; + + let func = Function::from_instructions(code, 1); + + let func = machine.pool.allocate(Box::new(func)); + + let code = vec![ + Instruction::LoadConst(2, func), + Instruction::LoadConst(1, string), + Instruction::LoadArg(2), + Instruction::LoadAt(2, 2, 1), + Instruction::LoadArg(2), + Instruction::Call(2, 2, 0), + Instruction::Ret(2), + ]; + + let func = Value::Object( + machine + .pool + .allocate(Box::new(Function::from_instructions(code, 0))), + ); + let v = machine.invoke(func, vec![]); + let obj = if let Value::Object(id) = v { + machine.pool.get(id) + } else { + panic!(""); + }; + + println!("{}", obj.to_String(&mut machine)); +} diff --git a/src/object.rs b/src/object.rs new file mode 100755 index 0000000..6788b32 --- /dev/null +++ b/src/object.rs @@ -0,0 +1,84 @@ +use crate::{machine::Machine, object_pool::ObjectPool, value::Value}; +use std::any::Any; +pub trait Object: Send + ObjectAddon { + /// Initialized + fn initialize(&mut self, _: &mut ObjectPool) {} + fn call(&self, _m: &mut Machine, _args: Vec) -> Value { + Value::Null + } + + fn store_at(&self, _m: &mut Machine, _args: Vec, _rindex: usize) { + println!("{:?}", _args); + panic!("Cannot store_at, {}", self.to_String(_m)); + } + + fn load_at(&self, _m: &mut Machine, _args: Vec, _rindex: usize) { + panic!("Cannot load_at. {:?}", self.to_String(_m)); + } + + fn as_any(&self) -> &dyn Any; + + fn as_any_mut(&mut self) -> &mut dyn Any; + + fn get_children(&self) -> Vec; +} + +pub trait ObjectAddon { + fn typename(&self, _m: &mut Machine) -> String { + String::from("Object") + } + + fn o_clone(&self, _m: &mut Machine) -> Value { + panic!("Cannot clone!"); + } + fn to_String(&self, _: &mut Machine) -> String { + String::new() + } + + fn as_bytes(&self, _: &mut Machine) -> Vec { + Vec::new() + } + + fn to_int(&self, _: &mut Machine) -> i32 { + 0 + } + + fn to_long(&self, _: &mut Machine) -> i64 { + 0 + } + + fn to_float(&self, _: &mut Machine) -> f32 { + 0.0 + } + fn to_double(&self, _: &mut Machine) -> f64 { + 0.0 + } + + fn as_function(&self) -> &crate::function::Function { + panic!() + } + + fn eq(&self, _m: &mut Machine) -> bool { + false + } + + fn add(&self, _rhs: Value, _m: &mut Machine) -> Value { + Value::Null + } + + fn sub(&self, _rhs: Value, _m: &mut Machine) -> Value { + Value::Null + } + + fn div(&self, _rhs: Value, _m: &mut Machine) -> Value { + Value::Null + } + + fn not(&self, _m: &mut Machine) -> bool { + false + } + + fn isa(&self, s: String, m: &mut Machine) -> bool { + self.typename(m) == s + } +} diff --git a/src/object_info.rs b/src/object_info.rs new file mode 100755 index 0000000..8b76011 --- /dev/null +++ b/src/object_info.rs @@ -0,0 +1,123 @@ +use crate::object::Object; +use std::{cell::Cell, ops::Deref, rc::Rc}; + +pub struct ObjectInfo { + object: Box, + native_ref_info: ObjectNativeRefInfo, +} + +pub struct ObjectHandle<'a> { + object: &'a dyn Object, + _native_ref_info: ObjectNativeRefInfo, +} + +impl<'a> Deref for ObjectHandle<'a> { + type Target = &'a dyn Object; + fn deref(&self) -> &&'a dyn Object { + &self.object + } +} + +pub struct ObjectNativeRefInfo { + // TODO: Remove Rc + n_refs: Rc>, + + // in case n_refs becomes zero + gc_notified: bool, +} + +impl ObjectInfo { + pub fn new(obj: Box) -> ObjectInfo { + ObjectInfo { + object: obj, + native_ref_info: ObjectNativeRefInfo { + n_refs: Rc::new(Cell::new(0)), + gc_notified: false, + }, + } + } + + pub fn gc_notify(&mut self) { + self.native_ref_info.gc_notified = true; + } + + pub fn as_object(&self) -> &dyn Object { + &*self.object + } + + pub fn has_native_refs(&self) -> bool { + self.native_ref_info.n_refs.get() != 0 + } + + pub fn handle<'a>(&self) -> ObjectHandle<'a> { + ObjectHandle { + object: unsafe { + ::std::mem::transmute::<&dyn Object, &'static dyn Object>(&*self.object) + }, + _native_ref_info: self.native_ref_info.clone(), + } + } +} + +impl Drop for ObjectInfo { + fn drop(&mut self) { + if self.native_ref_info.n_refs.get() != 0 { + eprintln!("Attempting to drop object with alive references"); + ::std::process::abort(); + } + } +} + +impl Clone for ObjectNativeRefInfo { + fn clone(&self) -> Self { + self.n_refs.replace(self.n_refs.get() + 1); + ObjectNativeRefInfo { + n_refs: self.n_refs.clone(), + gc_notified: false, + } + } +} + +impl Drop for ObjectNativeRefInfo { + fn drop(&mut self) { + let n_refs = self.n_refs.get(); + + if self.gc_notified { + assert_eq!(n_refs, 0); + } else { + assert!(n_refs > 0); + self.n_refs.replace(n_refs - 1); + } + } +} + +pub struct TypedObjectHandle<'a, T> { + _handle: ObjectHandle<'a>, + value: &'a T, +} + +impl<'a, T> Deref for TypedObjectHandle<'a, T> +where + T: 'a, +{ + type Target = &'a T; + fn deref(&self) -> &&'a T { + &self.value + } +} + +impl<'a, T> TypedObjectHandle<'a, T> +where + T: 'static, +{ + pub fn downcast_from(other: ObjectHandle<'a>) -> Option> { + let value = match other.object.as_any().downcast_ref::() { + Some(v) => v, + None => return None, + }; + Some(TypedObjectHandle { + _handle: other, + value, + }) + } +} diff --git a/src/object_pool.rs b/src/object_pool.rs new file mode 100755 index 0000000..29252f3 --- /dev/null +++ b/src/object_pool.rs @@ -0,0 +1,123 @@ +use crate::{ + object::Object, + object_info::{ObjectHandle, ObjectInfo, TypedObjectHandle}, + static_root::StaticRoot, +}; + +#[derive(Default)] +/// An object pool that provides the backing object storage for executors. +pub struct ObjectPool { + objects: Vec>, + object_idx_pool: Vec, + alloc_count: usize, +} + +impl ObjectPool { + pub fn new() -> ObjectPool { + ObjectPool { + objects: vec![Some(ObjectInfo::new(Box::new(StaticRoot::new())))], + object_idx_pool: vec![], + alloc_count: 0, + } + } + + /// Pins an object to the pool. + pub fn allocate(&mut self, mut inner: Box) -> usize { + inner.initialize(self); + + let id = if let Some(id) = self.object_idx_pool.pop() { + id + } else { + let objects = &mut self.objects; + objects.push(None); + objects.len() - 1 + }; + self.objects[id] = Some(ObjectInfo::new(inner)); + + self.alloc_count += 1; + + id + } + + #[allow(dead_code)] + pub fn deallocate(&mut self, id: usize) { + let objects = &mut self.objects; + let pool = &mut self.object_idx_pool; + + assert!(objects[id].is_some()); + + objects[id] = None; + pool.push(id); + } + + /// Gets a handle to the object at `id`. + /// + /// The handle can be passed around safely and + /// the underlying object will not be garbage + /// collected until all handles to it are released. + /// + /// If the object pool gets destroyed before + /// all handles are dropped, the process will be + /// aborted because of memory unsafety introduced + /// by reference invalidation. + pub fn get<'a>(&self, id: usize) -> ObjectHandle<'a> { + self.objects[id].as_ref().unwrap().handle() + } + + /// Gets a direct reference to the object at `id`. + pub fn get_direct(&self, id: usize) -> &dyn Object { + self.objects[id].as_ref().unwrap().as_object() + } + + /// Gets a direct typed reference to the object at `id`. + /// If downcast fails, `None` is returned. + pub fn get_direct_typed(&self, id: usize) -> Option<&T> { + self.get_direct(id).as_any().downcast_ref::() + } + + /// Gets a direct reference to the object at `id`. + /// If downcast fails, this raises a `RuntimeError`. + pub fn must_get_direct_typed(&self, id: usize) -> &T { + self.get_direct_typed(id) + .unwrap_or_else(|| panic!("Type mismatch")) + } + + /// Gets a typed object handle to the object at `id`. + /// If downcast fails, `None` is returned. + pub fn get_typed<'a, T: 'static>(&self, id: usize) -> Option> { + TypedObjectHandle::downcast_from(self.get(id)) + } + + /// Gets a typed object handle to the object at `id`. + /// If downcast fails, this raises a `RuntimeError`. + pub fn must_get_typed<'a, T: 'static>(&self, id: usize) -> TypedObjectHandle<'a, T> { + self.get_typed(id) + .unwrap_or_else(|| panic!("Type mismatch")) + } + + pub fn get_static_root<'a>(&self) -> TypedObjectHandle<'a, StaticRoot> { + self.get_typed(0).unwrap() + } + + pub fn get_direct_static_root(&self) -> &StaticRoot { + self.get_direct_typed(0).unwrap() + } + + pub fn get_alloc_count(&self) -> usize { + self.alloc_count + } + + pub fn reset_alloc_count(&mut self) { + self.alloc_count = 0; + } +} + +impl Drop for ObjectPool { + fn drop(&mut self) { + for obj in &mut self.objects { + if let Some(ref mut obj) = *obj { + obj.gc_notify(); + } + } + } +} diff --git a/src/opcodes.rs b/src/opcodes.rs new file mode 100755 index 0000000..647931f --- /dev/null +++ b/src/opcodes.rs @@ -0,0 +1,255 @@ +use colored; + +use self::colored::Colorize; + +#[derive(Clone)] +pub enum Instruction { + LoadString(usize, String), + + /// LoadBool R(A) = B + /// + /// Loading bool value B to register A + LoadBool(usize, bool), + + ///LoadInt R(A) = B + /// + /// Loading integer value B to register A + LoadInt(usize, i32), + ///LoadLong R(A) = B + /// + /// Loading long value B to register A + LoadLong(usize, i64), + ///LoadFloat R(A) = B + /// + /// Loading float value B to register A + LoadFloat(usize, f32), + /// LoadDouble R(A) = B + /// + /// Loading double value B to register A + LoadDouble(usize, f64), + + /// LoadConst R(A) = C(B) + /// + /// Load constant from object pool to register A + LoadConst(usize, usize), + /// LoadGlobal R(A) = G(B) + /// + /// Load global value B into register A + LoadGlobal(usize, usize), + /// LoadAt R(A) = R(B)\[C\] + /// + /// Load C from B and store in A + LoadAt(usize, usize, usize), + /// LoadSuper R(A) = R(B)\[C\] + /// + /// Load C from B and store in A + LoadSuper(usize, usize, usize), + /// Move R(A) = R(B) + /// + /// Move register + Move(usize, usize), + /// Store R(B)\[C\] = A + /// + /// Store A into R(B)\[C\] + Store(usize, usize, usize), + StoreAt(usize, usize, usize), + /// StoreGlobal G(A) = R(B) + /// + /// Store global + StoreGlobal(usize, usize), + /// Jump IP + Jump(usize), + /// Jump (R(A) == false ? ip = B : continue) + JumpF(usize, usize), + + /// Goto + /// + /// Same as Jump instructions, but uses labels + Goto(usize), + GotoF(usize, usize), + + /// Push value from R(A) to arguments stack + LoadArg(usize), + /// R(A) = B(Args), C - Arg count, args poped from arg stack + Call(usize, usize, usize), + + Isa(usize, usize, usize), + + Not(usize, usize), + ///Add R(A) = R(B) + R(C) + Add(usize, usize, usize), + ///Sub R(A) = R(B) - R(C) + Sub(usize, usize, usize), + ///Mul R(A) = R(B) * R(C) + Mul(usize, usize, usize), + ///Div R(A) = R(B) / R(C) + Div(usize, usize, usize), + Rem(usize, usize, usize), + ///Gt R(A) = R(B) > R(C) + Gt(usize, usize, usize), + ///Lt R(A) = R(B) < R(C) + Lt(usize, usize, usize), + /// Ge R(A) = R(B) >= R(C) + Ge(usize, usize, usize), + /// Le R(A) = R(B) <= R(C) + Le(usize, usize, usize), + + /// Eq R(A) = R(B) == R(C) + Eq(usize, usize, usize), + Neq(usize, usize, usize), + /// Ret0 + /// + /// return null value + Ret0, + /// Ret R(A) + /// + /// return value from R(A) + Ret(usize), + + /// Create label with id A + Label(usize), + + Shr(usize, usize, usize), + Shl(usize, usize, usize), + BitOr(usize, usize, usize), + BitXor(usize, usize, usize), + BitAnd(usize, usize, usize), + And(usize, usize, usize), + Or(usize, usize, usize), +} + +use std::fmt; +impl fmt::Display for Instruction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::Instruction::*; + + match self { + Neq(dest, r1, r2) => write!(f, "Neq {} {} {}", dest, r1, r2), + Isa(dest, r1, r2) => write!(f, "Isa {} {} {}", dest, r1, r2), + Not(r1, r2) => write!(f, "Not {} {}", r1, r2), + Add(r3, r1, r2) => write!(f, "Add {} {} {}", r3, r1, r2), + Sub(r3, r1, r2) => write!(f, "Sub {} {} {}", r3, r1, r2), + Div(r3, r1, r2) => write!(f, "Div {} {} {}", r3, r1, r2), + Mul(r3, r1, r2) => write!(f, "Mul {} {} {}", r3, r1, r2), + Rem(r3, r1, r2) => write!(f, "Rem {} {} {}", r3, r1, r2), + Gt(r3, r1, r2) => write!(f, "Gt {} {} {} ", r3, r1, r2), + Lt(r3, r1, r2) => write!(f, "Lt {} {} {}", r3, r1, r2), + Le(r3, r1, r2) => write!(f, "Le {} {} {}", r3, r1, r2), + Ge(r3, r1, r2) => write!(f, "Ge {} {} {}", r3, r1, r2), + Eq(r3, r1, r2) => write!(f, "Eq {} {} {}", r3, r1, r2), + Ret0 => write!(f, "Ret0"), + Ret(r1) => write!(f, "Ret {}", r1), + Goto(label_id) => write!(f, "Goto {}", label_id), + GotoF(r1, label_id) => write!(f, "GotoF {} {}", r1, label_id), + Jump(ip) => write!(f, "Jump {}", ip), + JumpF(r1, ip) => write!(f, "JumpF {} {}", r1, ip), + LoadConst(r1, object_id) => write!(f, "LoadConst {} {}", r1, object_id), + LoadGlobal(r1, global) => write!(f, "LoadGlobal {} {}", r1, global), + LoadInt(r1, int) => write!(f, "LoadInt {} {}", r1, int), + LoadLong(r1, long) => write!(f, "LoadLong {} {}", r1, long), + LoadFloat(r1, float) => write!(f, "LoadFloat {} {}", r1, float), + LoadDouble(r1, double) => write!(f, "LoadDouble {} {}", r1, double), + LoadBool(r1, bool) => write!(f, "LoadBool {} {}", r1, bool), + LoadString(r1, str) => write!(f, "LoadString {} \"{}\"", r1, str), + StoreGlobal(r1, global) => write!(f, "StoreGlobal {} {}", r1, global), + StoreAt(r1, r2, r3) => write!(f, "StoreAt {} {} {}", r1, r2, r3), + Store(r1, r2, r3) => write!(f, "Store {} {} {}", r1, r2, r3), + LoadAt(r1, r2, r3) => write!(f, "LoadAt {} {} {}", r1, r2, r3), + BitAnd(r3, r1, r2) => write!(f, "BitAnd {} {} {}", r3, r1, r2), + BitOr(r3, r1, r2) => write!(f, "BitOr {} {} {}", r3, r1, r2), + BitXor(r3, r1, r2) => write!(f, "BitXor {} {} {}", r3, r1, r2), + Or(r3, r1, r2) => write!(f, "Or {} {} {}", r3, r1, r2), + And(r3, r1, r2) => write!(f, "And {} {} {}", r3, r1, r2), + Shr(r3, r1, r2) => write!(f, "Shr {} {} {}", r3, r1, r2), + Shl(r3, r1, r2) => write!(f, "Shl {} {} {}", r3, r1, r2), + Label(id) => write!(f, "Label {}", id), + Call(r3, r2, r1) => write!(f, "Call {} {} {}", r3, r2, r1), + LoadArg(r1) => write!(f, "LoadArg {}", r1), + Move(r1, r2) => write!(f, "Move {} {}", r1, r2), + LoadSuper(r3, r2, r1) => write!(f, "LoadSuper {} {} {}", r3, r2, r1), + } + } +} + +impl fmt::Debug for Instruction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::Instruction::*; + + match self { + Neq(dest, r1, r2) => write!(f, "Neq {} {} {}", dest, r1, r2), + Isa(dest, r1, r2) => write!(f, "Isa {} {} {}", dest, r1, r2), + Not(r1, r2) => write!(f, "Not {} {}", r1, r2), + Add(r3, r1, r2) => write!(f, "Add {} {} {}", r3, r1, r2), + Sub(r3, r1, r2) => write!(f, "Sub {} {} {}", r3, r1, r2), + Div(r3, r1, r2) => write!(f, "Div {} {} {}", r3, r1, r2), + Mul(r3, r1, r2) => write!(f, "Mul {} {} {}", r3, r1, r2), + Rem(r3, r1, r2) => write!(f, "Rem {} {} {}", r3, r1, r2), + Gt(r3, r1, r2) => write!(f, "Gt {} {} {} ", r3, r1, r2), + Lt(r3, r1, r2) => write!(f, "Lt {} {} {}", r3, r1, r2), + Le(r3, r1, r2) => write!(f, "Le {} {} {}", r3, r1, r2), + Ge(r3, r1, r2) => write!(f, "Ge {} {} {}", r3, r1, r2), + Eq(r3, r1, r2) => write!(f, "Eq {} {} {}", r3, r1, r2), + Ret0 => write!(f, "Ret0"), + Ret(r1) => write!(f, "Ret {}", r1), + Goto(label_id) => write!(f, "Goto {}", label_id), + GotoF(r1, label_id) => write!(f, "GotoF {} {}", r1, label_id), + Jump(ip) => write!(f, "Jump {}", ip), + JumpF(r1, ip) => write!(f, "JumpF {} {}", r1, ip), + LoadConst(r1, object_id) => write!(f, "LoadConst {} {}", r1, object_id), + LoadGlobal(r1, global) => write!(f, "LoadGlobal {} {}", r1, global), + LoadInt(r1, int) => write!(f, "LoadInt {} {}", r1, int), + LoadLong(r1, long) => write!(f, "LoadLong {} {}", r1, long), + LoadFloat(r1, float) => write!(f, "LoadFloat {} {}", r1, float), + LoadDouble(r1, double) => write!(f, "LoadDouble {} {}", r1, double), + LoadBool(r1, bool) => write!(f, "LoadBool {} {}", r1, bool), + LoadString(r1, str) => write!(f, "LoadString {} \"{}\"", r1, str), + StoreGlobal(r1, global) => write!(f, "StoreGlobal {} {}", r1, global), + StoreAt(r1, r2, r3) => write!(f, "StoreAt {} {} {}", r1, r2, r3), + Store(r1, r2, r3) => write!(f, "Store {} {} {}", r1, r2, r3), + LoadAt(r1, r2, r3) => write!(f, "LoadAt {} {} {}", r1, r2, r3), + BitAnd(r3, r1, r2) => write!(f, "BitAnd {} {} {}", r3, r1, r2), + BitOr(r3, r1, r2) => write!(f, "BitOr {} {} {}", r3, r1, r2), + BitXor(r3, r1, r2) => write!(f, "BitXor {} {} {}", r3, r1, r2), + Or(r3, r1, r2) => write!(f, "Or {} {} {}", r3, r1, r2), + And(r3, r1, r2) => write!(f, "And {} {} {}", r3, r1, r2), + Shr(r3, r1, r2) => write!(f, "Shr {} {} {}", r3, r1, r2), + Shl(r3, r1, r2) => write!(f, "Shl {} {} {}", r3, r1, r2), + Label(id) => write!(f, "Label {}", id), + Call(r3, r2, r1) => write!(f, "Call {} {} {}", r3, r2, r1), + LoadArg(r1) => write!(f, "LoadArg {}", r1), + Move(r1, r2) => write!(f, "Move {} {}", r1, r2), + LoadSuper(r3, r2, r1) => write!(f, "LoadSuper {} {} {}", r3, r2, r1), + } + } +} + +///Trait used for print Vec\ + +pub trait DebugCode { + #[allow(non_snake_case)] + fn toString(&self) -> String; +} + +impl DebugCode for Vec { + fn toString(&self) -> String { + let mut str = String::new(); + for i in 0..self.len() { + str.push_str(&format!("{:04} {}", i, format!("{}", self[i]).white())); + str.push('\n'); + } + str + } +} +/// Stores instructions +#[derive(Clone, Debug)] +pub struct CodeBlock { + pub code: Vec, + pub ip: usize, +} + +impl CodeBlock { + /// Create new instance of CodeBlock + pub fn new(ins: Vec) -> CodeBlock { + CodeBlock { code: ins, ip: 0 } + } +} diff --git a/src/static_root.rs b/src/static_root.rs new file mode 100755 index 0000000..9d56959 --- /dev/null +++ b/src/static_root.rs @@ -0,0 +1,34 @@ +use crate::object::{Object, ObjectAddon}; +use std::{any::Any, cell::RefCell}; +#[derive(Default)] +pub struct StaticRoot { + children: RefCell>, +} + +impl ObjectAddon for StaticRoot {} + +impl Object for StaticRoot { + fn as_any(&self) -> &dyn Any { + self as &dyn Any + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self as &mut dyn Any + } + + fn get_children(&self) -> Vec { + self.children.borrow().clone() + } +} + +impl StaticRoot { + pub fn new() -> StaticRoot { + StaticRoot { + children: RefCell::new(Vec::new()), + } + } + + pub fn append_child(&self, id: usize) { + self.children.borrow_mut().push(id); + } +} diff --git a/src/string.rs b/src/string.rs new file mode 100755 index 0000000..5d9a5f4 --- /dev/null +++ b/src/string.rs @@ -0,0 +1,39 @@ +use crate::{machine::Machine, object::*, object_pool::ObjectPool}; + +impl ObjectAddon for String { + fn typename(&self, _m: &mut Machine) -> String { + String::from("Str") + } + + fn to_String(&self, _: &mut Machine) -> String { + self.clone() + } + + fn to_int(&self, _: &mut Machine) -> i32 { + self.parse::().unwrap() + } + fn to_long(&self, _: &mut Machine) -> i64 { + self.parse::().unwrap() + } + fn to_float(&self, _: &mut Machine) -> f32 { + self.parse::().unwrap() + } + fn to_double(&self, _: &mut Machine) -> f64 { + self.parse::().unwrap() + } +} + +use std::any::Any; + +impl Object for String { + fn initialize(&mut self, _: &mut ObjectPool) {} + fn as_any(&self) -> &dyn Any { + self as &dyn Any + } + fn as_any_mut(&mut self) -> &mut dyn Any { + self as &mut dyn Any + } + fn get_children(&self) -> Vec { + vec![] + } +} diff --git a/src/value.rs b/src/value.rs new file mode 100755 index 0000000..520a0b2 --- /dev/null +++ b/src/value.rs @@ -0,0 +1,183 @@ +#[derive(Clone, Debug, Copy)] +pub enum Value { + /// Integer or i32 in Rust + Int(i32), + /// Long or i64 in Rust + Long(i64), + /// Float or f32 in Rust + Float(f32), + /// Double or f64 in Rust + Double(f64), + /// Pointer to object in pool + Object(usize), + /// Null reference + Null, + /// Boolean + Bool(bool), +} + +use crate::{machine::Machine, object::ObjectAddon}; + +impl ObjectAddon for Value { + fn typename(&self, m: &mut Machine) -> String { + match self { + Value::Bool(_) => String::from("Bool"), + Value::Double(_) => String::from("Float"), + Value::Long(_) => String::from("Int"), + Value::Object(id) => { + let obj = m.pool.get(*id); + obj.typename(m) + } + Value::Null => String::from("null"), + _ => unimplemented!(), + } + } + + fn o_clone(&self, m: &mut Machine) -> Value { + match self { + Value::Object(id) => { + let obj = m.pool.get(*id); + obj.o_clone(m) + } + v => *v, + } + } + fn to_String(&self, m: &mut Machine) -> String { + match self { + Value::Double(d) => d.to_string(), + Value::Float(f) => f.to_string(), + Value::Bool(b) => { + if *b { + "true".to_string() + } else { + "false".to_string() + } + } + Value::Int(i) => i.to_string(), + Value::Long(i) => i.to_string(), + Value::Null => "null".to_string(), + Value::Object(id) => { + let obj = m.pool.get(*id); + obj.to_String(m) + } + } + } + + fn as_bytes(&self, m: &mut Machine) -> Vec { + let string: String = match self { + Value::Double(d) => d.to_string(), + Value::Float(f) => f.to_string(), + Value::Bool(b) => { + if *b { + "true".to_string() + } else { + "false".to_string() + } + } + Value::Int(i) => i.to_string(), + Value::Long(i) => i.to_string(), + Value::Null => "null".to_string(), + Value::Object(id) => { + let obj = m.pool.get(*id); + obj.to_String(m) + } + }; + string.into_bytes() + } + + fn to_int(&self, m: &mut Machine) -> i32 { + match self { + Value::Double(d) => *d as i32, + Value::Float(f) => *f as i32, + Value::Bool(b) => { + if *b { + 1 + } else { + 0 + } + } + Value::Int(i) => *i, + Value::Long(i) => *i as i32, + Value::Null => 0, + Value::Object(id) => { + let obj = m.pool.get(*id); + obj.to_int(m) + } + } + } + + fn to_long(&self, m: &mut Machine) -> i64 { + match self { + Value::Double(d) => *d as i64, + Value::Float(f) => *f as i64, + Value::Bool(b) => { + if *b { + 1 + } else { + 0 + } + } + Value::Int(i) => i64::from(*i), + Value::Long(i) => *i, + Value::Null => 0, + Value::Object(id) => { + let obj = m.pool.get(*id); + obj.to_long(m) + } + } + } + + fn to_float(&self, m: &mut Machine) -> f32 { + match self { + Value::Double(d) => *d as f32, + Value::Float(f) => *f, + Value::Bool(b) => { + if *b { + 1.0 + } else { + 0.0 + } + } + Value::Int(i) => *i as f32, + Value::Long(i) => *i as f32, + Value::Null => 0.0, + Value::Object(id) => { + let obj = m.pool.get(*id); + obj.to_float(m) + } + } + } + + fn to_double(&self, m: &mut Machine) -> f64 { + match self { + Value::Double(d) => *d, + Value::Float(f) => f64::from(*f), + Value::Bool(b) => { + if *b { + 1.0 + } else { + 0.0 + } + } + Value::Int(i) => f64::from(*i), + Value::Long(i) => *i as f64, + Value::Null => 0.0, + Value::Object(id) => { + let obj = m.pool.get(*id); + obj.to_double(m) + } + } + } + + fn not(&self, _m: &mut Machine) -> bool { + match self { + Value::Null => true, + Value::Int(i) => *i == 0, + Value::Long(l) => *l == 0, + Value::Double(b) => *b == 0.0, + Value::Float(f) => *f == 0.0, + Value::Bool(b) => !b, + _ => unimplemented!(), + } + } +}