├── src ├── vm │ ├── runtime │ │ ├── mod.rs │ │ └── memory │ │ │ ├── mod.rs │ │ │ ├── memory_pool │ │ │ └── mod.rs │ │ │ └── runtime_info │ │ │ └── mod.rs │ ├── value.rs │ ├── mod.rs │ └── interpreter.rs ├── binary │ ├── mod.rs │ ├── test.rs │ ├── tags.rs │ ├── variable.rs │ ├── bytecode.rs │ ├── opcode.rs │ ├── constant.rs │ ├── function.rs │ ├── io.rs │ └── debug.rs ├── lib.rs └── main.rs ├── .gitignore ├── cfg ├── README.md ├── Cargo.toml ├── Documents ├── Package and Module │ ├── Loading.md │ ├── Bytecode_Design.md │ └── Design_Draft.md └── Memory Layout.md ├── .github └── workflows │ └── rust.yml ├── .vscode └── launch.json ├── Cargo.lock └── LMVMBExample └── quick_pow.txt /src/vm/runtime/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod memory; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .DS_Store 3 | a.out -------------------------------------------------------------------------------- /cfg: -------------------------------------------------------------------------------- 1 | // compile 2 | BIGNUM 3 | VALUE_TYPE_REFERENCE -------------------------------------------------------------------------------- /src/vm/runtime/memory/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod runtime_info; 2 | pub mod memory_pool; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LemonVMReDesign 2 | 3 | ![Rust CI](https://github.com/LemonVM/LemonVMReDesign/workflows/Rust/badge.svg) 4 | 5 | 重新设计LemonVM用于AcidJS运行时 6 | -------------------------------------------------------------------------------- /src/binary/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | A LMVMB file is either a executable lemonvm binary or 3 | a library 4 | */ 5 | pub mod bytecode; 6 | pub mod constant; 7 | pub mod debug; 8 | pub mod function; 9 | pub mod io; 10 | pub mod opcode; 11 | pub mod variable; 12 | pub mod tags; 13 | 14 | mod test; -------------------------------------------------------------------------------- /src/vm/runtime/memory/memory_pool/mod.rs: -------------------------------------------------------------------------------- 1 | pub static LemonVMMemoryPool: *mut u8 = std::ptr::null_mut(); 2 | pub static LemonVMRoots: *mut u8 = std::ptr::null_mut(); 3 | struct Pool{ 4 | 5 | } 6 | 7 | union Ref{ 8 | primitive: u64, 9 | module: RuntimeModule, 10 | } 11 | 12 | struct GCRef{ 13 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lemonvm" 3 | version = "0.2.0" 4 | authors = ["LemonHX "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "liblemonvm" 9 | path = "src/lib.rs" 10 | 11 | [[bin]] 12 | name = "lemonvm_repl" 13 | path = "src/main.rs" 14 | 15 | [dev-dependencies] 16 | 17 | [dependencies] 18 | rand = "*" -------------------------------------------------------------------------------- /Documents/Package and Module/Loading.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 首先, VM作为主运行时而非寄生运行时的时候, 使用类似JVM的方式进行目录查找 3 | - Bootstrap : `~/.lemonvm/bootstrap/*` 4 | - Extension : `~/.lemonvm/extension/*` 5 | - User : `. | LEMONVM_MODULE_PATH | -mp "string"` 6 | 7 | 也就这仨, 具体有三种Entry 8 | - Dir + Wildcard 9 | - Package : zip file with manifest.json 10 | - String (也就是裸指针) 11 | -------------------------------------------------------------------------------- /Documents/Memory Layout.md: -------------------------------------------------------------------------------- 1 | # 内存布局 2 | 3 | ## 线程私有的信息 4 | ```c 5 | ThreadInfo{ 6 | u64 pc; 7 | u8 args_len; 8 | Value call_args[args_len]; 9 | Value registers[MAX_REGISTER_LEN]; 10 | } 11 | ``` 12 | 13 | ## 全局共享的信息 14 | 只能加不能减,不能改的 15 | - Global Values 16 | - Runtime Packages 17 | - Runtime Modules 18 | - Runtime Constant Pool 19 | 20 | GC帮着管理的 21 | - Reference Typed Values 22 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod binary; 2 | pub mod vm; 3 | 4 | pub fn lemonvm_init() -> *mut u8{ 5 | // load bytecode 6 | // init runtime memories 7 | } 8 | 9 | pub fn lemonvm_run(lemonvm_instance:*mut u8,function_name: std::ffi::CString){ 10 | // look for function to run 11 | } 12 | 13 | pub fn lemonvm_destroy(lemonvm_instance:*mut u8){ 14 | } 15 | 16 | pub fn lemonvm_start(){ 17 | // init 18 | // run main function 19 | 20 | // destroy 21 | } -------------------------------------------------------------------------------- /src/binary/test.rs: -------------------------------------------------------------------------------- 1 | use super::bytecode::*; 2 | use super::io::*; 3 | use std::fs::File; 4 | use std::io::prelude::*; 5 | use std::io::BufReader; 6 | 7 | // #[test] 8 | // fn test_bytecode_read() { 9 | // let mut content: Vec = Vec::new(); 10 | // { 11 | // let file = File::open("114514.txt").unwrap(); 12 | // let mut buffer = BufReader::new(file); 13 | // buffer.read_to_end(&mut content).unwrap(); 14 | // } 15 | // let mut reader = Reader::new(content.as_ptr()); 16 | // let _bytecodes = LemonVMByteCode::read(&mut reader); 17 | // } 18 | -------------------------------------------------------------------------------- /src/vm/value.rs: -------------------------------------------------------------------------------- 1 | use super::{gc::*, VMClosure, VMClosureStatus, VMState}; 2 | use crate::binary::constant::Constant; 3 | use std::{collections::BTreeMap, ptr::NonNull}; 4 | 5 | use std::mem::ManuallyDrop; 6 | 7 | pub union Value{ 8 | _bool:bool, 9 | u_8:u8, 10 | i_8:i8, 11 | 12 | } 13 | 14 | #[derive(Debug, Clone, Copy, PartialEq)] 15 | pub enum Value { 16 | // on stack 17 | Null, 18 | Undef, 19 | Boolean(bool), 20 | 21 | U8(u8), 22 | I8(i8), 23 | U16(u16), 24 | I16(i16), 25 | U32(u32), 26 | I32(i32), 27 | U64(u64), 28 | I64(i64), 29 | F32(f32), 30 | F64(f64), 31 | // on heap but not escaped (managed by rust) 32 | NSValue(NSValue), 33 | // on gc heap 34 | GCValue(GCValue), 35 | } -------------------------------------------------------------------------------- /src/binary/tags.rs: -------------------------------------------------------------------------------- 1 | 2 | // MemoryTags first two digit of u8 tag 3 | const REGVar:u8 = 0b00000000; 4 | const NSVar:u8 = 0b01000000; 5 | const GCVar:u8 = 0b10000000; 6 | 7 | // TypeTags last 6 digit of u8 tag 8 | pub const UndefinedType:u8 = 0x00; 9 | pub const NullType:u8 = 0x01; 10 | pub const U8Type:u8 = 0x02; 11 | pub const I8Type:u8 = 0x03; 12 | pub const U16T.ype:u8 = 0x04; 13 | pub const I16Type:u8 = 0x05; 14 | pub const U32Type:u8 = 0x06; 15 | pub const I32Type:u8 = 0x07; 16 | pub const U64Type:u8 = 0x08; 17 | pub const I64Type:u8 = 0x09; 18 | pub const F32Type:u8 = 0x0A; 19 | pub const F64Type:u8 = 0x0B; 20 | 21 | const StringType:u8 = 0x0C; 22 | const SymbolType:u8 = 0x0D; 23 | 24 | const VectorType:u8 = 0x0E; 25 | const MapType:u8 = 0x0F; 26 | const ClosureType:u8 = 0x10; 27 | // use to make typed array 28 | const OpaqueType:u8 = 0x11; 29 | 30 | // With extension 31 | #[cfg(BIG_INT)] 32 | const BigIntType:u8 = 0x12; 33 | #[cfg(VALUE_TYPE_REFERENCE)] 34 | const REFType:u8 = 0x13; -------------------------------------------------------------------------------- /Documents/Package and Module/Bytecode_Design.md: -------------------------------------------------------------------------------- 1 | # Package 文件 2 | TODO 3 | # Module 文件 4 | 5 | 下面是类C语言伪代码表示的Module二进制文件的存储格式 6 | ```c 7 | ModuleByteCode { 8 | u8 signature[5]; 9 | u32 version; 10 | u8 extension_length; 11 | u8 extensions_id [extension_length]; 12 | // constant pool 13 | u64 pool_len; 14 | value pool [pool_len]; 15 | // fields 16 | u32 field_len; 17 | FieldInfo fields [field_len]; 18 | // infos such as debug info 19 | u8 info_len; 20 | Value infos [info_len]; 21 | } 22 | ``` 23 | > 为了平台规范性,module文件存储的所有的数据采用大端存储 24 | 25 | 这是module中每一field的结构定义 26 | ```c 27 | FieldInfo{ 28 | // extern public static private ... 29 | u16 access_mask; 30 | // field name in constant pool 31 | u16 name_index; 32 | u16 type_info_index; 33 | u8 info_len; 34 | Value infos [info_len]; 35 | // for stack allocate data 36 | u32 value_index; 37 | } 38 | ``` 39 | 40 | 这是Constant Pool中任意一个Constant的定义 41 | ```c 42 | Value{ 43 | // type tag or info tag 44 | u8 tag; 45 | union primitives value; 46 | } 47 | ``` -------------------------------------------------------------------------------- /Documents/Package and Module/Design_Draft.md: -------------------------------------------------------------------------------- 1 | # LemonVM Module & Package 设计草案 2 | 首先就是说为什么存在module 3 | 1. 方便去做类似JVM这种class文件一样的模块化动态加载 4 | 2. 同时解决模块化的问题,类似JAVA的package的概念 5 | 6 | 然后就是为什么存在Package文件 7 | 1. package文件是用来解决部署的问题的,因为LemonVM的初心在于打造一个 8 | 万能的胶水语言的VM,所以为了方便胶水的管理设立一个官方的package 9 | 2. 同时去解决依赖问题,这里我觉得JAR和DLL都没有做好,都会陷入JAR地狱和DLL地狱 10 | 原因在于一开始没有考虑到现代的这种包管理 11 | 12 | ## LemonVM Module 13 | Module类似JVM的class文件,包含了头,常量池,调试信息,还有就是改Module的加载方法 14 | ### Module 相当于什么 15 | Module大概相当于类型,和这个类型的伴生方法,同时这个类型是如何构造的 16 | 因为Module的构造是在LemonVM的加载时期动态完成的,所以也就不存在HKT的问题。 17 | 18 | ### Module的类型信息 19 | Module在加载之前的字节码状态的时候暂时还没想好如何处理类型信息 `TODO` 20 | 原因是我想引入VM自带的Structural Type的同时还想处理Alias问题 21 | 但是简单来讲就只是最最基础的类似String或者HashMap之类的字面类型, 22 | 当Module在正式加载之后才开始去填充他的实际的类型信息, 23 | 同时指引字面类型到某个虚拟机里面的实际类型,这也使得动态加载变得可行。 24 | 25 | 同时`TODO`我还没有想好动态加载进来的新的Module 26 | 对于已经存在的旧的带有Parameter的Module之间的关系,不过我暂时认为 27 | 28 | `List`和`List`之间不应该存在什么关系( 29 | 至少想要他们发生关系的话需要先lift到`Any`类型 30 | 31 | 所以每一个有parameter构造的module在新的实例加载并使用的时候才会构造新的类型。 32 | 33 | ## LemonVM Package 34 | Package相当与库或者是可执行文件,Package会有一个配置文件 35 | 在这个配置文件里需要描述依赖关系 36 | 37 | Package和Module的关系是Module \in Package,通过指定那个Module中那个函数作为main来运行。 38 | 39 | ### 依赖关系的处理 40 | 老生畅谈的问题,比如循环依赖怎么解决 41 | 42 | 在一个Package被加载的时候,对本体进行缓存后首先去加载他的依赖Package,同时在加载依赖Package的时候 43 | 遇到对本体的依赖,当版本信息位于此大版本之内将不会加载,若大版本有区别就报错呗~ 44 | 45 | 同时由于Module的类型信息也是运行时加载的,所以不存在那个类型不匹配之类的。 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/binary/variable.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | io::{BinaryRW, Reader, Writer}, 3 | TypeTags, 4 | }; 5 | use std::collections::BTreeMap; 6 | // strong type extension 7 | #[derive(Debug, Clone)] 8 | enum Type { 9 | Mono(TypeTags), 10 | Record(BTreeMap), 11 | // last in function is the return value type 12 | Function(Vec), 13 | } 14 | 15 | #[derive(Debug, Clone)] 16 | pub struct Variable { 17 | name: u16, 18 | access: u8, 19 | init_value: Option, 20 | // strong type extension 21 | // type_info: Type, 22 | } 23 | 24 | impl BinaryRW for Variable { 25 | fn read(reader: &mut Reader) -> Self { 26 | let name = reader.read_u16(); 27 | let access = reader.read_u8(); 28 | let init_value = reader.read_option(|reader| reader.read_u16()); 29 | Variable { 30 | name, 31 | access, 32 | init_value, 33 | } 34 | } 35 | 36 | fn write(&self, writer: &mut Writer) { 37 | writer.write_u16(self.name); 38 | writer.write_u8(self.access); 39 | writer.write_option(self.init_value, |write, u| write.write_u16(u)); 40 | } 41 | 42 | // #[cfg(mock)] 43 | fn mock_data() -> Vec> { 44 | use rand::*; 45 | let mut ret = vec![]; 46 | for _ in 0..10 { 47 | ret.push(Box::new(Variable { 48 | name: random(), 49 | access: random(), 50 | init_value: if random() { Some(random()) } else { None }, 51 | })); 52 | } 53 | ret 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "lldb", 9 | "request": "launch", 10 | "name": "Debug unit tests in library 'liblemonvm'", 11 | "cargo": { 12 | "args": [ 13 | "test", 14 | "--no-run", 15 | "--lib", 16 | "--package=lemonvm" 17 | ], 18 | "filter": { 19 | "name": "liblemonvm", 20 | "kind": "lib" 21 | } 22 | }, 23 | "args": [], 24 | "cwd": "${workspaceFolder}" 25 | }, 26 | { 27 | "type": "lldb", 28 | "request": "launch", 29 | "name": "Debug executable 'lemonvm_repl'", 30 | "cargo": { 31 | "args": [ 32 | "build", 33 | "--bin=lemonvm_repl", 34 | "--package=lemonvm" 35 | ], 36 | "filter": { 37 | "name": "lemonvm_repl", 38 | "kind": "bin" 39 | } 40 | }, 41 | "args": [], 42 | "cwd": "${workspaceFolder}" 43 | }, 44 | { 45 | "type": "lldb", 46 | "request": "launch", 47 | "name": "Debug unit tests in executable 'lemonvm_repl'", 48 | "cargo": { 49 | "args": [ 50 | "test", 51 | "--no-run", 52 | "--bin=lemonvm_repl", 53 | "--package=lemonvm" 54 | ], 55 | "filter": { 56 | "name": "lemonvm_repl", 57 | "kind": "bin" 58 | } 59 | }, 60 | "args": [], 61 | "cwd": "${workspaceFolder}" 62 | } 63 | ] 64 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "cfg-if" 5 | version = "0.1.10" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 8 | 9 | [[package]] 10 | name = "getrandom" 11 | version = "0.1.15" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" 14 | dependencies = [ 15 | "cfg-if", 16 | "libc", 17 | "wasi", 18 | ] 19 | 20 | [[package]] 21 | name = "lemonvm" 22 | version = "0.2.0" 23 | dependencies = [ 24 | "rand", 25 | ] 26 | 27 | [[package]] 28 | name = "libc" 29 | version = "0.2.78" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98" 32 | 33 | [[package]] 34 | name = "ppv-lite86" 35 | version = "0.2.9" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" 38 | 39 | [[package]] 40 | name = "rand" 41 | version = "0.7.3" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 44 | dependencies = [ 45 | "getrandom", 46 | "libc", 47 | "rand_chacha", 48 | "rand_core", 49 | "rand_hc", 50 | ] 51 | 52 | [[package]] 53 | name = "rand_chacha" 54 | version = "0.2.2" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 57 | dependencies = [ 58 | "ppv-lite86", 59 | "rand_core", 60 | ] 61 | 62 | [[package]] 63 | name = "rand_core" 64 | version = "0.5.1" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 67 | dependencies = [ 68 | "getrandom", 69 | ] 70 | 71 | [[package]] 72 | name = "rand_hc" 73 | version = "0.2.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 76 | dependencies = [ 77 | "rand_core", 78 | ] 79 | 80 | [[package]] 81 | name = "wasi" 82 | version = "0.9.0+wasi-snapshot-preview1" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 85 | -------------------------------------------------------------------------------- /src/vm/runtime/memory/runtime_info/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, sync::Arc, sync::Mutex}; 2 | 3 | type ConstantPoolRef = u16; 4 | enum TypeInfoType{ 5 | // for example generic module doesnt apply shit 6 | UNINIT_GENERIC, 7 | // just type name for example I32 8 | MONO, 9 | // typed by fields for example struct A { i32 a } -> {a:I32} 10 | STRUCTRUAL, 11 | // functions closures 12 | ARROR, 13 | } 14 | union TypeInfoVale{ 15 | // uninit generic 16 | uninit_generic: ConstantPoolRef, 17 | // mono: tag 18 | mono: u8, 19 | // structrual 20 | structrual: Vec<(Option,ConstantPoolRef,RuntimeTypeInfo)>, 21 | // arrow 22 | arrow: (Vec<(Option,ConstantPoolRef,RuntimeTypeInfo)>,Vec<(ConstantPoolRef,RuntimeTypeInfo)>), 23 | } 24 | 25 | pub struct RuntimeTypeInfo{ 26 | // constant pool index 27 | pub type_name: ConstantPoolRef, 28 | // type info type 29 | pub info: u8, 30 | pub type_info: TypeInfoValue, 31 | } 32 | 33 | pub struct RuntimeField{ 34 | pub type_info: RuntimeTypeInfo, 35 | // if current module is value typed 36 | pub value_typed_index:u16, 37 | } 38 | pub struct RuntimeModule{ 39 | pub constant_pool:Vec, 40 | pub field_index_table: HashMap, 41 | pub fields : HashMap, 42 | } 43 | 44 | pub struct RuntimeThreadInfo { 45 | pub registers: [Value;64], 46 | pub pc: u16, 47 | pub status: VMClosureStatus, 48 | // after throwing an exception and in that scope there is no exception handler 49 | // in that case the exception will throw to super function call 50 | // for saving the exception status adding the closure into the exception_stack 51 | // when the exception is finally handled the exception stack is renewed 52 | pub exception_stack: Vec, 53 | // in runtime add break point(pc) or removing a break point in current function 54 | pub break_points: Vec, 55 | 56 | pub closure: VMClosure, 57 | pub shared_data: Arc 58 | } 59 | 60 | 61 | 62 | pub struct RuntimeShareData{ 63 | // thread pool info 64 | pub modules: Mutex>, 65 | pub global_vars: Mutex>, 66 | pub memory_pool: MemoryPool, 67 | // jit mems 68 | 69 | // enable debug mode will able to see the bytecode executed 70 | pub debug_mode: bool, 71 | // enable profile mode will display the memory usage and gc status 72 | pub profile_mode: bool, 73 | } -------------------------------------------------------------------------------- /LMVMBExample/quick_pow.txt: -------------------------------------------------------------------------------- 1 | /* 0: */ INS!(IMMU32 , 0x0002u16, 0x0000u16, 0x0000u16), 2 | /* 1: */ INS!(IMMU32 , 0x0003u16, 0x0001u16, 0x0000u16), 3 | /* 2: */ INS!(SEQ , 0x0001u16, 0x0002u16, 0x0002u16), 4 | /* 3: */ INS!(JPN , 0x0002u16, 0x0005u16, 0x0000u16), 5 | /* 4: */ INS!(RET , 0x0003u16, 0x0000u16, 0x0000u16), 6 | /* 5: */ INS!(SEQ , 0x0001u16, 0x0003u16, 0x0002u16), 7 | /* 6: */ INS!(JPN , 0x0002u16, 0x0008u16, 0x0000u16), 8 | /* 7: */ INS!(RET , 0x0000u16, 0x0000u16, 0x0000u16), 9 | /* 8: */ INS!(LOADK , 0x0004u16, 0x0001u16, 0xFFFFu16), 10 | /* 9: */ INS!(IMMU32 , 0x0002u16, 0x0002u16, 0x0000u16), 11 | /* A: */ INS!(DIV32 , 0x0001u16, 0x0002u16, 0x0002u16), 12 | /* B: */ INS!(ARGS , 0x0000u16, 0x0000u16, 0x0000u16), 13 | /* C: */ INS!(ARGS , 0x0002u16, 0x0000u16, 0x0000u16), 14 | /* D: */ INS!(CALL , 0x0004u16, 0x0000u16, 0x0000u16), 15 | /* E: */ INS!(GETRET , 0x0002u16, 0x0000u16, 0x0000u16), 16 | /* F: */ INS!(MUL32 , 0x0002u16, 0x0002u16, 0x0002u16), 17 | /* 10: */ INS!(BAND , 0x0001u16, 0x0003u16, 0x0004u16), 18 | /* 11: */ INS!(SEQ , 0x0004u16, 0x0003u16, 0x0004u16), 19 | /* 12: */ INS!(JPN , 0x0004u16, 0x0014u16, 0x0000u16), 20 | /* 13: */ INS!(MUL32 , 0x0002u16, 0x0000u16, 0x0002u16), 21 | /* 14: */ INS!(RET , 0x0002u16, 0x0000u16, 0x0000u16), 22 | 23 | // load 0 24 | /* 0 */ INS!(IMMU32,0x0002u16,0x0000u16,0x0000u16), 25 | // load 1 26 | /* 1 */ INS!(IMMU32,0x0003u16,0x0001u16,0x0000u16), 27 | // load f 28 | /* 2 */ INS!(LOADK,0x0009u16,0x0001u16,0xFFFFu16), 29 | // == 0 30 | /* 3 */ INS!(SEQ,0x0001u16,0x0002u16,0x0004u16), 31 | /* 4 */ INS!(JPN,0x0004u16,0x0006u16,0x0000u16), 32 | /* 5 */ INS!(RET,0x0003u16,0x0000u16,0x0000u16), 33 | // == 1 34 | /* 6 */ INS!(SEQ,0x0001u16,0x0003u16,0x0004u16), 35 | /* 7 */ INS!(JPN,0x0004u16,0x0009u16,0x0000u16), 36 | /* 8 */ INS!(RET,0x0000u16,0x0000u16,0x0000u16), 37 | // %2 38 | /* 9 */ INS!(IMMU32,0x0005u16,0x0002u16,0x0000u16), 39 | /* A */ INS!(REM32,0x0001u16,0x0005u16,0x0006u16), 40 | /* B */ INS!(SEQ,0x0006u16,0x0002u16,0x0004u16), 41 | /* C */ INS!(JPE,0x0004u16,0x000Eu16,0x0000u16), 42 | /* D */ INS!(JPN,0x0004u16,0x0015u16,0x0000u16), 43 | // == 0 44 | /* E */ INS!(MUL32,0x0000u16,0x0000u16,0x0007u16), 45 | /* F */ INS!(DIV32,0x0001u16,0x0005u16,0x0008u16), 46 | /* 10 */ INS!(ARGS,0x0007u16,0x0000u16,0x0000u16), 47 | /* 11 */ INS!(ARGS,0x0008u16,0x0000u16,0x0000u16), 48 | /* 12 */ INS!(CALL,0x0009u16,0x0000u16,0x0000u16), 49 | /* 13 */ INS!(GETRET,0x0009u16,0x0000u16,0x0000u16), 50 | /* 14 */ INS!(RET,0x0009u16,0x0000u16,0x0000u16), 51 | // != 0 52 | /* 15 */ INS!(MUL32,0x0000u16,0x0000u16,0x0007u16), 53 | /* 16 */ INS!(SUB32,0x0001u16,0x0002u16,0x0008u16), 54 | /* 17 */ INS!(DIV32,0x0008u16,0x0005u16,0x0008u16), 55 | /* 18 */ INS!(ARGS,0x0007u16,0x0000u16,0x0000u16), 56 | /* 19 */ INS!(ARGS,0x0008u16,0x0000u16,0x0000u16), 57 | /* 1A */ INS!(CALL,0x0009u16,0x0000u16,0x0000u16), 58 | /* 1B */ INS!(GETRET,0x0009u16,0x0000u16,0x0000u16), 59 | /* 1C */ INS!(MUL32,0x0000u16,0x0009u16,0x0009u16), 60 | /* 1D */ INS!(RET,0x0009u16,0x0000u16,0x0000u16), -------------------------------------------------------------------------------- /src/binary/bytecode.rs: -------------------------------------------------------------------------------- 1 | /* 2 | an instruction is normally 64 bit long 3 | 4 | ins rega regb regc 5 | 0x00 0x00 0xAA 0xAA 0xBB 0xBB 0xCC 0xCC 6 | 7 | but abnormally some ins uses more than 48 bit data 8 | ins data-start: 9 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 10 | ins EXTRA 11 | 0x00 0xAA 0x00 0x00 0x00 0x00 0x00 0x00 12 | 13 | until the next instruction is not start with 0xAA 14 | the data is fully loaded 15 | */ 16 | use super::{ 17 | constant::Constant, 18 | io::{BinaryRW, Reader, Writer}, 19 | variable::Variable, 20 | }; 21 | use std::collections::BTreeMap; 22 | 23 | pub struct LemonVMByteCode { 24 | signature: [u8; 5], 25 | version: u32, 26 | enabled_extensions: Vec, 27 | // find in constant pool 28 | // before loading the bytecode first check the name exist in the vm instance 29 | // then check the version 30 | // if all equal do nothing 31 | // if (version | name) not equal load 32 | module_name: u16, 33 | module_version: u32, 34 | 35 | // format 36 | // u32 len 37 | // u16 value(tag data) 38 | // ... 39 | constant_pool: BTreeMap, 40 | 41 | // to index the main function from constant_pool by uuid 42 | entry: Option, 43 | variables: Vec, 44 | } 45 | 46 | impl BinaryRW for LemonVMByteCode { 47 | fn read(reader: &mut Reader) -> Self { 48 | let s1 = reader.read_u8(); 49 | let s2 = reader.read_u8(); 50 | let s3 = reader.read_u8(); 51 | let s4 = reader.read_u8(); 52 | let s5 = reader.read_u8(); 53 | let signature = [s1, s2, s3, s4, s5]; 54 | let version = reader.read_u32(); 55 | let enabled_extensions = reader.read_vec(|reader| reader.read_u8()); 56 | let module_name = reader.read_u16(); 57 | let module_version = reader.read_u32(); 58 | let constant_pool = reader.read_map(|reader| (reader.read_u16(), Constant::read(reader))); 59 | let entry = reader.read_option(|reader| reader.read_u16()); 60 | let variables = reader.read_vec(|reader| Variable::read(reader)); 61 | LemonVMByteCode { 62 | signature, 63 | version, 64 | module_name, 65 | module_version, 66 | enabled_extensions, 67 | constant_pool, 68 | entry, 69 | variables, 70 | } 71 | } 72 | fn write(&self, writer: &mut Writer) { 73 | for i in self.signature.iter() { 74 | writer.write_u8(*i); 75 | } 76 | writer.write_u32(self.version); 77 | writer.write_vec(self.enabled_extensions.clone(), |write, u| { 78 | write.write_u8(u) 79 | }); 80 | writer.write_map(self.constant_pool.clone(), |writer, (id, c)| { 81 | writer.write_u16(id); 82 | c.write(writer); 83 | }); 84 | writer.write_option(self.entry, |write, u| write.write_u16(u)); 85 | writer.write_vec(self.variables.clone(), |writer, i| i.write(writer)) 86 | } 87 | 88 | //TODO: i don't think this need test 89 | // #[cfg(mock)] 90 | fn mock_data() -> Vec> { 91 | use rand::*; 92 | let mut ret = vec![]; 93 | ret 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use liblemonvm::{binary::{constant::Constant, function::{Function, FunctionType}}, vm::*}; 2 | use std::{ptr::NonNull, collections::BTreeMap}; 3 | use gc::{onclosegc::OnCloseGC, GC}; 4 | use liblemonvm::binary::opcode::OpCode::*; 5 | macro_rules! INS { 6 | ($code:ident,$e1:literal,$e2:literal,$e3:literal) => { 7 | { 8 | let mut i = $code as u64; 9 | i |= ($e1 as u64) << 16; 10 | i |= ($e2 as u64) << 32; 11 | i |= ($e3 as u64) << 48; 12 | i 13 | } 14 | }; 15 | } 16 | 17 | fn main() { 18 | let fib = Function{ 19 | is_multi_return_function: false, 20 | function_type: FunctionType::Function, 21 | args_count: 1, 22 | max_registers: 255, 23 | code: vec![ 24 | // load 0 25 | INS!(IMMU32,0x0001u16,0x0000u16,0x0000u16), 26 | // load 1 27 | INS!(IMMU32,0x0002u16,0x0001u16,0x0000u16), 28 | // if args[0] == 0 || args[0] == 1 29 | INS!(SEQ,0x0000u16,0x0001u16,0x0003u16), 30 | INS!(SEQ,0x0000u16,0x0002u16,0x0004u16), 31 | INS!(OR ,0x0003u16,0x0004u16,0x0003u16), 32 | INS!(JPN,0x0003u16,0x0007u16,0x0000u16), 33 | INS!(RET,0x0002u16,0x0000u16,0x0000u16), 34 | // else 35 | // load this closure 36 | INS!(LOADK,0x0004u16,0x0001u16,0xFFFFu16), 37 | // load 2 38 | INS!(IMMU32,0x0005u16,0x0002u16,0x0000u16), 39 | INS!(SUB32,0x0000u16,0x0005u16,0x0006u16), 40 | INS!(ARGS,0x0006u16,0x0000u16,0x0000u16), 41 | INS!(CALL,0x0004u16,0x0000u16,0x0000u16), 42 | INS!(GETRET,0x0007u16,0x0000u16,0x0000u16), 43 | 44 | INS!(SUB32,0x0000u16,0x0002u16,0x0006u16), 45 | INS!(ARGS,0x0006u16,0x0000u16,0x0000u16), 46 | INS!(CALL,0x0004u16,0x0000u16,0x0000u16), 47 | INS!(GETRET,0x0008u16,0x0000u16,0x0000u16), 48 | INS!(ADD32,0x0007u16,0x0008u16,0x0007u16), 49 | 50 | INS!(RET ,0x0007u16,0x0000u16,0x0000u16), 51 | ], 52 | 53 | exception_table: None, 54 | debug_info: None, 55 | }; 56 | let bytecode = Function{ 57 | is_multi_return_function: false, 58 | function_type: FunctionType::Function, 59 | args_count: 0, 60 | max_registers: 255, 61 | code: vec![ 62 | INS!(LOADK,0x0000u16,0x0001u16,0xFFFFu16), 63 | INS!(IMMU32,0x0001u16,0x0018u16,0x0000u16), 64 | INS!(ARGS,0x0001u16,0x0000u16,0x0000u16), 65 | INS!(CALL,0x0000u16,0x0000u16,0x0000u16), 66 | INS!(GETRET,0x0002u16,0x0000u16,0x0000u16), 67 | INS!(RET,0x0002u16,0x0000u16,0x0000u16) 68 | ], 69 | 70 | exception_table: None, 71 | debug_info: None, 72 | }; 73 | let closure = VMClosure{ 74 | function_bytecode: bytecode, 75 | registers: vec![], 76 | pc: 0, 77 | status: VMClosureStatus::None, 78 | constant_pool_ptr: unsafe{NonNull::new_unchecked(std::ptr::null_mut())}, 79 | stack_values: vec![], 80 | }; 81 | let gc: Box = Box::new(OnCloseGC{ blocks: vec![], pool: vec![]}); 82 | let mut state = VMState{ 83 | function_call_chain_states: vec![], 84 | current_function_call_state: closure, 85 | exception_stack: vec![], 86 | args: vec![], 87 | nargs: BTreeMap::new(), 88 | return_value: None, 89 | return_values: vec![], 90 | constant_pools: vec![], 91 | debug_mode: true, 92 | profile_mode: true, 93 | break_points: vec![], 94 | gc, 95 | }; 96 | let mut CP = BTreeMap::new(); 97 | CP.insert(0x0001, Constant::Function(fib)); 98 | state.constant_pools.push(CP); 99 | state.current_function_call_state.constant_pool_ptr = NonNull::new(state.constant_pools.last_mut().unwrap()).unwrap(); 100 | interpreter::interpreter(&mut state); 101 | println!("{:?}",state.return_value); 102 | } 103 | -------------------------------------------------------------------------------- /src/binary/opcode.rs: -------------------------------------------------------------------------------- 1 | #[repr(u16)] 2 | #[derive(Debug)] 3 | pub enum OpCode { 4 | // use as debug 5 | // in debug mode will print the VM runtime info 6 | NOP = 0x0000, 7 | 8 | // ===== LOAD ===== 9 | // load constant 10 | // LOADK dst [index] [module_name_index or 0xFFFF(local)] 11 | LOADK, 12 | // ===== IMMLOAD ===== 13 | // used for performance 14 | // IMMBOOL dst 0x0100(true) 0x0000 15 | IMMBOOL, 16 | // IMMI16 dst [0x01 0x00 0x00 0x00](1) 17 | IMMU8, 18 | IMMI8, 19 | IMMU16, 20 | IMMI16, 21 | IMMU32, 22 | IMMI32, 23 | IMMF32, 24 | 25 | // EXTRA [48bit data] 26 | EXTRA, 27 | // IMMX64 dst [32bit 28 | // EXTRA 32bit] 16bit 29 | IMMU64, 30 | IMMI64, 31 | IMMF64, 32 | 33 | // IMMSTR only used to load short string for saving time of indexing constant pool 34 | // similar to IMMF64 35 | IMMSTR, 36 | 37 | // ===== ARITH ===== 38 | // enable operator overload will influence the performance 39 | // due to it looks table rather than directly doing the arith 40 | 41 | // Ix will neg imm 42 | // Ux will force cast to Ix then neg 43 | // NEG dst src 44 | NEG, 45 | // Ix will neg imm 46 | // Ux and other will panic 47 | // TODO: throw exception 48 | SNEG, 49 | 50 | // format INS src1 src2 dst 51 | ADD8, 52 | SUB8, 53 | MUL8, 54 | REM8, 55 | DIV8, 56 | 57 | ADD16, 58 | SUB16, 59 | MUL16, 60 | REM16, 61 | DIV16, 62 | 63 | ADD32, 64 | SUB32, 65 | MUL32, 66 | REM32, 67 | DIV32, 68 | 69 | ADD64, 70 | SUB64, 71 | MUL64, 72 | REM64, 73 | DIV64, 74 | 75 | // safe arith 76 | // check value that make sure is not overflow 77 | // check for minus unsigned value 78 | // check for div 0 79 | SA, 80 | 81 | // FLOATING ARITH 82 | ADDF32, 83 | SUBF32, 84 | MULF32, 85 | REMF32, 86 | DIVF32, 87 | 88 | ADDF64, 89 | SUBF64, 90 | MULF64, 91 | REMF64, 92 | DIVF64, 93 | 94 | BNOT, 95 | BAND, 96 | BXOR, 97 | BOR, 98 | 99 | SHL, 100 | SHR, 101 | 102 | NOT, 103 | AND, 104 | OR, 105 | 106 | EQ, 107 | LT, 108 | GT, 109 | LTEQ, 110 | GTEQ, 111 | 112 | // ===== CONTROL FLOW ===== 113 | // normally won't generate 114 | // JMP [16bit label] 115 | JMP, 116 | // if true 117 | // JPE src [16bit label] 118 | JPE, 119 | // if false 120 | // JPN src [16bit label] 121 | JPN, 122 | // ===== FUNCTION? ===== 123 | // pushing a new call frame in local thread 124 | // PUSHF 125 | PUSHF, 126 | // pushing a new var into the tail of call frame 127 | // PUSHARG src 128 | PUSHARG, 129 | // pusing a named var into the tail of call frame 130 | // PUSHNARG src 131 | PUSHNARG, 132 | // CALL 133 | // enter the tail of call frame 134 | // CALL src 135 | // call the closure 136 | CALL, 137 | // this ins is unstable, so normally will not generate 138 | // TAILCALL args-reg 139 | TAILCALL, 140 | // TODO: implement 141 | CALLCONS, 142 | // TODO: implement 143 | CALLMETHOD, 144 | GETRET, 145 | // RET 0xFFFF => return void 146 | // RET src 147 | // set return value to the VMState 148 | RET, 149 | // RETN src(RETS) 150 | // append return value into the VMState 151 | // usage: RETN 0x0100; RETN 0x0200; RET 0xFFFF; 152 | RETN, 153 | // raise an error into VM status 154 | // check next exception table in current function 155 | // if not then goto last function call satck with last pc and check recursively 156 | ERROR, 157 | 158 | // ===== TEMP CONTAINER ===== 159 | // container object managed by rust instead of managed by gc 160 | // make dst a vec object, if already is , then push src to dst 161 | // VEC dst src 162 | VEC, 163 | 164 | TOGC, 165 | 166 | // ===== OBJECT and MODULE ===== 167 | // An object is an runtime defined anonymous object 168 | // or loaded a dynamic(which means has state) module(lmvmb file loaded) instance 169 | 170 | // LOADMODULE will load module into the vmstate 171 | // LOADMODULE [module_name_index or 0xFFFF(local)] 172 | LOADMODULE, 173 | // NEWOBJM dst [module_name_index or 0xFFFF(local)] 174 | NEWOBJM, 175 | SETV, 176 | ADDKV, 177 | INDEXV, 178 | FINDKBYV, 179 | // NEWOBJ dst 180 | NEWOBJ, 181 | } 182 | -------------------------------------------------------------------------------- /src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::binary::{constant::Constant, function::Function}; 2 | use std::{collections::BTreeMap, ptr::NonNull}; 3 | use value::{NSValue, Value}; 4 | 5 | 6 | pub mod runtime; 7 | pub mod interpreter; 8 | pub mod register; 9 | pub mod value; 10 | 11 | #[derive(Debug, Clone, PartialEq)] 12 | pub enum VMClosureStatus { 13 | None, 14 | Error, 15 | Yield, 16 | } 17 | 18 | // function call 19 | // first use args to fix all the variable that calling this function 20 | // to an args object 21 | // then using the max call args to make the register mapping 22 | // if arguments is far more over then think a way to... kind of vargs for example make an object 23 | #[derive(Debug, Clone, PartialEq)] 24 | pub struct VMClosure { 25 | pub function_bytecode: Function, 26 | pub registers: Vec, 27 | pub pc: u16, 28 | pub status: VMClosureStatus, 29 | pub constant_pool_ptr: NonNull>, 30 | pub stack_values: Vec, 31 | } 32 | 33 | macro_rules! new_stack_value_method_impl { 34 | ($name:ident,$data_type:ty,$alias_type:ident) => { 35 | pub fn $name(&mut self, data:$data_type) -> NSValue{ 36 | let b = Box::new(data); 37 | let ptr = Box::leak(b).into(); 38 | let v = NSValue::$alias_type(ptr); 39 | self.stack_values.push(v); 40 | v 41 | } 42 | }; 43 | } 44 | 45 | impl VMClosure { 46 | new_stack_value_method_impl!(new_closure,VMClosure,Closure); 47 | new_stack_value_method_impl!(new_string,String,String); 48 | new_stack_value_method_impl!(new_opaque,Vec,Opaque); 49 | new_stack_value_method_impl!(new_vec,Vec,Vector); 50 | new_stack_value_method_impl!(new_map,BTreeMap,Map); 51 | pub fn clean_stack_values(&mut self){ 52 | use std::alloc::{dealloc, Layout}; 53 | use std::ptr; 54 | for v in &mut self.stack_values{ 55 | unsafe{ 56 | match v { 57 | NSValue::Closure(c) => { 58 | ptr::drop_in_place(c.as_ptr()); 59 | dealloc(c.as_ptr() as *mut u8,Layout::new::()); 60 | } 61 | NSValue::String(s) => { 62 | ptr::drop_in_place(s.as_ptr()); 63 | dealloc(s.as_ptr() as *mut u8,Layout::new::()); 64 | } 65 | NSValue::Opaque(o) => { 66 | ptr::drop_in_place(o.as_ptr()); 67 | dealloc(o.as_ptr() as *mut u8,Layout::new::>()); 68 | } 69 | NSValue::Vector(v) => { 70 | ptr::drop_in_place(v.as_ptr()); 71 | dealloc(v.as_ptr() as *mut u8,Layout::new::>()); 72 | } 73 | NSValue::Map(m)=> { 74 | ptr::drop_in_place(m.as_ptr()); 75 | dealloc(m.as_ptr() as *mut u8,Layout::new::>()); 76 | } 77 | } 78 | } 79 | } 80 | } 81 | } 82 | 83 | // multiple instance sharing a same VMState? go on, tell me the bugs 84 | pub struct VMState { 85 | // register protection mode: once calling new function, 86 | // all old registers is saved in heap 87 | 88 | // when calling a function all the register is saved in heap 89 | // and the last one is last function 90 | // the first one should always be the main function 91 | // when current function returns, 92 | // pops the last element(registers) and copy them into the RegisterPool(normally on stack) 93 | // the return value of the function also( 94 | pub function_call_chain_states: Vec, 95 | // when resume a function the heap registers will be copied into stack(depends on size) 96 | pub current_function_call_state: VMClosure, 97 | // after throwing an exception and in that scope there is no exception handler 98 | // in that case the exception will throw to super function call 99 | // for saving the exception status adding the closure into the exception_stack 100 | // when the exception is finally handled the exception stack is renewed 101 | pub exception_stack: Vec, 102 | 103 | pub args: Vec, 104 | pub nargs: BTreeMap, 105 | 106 | pub return_value: Option, 107 | pub return_values: Vec, 108 | 109 | pub constant_pools: Vec>, 110 | 111 | // enable debug mode will able to see the bytecode executed 112 | pub debug_mode: bool, 113 | // enable profile mode will display the memory usage and gc status 114 | pub profile_mode: bool, 115 | 116 | // in runtime add break point(pc) or removing a break point in current function 117 | pub break_points: Vec, 118 | 119 | pub gc: Box, 120 | } 121 | 122 | impl VMState { 123 | // if the function loaded the module then return true 124 | // if the function is just doing some other work just return false 125 | fn module_load_hook(function: fn() -> bool) -> bool { 126 | false 127 | } 128 | fn load_module() {} 129 | // normally use in start up 130 | fn run_module() {} 131 | } 132 | -------------------------------------------------------------------------------- /src/binary/constant.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | function::Function, 3 | io::{BinaryRW, Reader, Writer}, 4 | }; 5 | use crate::gen_test_reader_writer_for_type; 6 | use super::tags::*; 7 | // type tag + data 8 | pub union ConstantValue{ 9 | u_8:u8, 10 | i_8:i8, 11 | u_16:u16, 12 | i_16:i16, 13 | u_32:u32, 14 | i_32:i32, 15 | u_64:u64, 16 | i_64:i64, 17 | f_32:f32, 18 | f_64:f64, 19 | 20 | ref_type: u16, 21 | symbol: Vec, 22 | string: Vec, 23 | } 24 | #[derive(Copy, PartialEq)] 25 | pub struct Constant { 26 | pub tag: u8, 27 | pub value: ConstantValue 28 | } 29 | 30 | impl BinaryRW for Constant { 31 | fn read(reader: &mut Reader) -> Self { 32 | let tag = reader.read_u8(); 33 | let value = match tag { 34 | _ if TypeTags::String as u8 == tag => Constant::String(reader.read_string()), 35 | 36 | _ if U8Type as u8 == tag => Constant::U8(reader.read_u8()), 37 | _ if I8Type as u8 == tag => Constant::I8(reader.read_i8()), 38 | _ if U16Type as u8 == tag => Constant::U16(reader.read_u16()), 39 | _ if I16Type as u8 == tag => Constant::I16(reader.read_i16()), 40 | _ if U32Type as u8 == tag => Constant::U32(reader.read_u32()), 41 | _ if I32Type as u8 == tag => Constant::I32(reader.read_i32()), 42 | _ if U64Type as u8 == tag => Constant::U64(reader.read_u64()), 43 | _ if I64Type as u8 == tag => Constant::I64(reader.read_i64()), 44 | _ if F32Type as u8 == tag => Constant::F32(reader.read_f32()), 45 | _ if F64Type as u8 == tag => Constant::F64(reader.read_f64()), 46 | 47 | _ if TypeTags::Function as u8 == tag => Constant::Function(Function::read(reader)), 48 | _ => unimplemented!(), 49 | }; 50 | Constant{ 51 | tag, 52 | value 53 | } 54 | } 55 | 56 | fn write(&self, writer: &mut Writer) { 57 | match self { 58 | Constant::String(v) => { 59 | writer.write_u8(TypeTags::String as u8); 60 | writer.write_string(v.clone()); 61 | } 62 | Constant::Map(v) => { 63 | writer.write_u8(TypeTags::Map as u8); 64 | writer.write_map(v.clone(), |write, (k, v): (String, Constant)| { 65 | write.write_string(k.clone()); 66 | v.write(write); 67 | }); 68 | } 69 | Constant::U8(v) => { 70 | writer.write_u8(TypeTags::U8 as u8); 71 | writer.write_u8(*v); 72 | } 73 | Constant::I8(v) => { 74 | writer.write_u8(TypeTags::I8 as u8); 75 | writer.write_u8(*v as u8); 76 | } 77 | Constant::U16(v) => { 78 | writer.write_u8(TypeTags::U16 as u8); 79 | writer.write_u16(*v as u16); 80 | } 81 | Constant::I16(v) => { 82 | writer.write_u8(TypeTags::I16 as u8); 83 | writer.write_u16(*v as u16); 84 | } 85 | Constant::U32(v) => { 86 | writer.write_u8(TypeTags::U32 as u8); 87 | writer.write_u32(*v as u32); 88 | } 89 | Constant::I32(v) => { 90 | writer.write_u8(TypeTags::I32 as u8); 91 | writer.write_u32(*v as u32); 92 | } 93 | Constant::U64(v) => { 94 | writer.write_u8(TypeTags::U64 as u8); 95 | writer.write_u64(*v as u64); 96 | } 97 | Constant::I64(v) => { 98 | writer.write_u8(TypeTags::I64 as u8); 99 | writer.write_u64(*v as u64); 100 | } 101 | Constant::F32(v) => { 102 | writer.write_u8(TypeTags::F32 as u8); 103 | writer.write_f32(*v); 104 | } 105 | Constant::F64(v) => { 106 | writer.write_u8(TypeTags::F64 as u8); 107 | writer.write_f64(*v); 108 | } 109 | Constant::Vector(v) => { 110 | writer.write_u8(TypeTags::Vector as u8); 111 | writer.write_vec(v.clone(), |writer, v| v.write(writer)); 112 | } 113 | Constant::Function(v) => { 114 | writer.write_u8(TypeTags::Function as u8); 115 | v.write(writer); 116 | } 117 | Constant::Opaque(v) => { 118 | writer.write_u8(TypeTags::Opaque as u8); 119 | writer.write_vec(v.clone(), |r, v| r.write_u8(v)); 120 | } 121 | } 122 | } 123 | 124 | // #[cfg(mock)] 125 | fn mock_data() -> Vec> { 126 | use crate::binary::io::*; 127 | use rand::*; 128 | vec![ 129 | Box::new(Constant::String(mock_string())), 130 | Box::new(Constant::U8(random())), 131 | Box::new(Constant::I8(random())), 132 | Box::new(Constant::U16(random())), 133 | Box::new(Constant::I16(random())), 134 | Box::new(Constant::U32(random())), 135 | Box::new(Constant::I32(random())), 136 | Box::new(Constant::U64(random())), 137 | Box::new(Constant::I64(random())), 138 | Box::new(Constant::F32(random())), 139 | Box::new(Constant::F64(random())), 140 | Box::new(Constant::Map(mock_object(&|| mock_string(), &|| { 141 | Constant::U8(random()) 142 | }))), 143 | Box::new(Constant::Function((&*Function::mock_data()[0]).clone())), 144 | Box::new(Constant::Vector(vec![ 145 | Constant::U8(random()), 146 | Constant::U64(random()), 147 | Constant::Map(mock_object(&|| mock_string(), &|| Constant::U8(random()))), 148 | Constant::Function((&*Function::mock_data()[0]).clone()), 149 | ])), 150 | ] 151 | } 152 | } 153 | gen_test_reader_writer_for_type!(test_rw_mock_Constant, Constant); 154 | -------------------------------------------------------------------------------- /src/binary/function.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Function is just a thing storage 3 | in constant pool, is not the function 4 | actually runs in vm, that is called closure 5 | */ 6 | 7 | use super::constant::*; 8 | use super::{ 9 | debug::*, 10 | io::{BinaryRW, Reader, Writer}, 11 | }; 12 | use crate::gen_test_reader_writer_for_type; 13 | use std::collections::BTreeMap; 14 | 15 | #[repr(u8)] 16 | #[derive(Debug, Clone, PartialEq)] 17 | pub enum FunctionType { 18 | Function = 0x00, 19 | // currently disabled 20 | Generator, 21 | // currently disabled 22 | AsyncFunction, 23 | // currently disabled 24 | AsyncGenerator, 25 | } 26 | 27 | impl BinaryRW for FunctionType { 28 | fn read(reader: &mut Reader) -> Self { 29 | let tag = reader.read_u8(); 30 | match tag { 31 | t if tag == FunctionType::Function as u8 => FunctionType::Function, 32 | _ => unimplemented!(), 33 | } 34 | } 35 | fn write(&self, writer: &mut super::io::Writer) { 36 | writer.write_u8(self.clone() as u8); 37 | } 38 | // #[cfg(mock)] 39 | fn mock_data() -> Vec> { 40 | use rand::*; 41 | let mut ret = vec![]; 42 | for _ in 0..10 { 43 | //TODO: when all implemented change that 44 | ret.push(Box::new(FunctionType::Function)); 45 | } 46 | ret 47 | } 48 | } 49 | 50 | gen_test_reader_writer_for_type!(test_rw_mock_FunctionType, FunctionType); 51 | 52 | // if pc in range from to pc and state is 53 | // error then use jump to handler pc 54 | #[derive(Debug, Clone, PartialEq)] 55 | pub struct Exception { 56 | pub start_pc: u16, 57 | pub end_pc: u16, 58 | pub handler_pc: u16, 59 | } 60 | 61 | impl BinaryRW for Exception { 62 | fn read(reader: &mut Reader) -> Self { 63 | let start_pc = reader.read_u16(); 64 | let end_pc = reader.read_u16(); 65 | let handler_pc = reader.read_u16(); 66 | Exception { 67 | start_pc, 68 | end_pc, 69 | handler_pc, 70 | } 71 | } 72 | fn write(&self, writer: &mut super::io::Writer) { 73 | writer.write_u16(self.start_pc); 74 | writer.write_u16(self.end_pc); 75 | writer.write_u16(self.handler_pc); 76 | } 77 | 78 | // #[cfg(mock)] 79 | fn mock_data() -> Vec> { 80 | use rand::*; 81 | let mut ret = vec![]; 82 | for _ in 0..10 { 83 | ret.push(Box::new(Exception { 84 | start_pc: random(), 85 | end_pc: random(), 86 | handler_pc: random(), 87 | })); 88 | } 89 | ret 90 | } 91 | } 92 | 93 | gen_test_reader_writer_for_type!(test_rw_mock_Exception, Exception); 94 | 95 | #[derive(Debug, Clone, PartialEq)] 96 | pub struct ExceptionTable { 97 | pub table: Vec, 98 | } 99 | 100 | impl BinaryRW for ExceptionTable { 101 | fn read(reader: &mut Reader) -> Self { 102 | let table = reader.read_vec(|reader| Exception::read(reader)); 103 | ExceptionTable { table } 104 | } 105 | fn write(&self, writer: &mut super::io::Writer) { 106 | writer.write_vec(self.table.clone(), |writer, o| Exception::write(&o, writer)); 107 | } 108 | // #[cfg(mock)] 109 | fn mock_data() -> Vec> { 110 | use rand::*; 111 | let mut ret = vec![]; 112 | for _ in 0..10 { 113 | ret.push(Box::new(ExceptionTable { 114 | table: Exception::mock_data() 115 | .iter() 116 | .map(|d| (&**d).clone()) 117 | .collect(), 118 | })); 119 | } 120 | ret 121 | } 122 | } 123 | 124 | gen_test_reader_writer_for_type!(test_rw_mock_ExceptionTable, ExceptionTable); 125 | 126 | #[derive(Debug, Clone, PartialEq)] 127 | pub struct Function { 128 | //TODO: prob add an option name 129 | pub is_multi_return_function: bool, 130 | pub function_type: FunctionType, 131 | // for example 132 | // args count is 3 f(a,b,c) will automatically use 4 register 133 | // the forth one is vargs 134 | pub args_count: u8, 135 | pub max_registers: u16, 136 | pub code: Vec, 137 | 138 | pub exception_table: Option, 139 | pub debug_info: Option, 140 | } 141 | 142 | impl BinaryRW for Function { 143 | fn read(reader: &mut Reader) -> Self { 144 | let is_multi_return_function = reader.read_u8() != 0x00; 145 | let function_type = FunctionType::read(reader); 146 | let args_count = reader.read_u8(); 147 | let max_registers = reader.read_u16(); 148 | let code = reader.read_vec(|reader| reader.read_u64()); 149 | let exception_table = reader.read_option(|reader| ExceptionTable::read(reader)); 150 | let debug_info = reader.read_option(|reader| DebugInfo::read(reader)); 151 | Function { 152 | is_multi_return_function, 153 | function_type, 154 | args_count, 155 | max_registers, 156 | code, 157 | exception_table, 158 | debug_info, 159 | } 160 | } 161 | fn write(&self, writer: &mut super::io::Writer) { 162 | writer.write_u8(if self.is_multi_return_function { 163 | 0xFF 164 | } else { 165 | 0x00 166 | }); 167 | FunctionType::write(&self.function_type, writer); 168 | writer.write_u8(self.args_count); 169 | writer.write_u16(self.max_registers); 170 | writer.write_vec(self.code.clone(), |writer, v| writer.write_u64(v)); 171 | writer.write_option(self.exception_table.clone(), |writer, o| { 172 | ExceptionTable::write(&o, writer) 173 | }); 174 | writer.write_option(self.debug_info.clone(), |writer, o| { 175 | DebugInfo::write(&o, writer) 176 | }); 177 | } 178 | 179 | // #[cfg(mock)] 180 | fn mock_data() -> Vec> { 181 | use rand::*; 182 | let mut ret = vec![]; 183 | for _ in 0..10 { 184 | let mut vecu64 = vec![]; 185 | for i in 0u8..random() { 186 | vecu64.push(random()); 187 | } 188 | let is_multi_return_function = random(); 189 | let function_type = (&*FunctionType::mock_data()[0]).clone(); 190 | let args_count = random(); 191 | let max_registers = random(); 192 | let code = vecu64; 193 | let exception_table = None; 194 | let debug_info = if random() { 195 | Some((&*DebugInfo::mock_data()[0]).clone()) 196 | } else { 197 | None 198 | }; 199 | ret.push(Box::new(Function { 200 | is_multi_return_function, 201 | function_type, 202 | args_count, 203 | max_registers, 204 | code, 205 | exception_table, 206 | debug_info, 207 | })); 208 | } 209 | ret 210 | } 211 | } 212 | 213 | gen_test_reader_writer_for_type!(test_rw_mock_Function, Function); 214 | -------------------------------------------------------------------------------- /src/binary/io.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | use std::collections::BTreeMap; 3 | 4 | pub struct Reader { 5 | data: *const u8, 6 | pos: usize, 7 | } 8 | 9 | pub struct Writer { 10 | pub data: Vec, 11 | } 12 | 13 | pub trait BinaryRW { 14 | fn read(reader: &mut Reader) -> Self; 15 | fn write(&self, writer: &mut Writer); 16 | 17 | // #[cfg(mock)] 18 | fn mock_data() -> Vec>; 19 | } 20 | 21 | // #[cfg(mock)] 22 | pub fn mock_string() -> String { 23 | use rand::*; 24 | let mut ret: String = String::new(); 25 | for i in 0..10 { 26 | ret.push('草'); 27 | } 28 | ret 29 | } 30 | 31 | #[macro_export] 32 | macro_rules! gen_test_reader_writer_for_type { 33 | ($f:ident,$t:ident) => { 34 | #[test] 35 | fn $f() { 36 | let data = $t::mock_data(); 37 | for d in data { 38 | let mut writer = Writer::new(); 39 | d.write(&mut writer); 40 | let raw_data = writer.data.as_mut_ptr(); 41 | let mut reader = Reader::new(raw_data); 42 | let read = $t::read(&mut reader); 43 | assert_eq!(*d, read) 44 | } 45 | } 46 | }; 47 | } 48 | 49 | // #[cfg(mock)] 50 | pub fn mock_object(kf: &dyn Fn() -> K, vf: &dyn Fn() -> V) -> BTreeMap { 51 | use rand::*; 52 | let mut ret: BTreeMap = BTreeMap::new(); 53 | for i in 0..10 { 54 | ret.insert(kf(), vf()); 55 | } 56 | ret 57 | } 58 | 59 | impl Reader { 60 | pub fn new(data: *const u8) -> Reader { 61 | Reader { data, pos: 0 } 62 | } 63 | 64 | pub fn read_u8(&mut self) -> u8 { 65 | unsafe { 66 | let b = *self.data.add(self.pos); 67 | self.pos += 1; 68 | b 69 | } 70 | } 71 | pub fn read_u16(&mut self) -> u16 { 72 | unsafe { 73 | let b = *(self.data.add(self.pos) as *const u16); 74 | self.pos += 2; 75 | b 76 | } 77 | } 78 | pub fn read_u32(&mut self) -> u32 { 79 | unsafe { 80 | let b = *(self.data.add(self.pos) as *const u32); 81 | self.pos += 4; 82 | b 83 | } 84 | } 85 | pub fn read_u64(&mut self) -> u64 { 86 | unsafe { 87 | let b = *(self.data.add(self.pos) as *const u64); 88 | self.pos += 8; 89 | b 90 | } 91 | } 92 | 93 | pub fn read_i8(&mut self) -> i8 { 94 | unsafe { 95 | let b = *self.data.add(self.pos); 96 | self.pos += 1; 97 | b as i8 98 | } 99 | } 100 | pub fn read_i16(&mut self) -> i16 { 101 | unsafe { 102 | let b = *(self.data.add(self.pos) as *const u16); 103 | self.pos += 2; 104 | b as i16 105 | } 106 | } 107 | pub fn read_i32(&mut self) -> i32 { 108 | unsafe { 109 | let b = *(self.data.add(self.pos) as *const u32); 110 | self.pos += 4; 111 | b as i32 112 | } 113 | } 114 | pub fn read_i64(&mut self) -> i64 { 115 | unsafe { 116 | let b = *(self.data.add(self.pos) as *const u64); 117 | self.pos += 8; 118 | b as i64 119 | } 120 | } 121 | 122 | pub fn read_f32(&mut self) -> f32 { 123 | unsafe { 124 | let i = *(self.data.add(self.pos) as *const u32); 125 | self.pos += 4; 126 | let bt = [i as u8, (i >> 8) as u8, (i >> 16) as u8, (i >> 24) as u8]; 127 | f32::from_be_bytes(bt) 128 | } 129 | } 130 | pub fn read_f64(&mut self) -> f64 { 131 | unsafe { 132 | let i = *(self.data.add(self.pos) as *const u64); 133 | self.pos += 8; 134 | let bt = [ 135 | i as u8, 136 | (i >> 8) as u8, 137 | (i >> 16) as u8, 138 | (i >> 24) as u8, 139 | (i >> 32) as u8, 140 | (i >> 40) as u8, 141 | (i >> 48) as u8, 142 | (i >> 56) as u8, 143 | ]; 144 | f64::from_be_bytes(bt) 145 | } 146 | } 147 | 148 | pub fn read_string(&mut self) -> String { 149 | let vec = self.read_vec(|reader| reader.read_u8()); 150 | String::from_utf8(vec).unwrap() 151 | } 152 | 153 | pub fn read_vec(&mut self, f: F) -> Vec 154 | where 155 | F: Fn(&mut Reader) -> T, 156 | { 157 | let n = self.read_u16() as usize; 158 | let mut vec = Vec::with_capacity(n); 159 | for _i in 0..n { 160 | vec.push(f(self)); 161 | } 162 | vec 163 | } 164 | pub fn read_map(&mut self, f: F) -> BTreeMap 165 | where 166 | F: Fn(&mut Reader) -> (K, V), 167 | K: Ord, 168 | { 169 | let n = self.read_u16() as usize; 170 | let mut map = BTreeMap::new(); 171 | for _i in 0..n { 172 | let (k, v) = f(self); 173 | map.insert(k, v); 174 | } 175 | map 176 | } 177 | pub fn read_option(&mut self, f: F) -> Option 178 | where 179 | F: Fn(&mut Reader) -> T, 180 | { 181 | let flag = self.read_u8(); 182 | if flag == 0x00 { 183 | None 184 | } else { 185 | Some(f(self)) 186 | } 187 | } 188 | } 189 | 190 | impl Writer { 191 | pub fn new() -> Self { 192 | Writer { data: Vec::new() } 193 | } 194 | 195 | pub fn write_u8(&mut self, i: u8) { 196 | self.data.push(i); 197 | } 198 | 199 | pub fn write_u16(&mut self, i: u16) { 200 | self.data.append(&mut vec![i as u8, (i >> 8) as u8]); 201 | } 202 | 203 | pub fn write_u32(&mut self, i: u32) { 204 | self.data.append(&mut vec![ 205 | i as u8, 206 | (i >> 8) as u8, 207 | (i >> 16) as u8, 208 | (i >> 24) as u8, 209 | ]); 210 | } 211 | 212 | pub fn write_u64(&mut self, i: u64) { 213 | self.data.append(&mut vec![ 214 | i as u8, 215 | (i >> 8) as u8, 216 | (i >> 16) as u8, 217 | (i >> 24) as u8, 218 | (i >> 32) as u8, 219 | (i >> 40) as u8, 220 | (i >> 48) as u8, 221 | (i >> 56) as u8, 222 | ]); 223 | } 224 | 225 | pub fn write_f32(&mut self, i: f32) { 226 | let d = i.to_be_bytes(); 227 | self.data.append(&mut d.into()); 228 | } 229 | 230 | pub fn write_f64(&mut self, i: f64) { 231 | let d = i.to_be_bytes(); 232 | self.data.append(&mut d.into()); 233 | } 234 | 235 | pub fn write_string(&mut self, i: String) { 236 | let bytes = i.as_bytes(); 237 | self.write_u16(bytes.len() as u16); 238 | for b in bytes { 239 | self.write_u8(*b); 240 | } 241 | } 242 | 243 | pub fn write_vec(&mut self, inp: Vec, f: F) 244 | where 245 | T: Clone, 246 | F: Fn(&mut Self, T), 247 | { 248 | self.write_u16(inp.len() as u16); 249 | for i in inp { 250 | f(self, i.clone()); 251 | } 252 | } 253 | 254 | pub fn write_map(&mut self, m: BTreeMap, f: F) 255 | where 256 | K: Clone, 257 | V: Clone, 258 | K: Ord, 259 | F: Fn(&mut Self, (K, V)), 260 | { 261 | self.write_u16(m.len() as u16); 262 | for i in m { 263 | f(self, (i.0.clone(), i.1.clone())); 264 | } 265 | } 266 | 267 | pub fn write_option(&mut self, o: Option, f: F) 268 | where 269 | F: Fn(&mut Self, T), 270 | { 271 | match o { 272 | Some(x) => { 273 | self.write_u8(0x01); 274 | f(self, x); 275 | } 276 | _ => self.write_u8(0x00), 277 | }; 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/binary/debug.rs: -------------------------------------------------------------------------------- 1 | use super::io::{BinaryRW, Reader, Writer}; 2 | use crate::gen_test_reader_writer_for_type; 3 | 4 | #[derive(Debug, Clone, PartialEq)] 5 | pub struct DebugPrecompiledLineNumber { 6 | start_pc: u16, 7 | end_pc: u16, 8 | precompiled_line_number: u16, 9 | } 10 | impl BinaryRW for DebugPrecompiledLineNumber { 11 | fn read(reader: &mut Reader) -> Self { 12 | let start_pc = reader.read_u16(); 13 | let end_pc = reader.read_u16(); 14 | let precompiled_line_number = reader.read_u16(); 15 | DebugPrecompiledLineNumber { 16 | start_pc, 17 | end_pc, 18 | precompiled_line_number, 19 | } 20 | } 21 | fn write(&self, writer: &mut Writer) { 22 | writer.write_u16(self.start_pc); 23 | writer.write_u16(self.end_pc); 24 | writer.write_u16(self.precompiled_line_number); 25 | } 26 | // #[cfg(mock)] 27 | fn mock_data() -> Vec> { 28 | use rand::*; 29 | let mut ret = vec![]; 30 | for _ in 0..10 { 31 | ret.push(Box::new(DebugPrecompiledLineNumber { 32 | start_pc: random(), 33 | end_pc: random(), 34 | precompiled_line_number: random(), 35 | })); 36 | } 37 | ret 38 | } 39 | } 40 | gen_test_reader_writer_for_type!( 41 | test_rw_mock_DebugPrecompiledLineNumber, 42 | DebugPrecompiledLineNumber 43 | ); 44 | 45 | #[derive(Debug, Clone, PartialEq)] 46 | pub struct DebugPrecompiledLineNumberTable { 47 | table: Vec, 48 | } 49 | 50 | impl BinaryRW for DebugPrecompiledLineNumberTable { 51 | fn read(reader: &mut Reader) -> Self { 52 | let table = reader.read_vec(|reader| DebugPrecompiledLineNumber::read(reader)); 53 | DebugPrecompiledLineNumberTable { table } 54 | } 55 | 56 | fn write(&self, writer: &mut Writer) { 57 | writer.write_vec(self.table.clone(), |writer, i| i.write(writer)) 58 | } 59 | 60 | // #[cfg(mock)] 61 | fn mock_data() -> Vec> { 62 | use rand::*; 63 | let mut ret = vec![]; 64 | for _ in 0..10 { 65 | ret.push(Box::new(DebugPrecompiledLineNumberTable { 66 | table: DebugPrecompiledLineNumber::mock_data() 67 | .iter() 68 | .map(|d| (&**d).clone()) 69 | .collect(), 70 | })); 71 | } 72 | ret 73 | } 74 | } 75 | gen_test_reader_writer_for_type!( 76 | test_rw_mock_DebugPrecompiledLineNumberTable, 77 | DebugPrecompiledLineNumberTable 78 | ); 79 | // such as your code is compiled to bytecode 80 | // JPE 0x000000 // if xxx == true 81 | #[derive(Debug, Clone, PartialEq)] 82 | pub struct DebugCompiledByteCodeComment { 83 | start_pc: u16, 84 | end_pc: u16, 85 | comment: u16, 86 | } 87 | 88 | impl BinaryRW for DebugCompiledByteCodeComment { 89 | fn read(reader: &mut Reader) -> Self { 90 | let start_pc = reader.read_u16(); 91 | let end_pc = reader.read_u16(); 92 | let comment = reader.read_u16(); 93 | DebugCompiledByteCodeComment { 94 | start_pc, 95 | end_pc, 96 | comment, 97 | } 98 | } 99 | fn write(&self, writer: &mut Writer) { 100 | writer.write_u16(self.start_pc); 101 | writer.write_u16(self.end_pc); 102 | writer.write_u16(self.comment); 103 | } 104 | // #[cfg(mock)] 105 | fn mock_data() -> Vec> { 106 | use rand::*; 107 | let mut ret = vec![]; 108 | for _ in 0..10 { 109 | ret.push(Box::new(DebugCompiledByteCodeComment { 110 | start_pc: random(), 111 | end_pc: random(), 112 | comment: random(), 113 | })); 114 | } 115 | ret 116 | } 117 | } 118 | 119 | gen_test_reader_writer_for_type!( 120 | test_rw_mock_DebugCompiledByteCodeComment, 121 | DebugCompiledByteCodeComment 122 | ); 123 | 124 | #[derive(Debug, Clone, PartialEq)] 125 | pub struct DebugCompiledByteCodeCommentTable { 126 | table: Vec, 127 | } 128 | 129 | impl BinaryRW for DebugCompiledByteCodeCommentTable { 130 | fn read(reader: &mut Reader) -> Self { 131 | let table = reader.read_vec(|reader| DebugCompiledByteCodeComment::read(reader)); 132 | DebugCompiledByteCodeCommentTable { table } 133 | } 134 | fn write(&self, writer: &mut Writer) { 135 | writer.write_vec(self.table.clone(), |writer, i| i.write(writer)) 136 | } 137 | // #[cfg(mock)] 138 | fn mock_data() -> Vec> { 139 | use rand::*; 140 | let mut ret = vec![]; 141 | for _ in 0..10 { 142 | ret.push(Box::new(DebugCompiledByteCodeCommentTable { 143 | table: DebugCompiledByteCodeComment::mock_data() 144 | .iter() 145 | .map(|d| (&**d).clone()) 146 | .collect(), 147 | })); 148 | } 149 | ret 150 | } 151 | } 152 | gen_test_reader_writer_for_type!( 153 | test_rw_mock_DebugCompiledByteCodeCommentTable, 154 | DebugCompiledByteCodeCommentTable 155 | ); 156 | 157 | #[derive(Debug, Clone, PartialEq)] 158 | pub struct DebugVariable { 159 | pub name: u16, 160 | pub start_pc: u16, 161 | pub end_pc: u16, 162 | pub register: u16, 163 | } 164 | impl BinaryRW for DebugVariable { 165 | fn read(reader: &mut Reader) -> Self { 166 | let name = reader.read_u16(); 167 | let start_pc = reader.read_u16(); 168 | let end_pc = reader.read_u16(); 169 | let register = reader.read_u16(); 170 | DebugVariable { 171 | name, 172 | start_pc, 173 | end_pc, 174 | register, 175 | } 176 | } 177 | fn write(&self, writer: &mut Writer) { 178 | writer.write_u16(self.name); 179 | writer.write_u16(self.start_pc); 180 | writer.write_u16(self.end_pc); 181 | writer.write_u16(self.register); 182 | } 183 | // #[cfg(mock)] 184 | fn mock_data() -> Vec> { 185 | use rand::*; 186 | let mut ret = vec![]; 187 | for _ in 0..10 { 188 | ret.push(Box::new(DebugVariable { 189 | name: random(), 190 | start_pc: random(), 191 | end_pc: random(), 192 | register: random(), 193 | })); 194 | } 195 | ret 196 | } 197 | } 198 | gen_test_reader_writer_for_type!(test_rw_mock_DebugVariable, DebugVariable); 199 | // break points: dynamically adding break points 200 | pub struct DebugBreakPointTable { 201 | pub table: Vec, 202 | } 203 | 204 | #[derive(Debug, Clone, PartialEq)] 205 | pub struct DebugVariableTable { 206 | pub table: Vec, 207 | } 208 | 209 | impl BinaryRW for DebugVariableTable { 210 | fn read(reader: &mut Reader) -> Self { 211 | let table = reader.read_vec(|reader| DebugVariable::read(reader)); 212 | DebugVariableTable { table } 213 | } 214 | fn write(&self, writer: &mut Writer) { 215 | writer.write_vec(self.table.clone(), |writer, i| i.write(writer)) 216 | } 217 | // #[cfg(mock)] 218 | fn mock_data() -> Vec> { 219 | use rand::*; 220 | let mut ret = vec![]; 221 | for _ in 0..10 { 222 | ret.push(Box::new(DebugVariableTable { 223 | table: DebugVariable::mock_data() 224 | .iter() 225 | .map(|d| (&**d).clone()) 226 | .collect(), 227 | })); 228 | } 229 | ret 230 | } 231 | } 232 | gen_test_reader_writer_for_type!(test_rw_mock_DebugVariableTable, DebugVariableTable); 233 | 234 | #[derive(Debug, Clone, PartialEq)] 235 | pub struct DebugSourceInfo { 236 | // string source of original programming language 237 | source: u16, 238 | source_file_name: u16, 239 | } 240 | 241 | impl BinaryRW for DebugSourceInfo { 242 | fn read(reader: &mut Reader) -> Self { 243 | let source = reader.read_u16(); 244 | let source_file_name = reader.read_u16(); 245 | DebugSourceInfo { 246 | source, 247 | source_file_name, 248 | } 249 | } 250 | fn write(&self, writer: &mut Writer) { 251 | writer.write_u16(self.source); 252 | writer.write_u16(self.source_file_name); 253 | } 254 | // #[cfg(mock)] 255 | fn mock_data() -> Vec> { 256 | use rand::*; 257 | let mut ret = vec![]; 258 | for _ in 0..10 { 259 | ret.push(Box::new(DebugSourceInfo { 260 | source: random(), 261 | source_file_name: random(), 262 | })); 263 | } 264 | ret 265 | } 266 | } 267 | 268 | gen_test_reader_writer_for_type!(test_rw_mock_DebugSourceInfo, DebugSourceInfo); 269 | 270 | #[derive(Debug, Clone, PartialEq)] 271 | pub struct DebugInfo { 272 | source_info: Option, 273 | variable_table: Option, 274 | precompiled_line_number_table: Option, 275 | comment_table: Option, 276 | } 277 | 278 | impl BinaryRW for DebugInfo { 279 | fn read(reader: &mut Reader) -> Self { 280 | let source_info = reader.read_option(|reader| DebugSourceInfo::read(reader)); 281 | let variable_table = reader.read_option(|reader| DebugVariableTable::read(reader)); 282 | let precompiled_line_number_table = 283 | reader.read_option(|reader| DebugPrecompiledLineNumberTable::read(reader)); 284 | let comment_table = 285 | reader.read_option(|reader| DebugCompiledByteCodeCommentTable::read(reader)); 286 | DebugInfo { 287 | source_info, 288 | variable_table, 289 | precompiled_line_number_table, 290 | comment_table, 291 | } 292 | } 293 | fn write(&self, writer: &mut Writer) { 294 | writer.write_option(self.source_info.clone(), |writer, o| o.write(writer)); 295 | writer.write_option(self.variable_table.clone(), |writer, o| o.write(writer)); 296 | writer.write_option(self.precompiled_line_number_table.clone(), |writer, o| { 297 | o.write(writer) 298 | }); 299 | writer.write_option(self.comment_table.clone(), |writer, o| o.write(writer)); 300 | } 301 | // #[cfg(mock)] 302 | fn mock_data() -> Vec> { 303 | use rand::*; 304 | let mut ret = vec![]; 305 | for _ in 0..10 { 306 | let source_info = if random() { 307 | Some((&*DebugSourceInfo::mock_data()[0]).clone()) 308 | } else { 309 | None 310 | }; 311 | let variable_table = if random() { 312 | Some((&*DebugVariableTable::mock_data()[0]).clone()) 313 | } else { 314 | None 315 | }; 316 | let precompiled_line_number_table = if random() { 317 | Some((&*DebugPrecompiledLineNumberTable::mock_data()[0]).clone()) 318 | } else { 319 | None 320 | }; 321 | let comment_table = if random() { 322 | Some((&*DebugCompiledByteCodeCommentTable::mock_data()[0]).clone()) 323 | } else { 324 | None 325 | }; 326 | ret.push(Box::new(DebugInfo { 327 | source_info, 328 | variable_table, 329 | precompiled_line_number_table, 330 | comment_table, 331 | })); 332 | } 333 | ret 334 | } 335 | } 336 | gen_test_reader_writer_for_type!(test_rw_mock_DebugInfo, DebugInfo); 337 | -------------------------------------------------------------------------------- /src/vm/interpreter.rs: -------------------------------------------------------------------------------- 1 | use super::register; 2 | use crate::config::*; 3 | 4 | use super::{ 5 | value::{NSValue, Value}, 6 | VMClosureStatus, VMState, 7 | }; 8 | use crate::{ 9 | binary::{constant::Constant, function::Function, opcode::OpCode}, 10 | config::*, 11 | }; 12 | use std::panic; 13 | use std::{collections::BTreeMap, ptr::NonNull}; 14 | 15 | macro_rules! expr { 16 | ($e:expr) => { 17 | $e 18 | }; 19 | } 20 | macro_rules! TRI_INS_X { 21 | ($regs:ident,$e1:ident,$e2:ident,$e3:ident,$t:ident,$t2:ident,$vc1:ident,$op:tt) => { 22 | let v1 = match $regs[$e1 as usize]{ 23 | Value::U8(v) => {v as $t}, 24 | Value::I8(v) => {v as $t}, 25 | Value::U16(v) => {v as $t}, 26 | Value::I16(v) => {v as $t}, 27 | Value::U32(v) => {v as $t}, 28 | Value::I32(v) => {v as $t}, 29 | Value::U64(v) => {v as $t}, 30 | Value::I64(v) => {v as $t}, 31 | Value::F32(v) => {v as $t}, 32 | Value::F64(v) => {v as $t}, 33 | _ => {panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES")} 34 | }; 35 | let v2 = match $regs[$e2 as usize]{ 36 | Value::U8(v) => {v as $t}, 37 | Value::I8(v) => {v as $t}, 38 | Value::U16(v) => {v as $t}, 39 | Value::I16(v) => {v as $t}, 40 | Value::U32(v) => {v as $t}, 41 | Value::I32(v) => {v as $t}, 42 | Value::U64(v) => {v as $t}, 43 | Value::I64(v) => {v as $t}, 44 | Value::F32(v) => {v as $t}, 45 | Value::F64(v) => {v as $t}, 46 | _ => {panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES")} 47 | }; 48 | unsafe { 49 | $regs[$e3 as usize] = Value::$vc1( 50 | expr!(v1 $op v2) 51 | ); 52 | } 53 | }; 54 | ($regs:ident,$e1:ident,$e2:ident,$e3:ident,$t:ident,$t2:ident,$vc1:ident,$vc2:ident,$op:ident) => { 55 | let mut sized = false; 56 | let v1 = match $regs[$e1 as usize]{ 57 | Value::U8(v) => {v as $t}, 58 | Value::I8(v) => {sized = true;v as $t}, 59 | Value::U16(v) => {v as $t}, 60 | Value::I16(v) => {sized = true;v as $t}, 61 | Value::U32(v) => {v as $t}, 62 | Value::I32(v) => {sized = true;v as $t}, 63 | Value::U64(v) => {v as $t}, 64 | Value::I64(v) => {sized = true;v as $t}, 65 | Value::F32(v) => {sized = true;v as $t}, 66 | Value::F64(v) => {sized = true;v as $t}, 67 | _ => {panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES")} 68 | }; 69 | let v2 = match $regs[$e2 as usize]{ 70 | Value::U8(v) => {v as $t}, 71 | Value::I8(v) => {sized = true;v as $t}, 72 | Value::U16(v) => {v as $t}, 73 | Value::I16(v) => {sized = true;v as $t}, 74 | Value::U32(v) => {v as $t}, 75 | Value::I32(v) => {sized = true;v as $t}, 76 | Value::U64(v) => {v as $t}, 77 | Value::I64(v) => {sized = true;v as $t}, 78 | Value::F32(v) => {sized = true;v as $t}, 79 | Value::F64(v) => {sized = true;v as $t}, 80 | _ => {panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES")} 81 | }; 82 | unsafe { 83 | if sized{ 84 | $regs[$e3 as usize] = Value::$vc1( 85 | (v1 as $t2).$op(v2 as $t2) 86 | ); 87 | }else{ 88 | $regs[$e3 as usize] = Value::$vc2( 89 | (v1).$op(v2) 90 | ); 91 | } 92 | } 93 | }; 94 | } 95 | 96 | #[inline(always)] 97 | fn value_to_bool(value: &Value) -> Option { 98 | match value { 99 | Value::U8(v) => Some(*v != 0), 100 | Value::I8(v) => Some(*v != 0), 101 | Value::U16(v) => Some(*v != 0), 102 | Value::I16(v) => Some(*v != 0), 103 | Value::U32(v) => Some(*v != 0), 104 | Value::I32(v) => Some(*v != 0), 105 | Value::U64(v) => Some(*v != 0), 106 | Value::I64(v) => Some(*v != 0), 107 | Value::F32(v) => Some(*v != 0.0), 108 | Value::F64(v) => Some(*v != 0.0), 109 | Value::Boolean(v) => Some(*v), 110 | _ => None, 111 | } 112 | } 113 | pub fn interpreter(state: &mut VMState) { 114 | // 垃圾rust没GOTO,做个函数调用都她妈费劲 115 | 'main_interpreter: loop { 116 | // init 117 | if state.current_function_call_state.registers.len() > MAX_REGISTER_ON_STACK { 118 | panic!("ERROR! PLATFORM DOES NOT SUPPORT THAT MUCH REGISTER") 119 | } 120 | 121 | // load registers 122 | let mut stack_regs: [Value; MAX_REGISTER_ON_STACK] = [Value::Undef; 64]; 123 | // copy register to stack 124 | for r in 0..state.current_function_call_state.registers.len() { 125 | stack_regs[r] = state.current_function_call_state.registers[r].clone(); 126 | } 127 | let mut pc = state.current_function_call_state.pc; 128 | if pc == 0 && state.args.len() > 0 { 129 | for i in 0..state.current_function_call_state.function_bytecode.args_count as usize { 130 | stack_regs[i] = state.args[i]; 131 | } 132 | // TODO: 多余的看看咋处理 133 | state.args = vec![]; 134 | } 135 | 'fetch_exe: loop { 136 | // on exception 137 | if state.current_function_call_state.status == VMClosureStatus::Error { 138 | let mut find_exception_handle = false; 139 | // reset to error pc 140 | pc -= 1; 141 | if let Some(etable) = &state.current_function_call_state.function_bytecode.exception_table { 142 | let handles = etable 143 | .table 144 | .iter() 145 | .filter(|x| x.start_pc <= pc && x.end_pc > pc) 146 | .next(); 147 | if let Some(handle) = handles { 148 | find_exception_handle = true; 149 | let handler_pc = handle.handler_pc; 150 | pc = handler_pc; 151 | } 152 | } 153 | if !find_exception_handle { 154 | // return to super function stack 155 | // set exception 156 | // save template stack variable to current function state 157 | state.current_function_call_state.registers = stack_regs.to_vec(); 158 | state.current_function_call_state.pc = pc; 159 | state 160 | .exception_stack 161 | // TODO: 看着优化了这个clone 162 | .push(state.current_function_call_state.clone()); 163 | if let Some(cls) = state.function_call_chain_states.pop() { 164 | state.current_function_call_state = cls; 165 | state.current_function_call_state.pc += 1; 166 | state.current_function_call_state.status = VMClosureStatus::Error; 167 | continue 'main_interpreter; 168 | } 169 | // the outer 170 | else { 171 | panic!("VM TERMINATED WITH CALL STACK {:?}", state.exception_stack); 172 | } 173 | } 174 | } 175 | 176 | // on breakpoint 177 | // on whatever 178 | 179 | // on end function scope 180 | if pc >= state.current_function_call_state.function_bytecode.code.len() as u16 { 181 | return; 182 | // TODO: I think that is an exception because a normal function at least has one return value or uses ret to return a void 183 | } 184 | let ci = state.current_function_call_state.function_bytecode.code[pc as usize]; 185 | 186 | // register status 187 | let ins = ci as u16; 188 | let e1 = (ci >> 16) as u16; 189 | let e1x = (ci >> 16) as u32; 190 | let e2 = (ci >> 32) as u16; 191 | let e2x = (ci >> 32) as u32; 192 | let e3 = (ci >> 48) as u16; 193 | // u48 194 | let ed = (ci >> 16) as u64; 195 | // you can ask me why i do it this way 196 | // no silver bullet 197 | match ins { 198 | _ if ins == OpCode::NOP as u16 => {} 199 | 200 | // ===== LOAD ===== 201 | _ if ins == OpCode::LOADK as u16 => { 202 | if e3 == 0xFFFF { 203 | let value = Value::from_idx_pool_ptr( 204 | e2, 205 | state.current_function_call_state.constant_pool_ptr, 206 | state, 207 | ); 208 | stack_regs[e1 as usize] = value; 209 | } 210 | // loadk from other module 211 | else { 212 | // let from_constant_pool = thispool.find e3(string) 213 | // state.pools.find(from_constant_pool) 214 | // do load 215 | unimplemented!() 216 | } 217 | } 218 | _ if ins == OpCode::IMMBOOL as u16 => { 219 | stack_regs[e1 as usize] = Value::Boolean(e2 != 0x00); 220 | } 221 | _ if ins == OpCode::IMMU8 as u16 => { 222 | stack_regs[e1 as usize] = Value::U8(e2 as u8); 223 | } 224 | _ if ins == OpCode::IMMU16 as u16 => { 225 | stack_regs[e1 as usize] = Value::U16(e2); 226 | } 227 | _ if ins == OpCode::IMMU32 as u16 => { 228 | stack_regs[e1 as usize] = Value::U32(e2x); 229 | } 230 | _ if ins == OpCode::IMMU64 as u16 => { 231 | let dp1 = e2x; 232 | pc += 1; 233 | let ci = state.current_function_call_state.function_bytecode.code[pc as usize]; 234 | let ins = ci as u16; 235 | // u48 236 | let ed = (ci << 16) as u64; 237 | if ins != OpCode::EXTRA as u16 { 238 | panic!("ERROR! EXCEPT EXTRA FIND {:02X}", ins); 239 | } else { 240 | let v = ed << 16 + dp1; 241 | stack_regs[e1 as usize] = Value::U64(v); 242 | } 243 | } 244 | 245 | _ if ins == OpCode::IMMI8 as u16 => { 246 | stack_regs[e1 as usize] = Value::I8(e2 as i8); 247 | } 248 | _ if ins == OpCode::IMMI16 as u16 => { 249 | stack_regs[e1 as usize] = Value::I16(e2 as i16); 250 | } 251 | _ if ins == OpCode::IMMI32 as u16 => { 252 | stack_regs[e1 as usize] = Value::I32(e2x as i32); 253 | } 254 | _ if ins == OpCode::IMMI64 as u16 => { 255 | let dp1 = e2x; 256 | pc += 1; 257 | let ci = state.current_function_call_state.function_bytecode.code[pc as usize]; 258 | let ins = ci as u16; 259 | // u48 260 | let ed = (ci << 16) as u64; 261 | if ins != OpCode::EXTRA as u16 { 262 | panic!("ERROR! EXCEPT EXTRA FIND {:02X}", ins); 263 | } else { 264 | let v = ed << 16 + dp1; 265 | stack_regs[e1 as usize] = Value::I64(v as i64); 266 | } 267 | } 268 | 269 | _ if ins == OpCode::IMMF32 as u16 => { 270 | let f = { 271 | let i = e2x; 272 | let bt = [i as u8, (i >> 8) as u8, (i >> 16) as u8, (i >> 24) as u8]; 273 | f32::from_be_bytes(bt) 274 | }; 275 | stack_regs[e1 as usize] = Value::F32(f); 276 | } 277 | _ if ins == OpCode::IMMF64 as u16 => { 278 | let dp1 = e2x; 279 | pc += 1; 280 | let ci = state.current_function_call_state.function_bytecode.code[pc as usize]; 281 | let ins = ci as u16; 282 | // u48 283 | let ed = (ci << 16) as u64; 284 | if ins != OpCode::EXTRA as u16 { 285 | panic!("ERROR! EXCEPT EXTRA FIND {:02X}", ins); 286 | } else { 287 | let bt = [ 288 | dp1 as u8, 289 | (dp1 >> 8) as u8, 290 | (dp1 >> 16) as u8, 291 | (dp1 >> 24) as u8, 292 | ed as u8, 293 | (ed >> 8) as u8, 294 | (ed >> 16) as u8, 295 | (ed >> 24) as u8, 296 | ]; 297 | let f = f64::from_be_bytes(bt); 298 | stack_regs[e1 as usize] = Value::F64(f); 299 | } 300 | } 301 | 302 | _ if ins == OpCode::IMMSTR as u16 => { 303 | // TODO: 304 | // load len 305 | // load vec 306 | // vec u8 to string 307 | } 308 | 309 | _ if ins == OpCode::NEG as u16 => match stack_regs[e1 as usize] { 310 | Value::U8(v) => stack_regs[e1 as usize] = Value::U8(-(v as i8) as u8), 311 | Value::I8(v) => stack_regs[e1 as usize] = Value::I8(-v), 312 | Value::U16(v) => stack_regs[e1 as usize] = Value::U16(-(v as i16) as u16), 313 | Value::I16(v) => stack_regs[e1 as usize] = Value::I16(-v), 314 | Value::U32(v) => stack_regs[e1 as usize] = Value::U32(-(v as i32) as u32), 315 | Value::I32(v) => stack_regs[e1 as usize] = Value::I32(-v), 316 | Value::U64(v) => stack_regs[e1 as usize] = Value::U64(-(v as i64) as u64), 317 | Value::I64(v) => stack_regs[e1 as usize] = Value::I64(-v), 318 | Value::F32(v) => stack_regs[e1 as usize] = Value::F32(-v), 319 | Value::F64(v) => stack_regs[e1 as usize] = Value::F64(-v), 320 | _ => {} 321 | }, 322 | _ if ins == OpCode::SNEG as u16 => match stack_regs[e1 as usize] { 323 | Value::U8(v) => panic!("ERROR! NEG A U8"), 324 | Value::I8(v) => stack_regs[e1 as usize] = Value::I8(-v), 325 | Value::U16(v) => panic!("ERROR! NEG A U16"), 326 | Value::I16(v) => stack_regs[e1 as usize] = Value::I16(-v), 327 | Value::U32(v) => panic!("ERROR! NEG A U32"), 328 | Value::I32(v) => stack_regs[e1 as usize] = Value::I32(-v), 329 | Value::U64(v) => panic!("ERROR! NEG A U64"), 330 | Value::I64(v) => stack_regs[e1 as usize] = Value::I64(-v), 331 | Value::F32(v) => stack_regs[e1 as usize] = Value::F32(-v), 332 | Value::F64(v) => stack_regs[e1 as usize] = Value::F64(-v), 333 | _ => panic!("ERROR! SNEG COULD NOT APPLY TO NONVALUE TYPES"), 334 | }, 335 | 336 | _ if ins == OpCode::DEC as u16 => match stack_regs[e1 as usize] { 337 | Value::U8(v) => stack_regs[e1 as usize] = Value::U8(v - 1), 338 | Value::I8(v) => stack_regs[e1 as usize] = Value::I8(v - 1), 339 | Value::U16(v) => stack_regs[e1 as usize] = Value::U16(v - 1), 340 | Value::I16(v) => stack_regs[e1 as usize] = Value::I16(v - 1), 341 | Value::U32(v) => stack_regs[e1 as usize] = Value::U32(v - 1), 342 | Value::I32(v) => stack_regs[e1 as usize] = Value::I32(v - 1), 343 | Value::U64(v) => stack_regs[e1 as usize] = Value::U64(v - 1), 344 | Value::I64(v) => stack_regs[e1 as usize] = Value::I64(v - 1), 345 | Value::F32(v) => stack_regs[e1 as usize] = Value::F32(v - 1.0), 346 | Value::F64(v) => stack_regs[e1 as usize] = Value::F64(v - 1.0), 347 | _ => {} 348 | }, 349 | _ if ins == OpCode::INC as u16 => match stack_regs[e1 as usize] { 350 | Value::U8(v) => stack_regs[e1 as usize] = Value::U8(v + 1), 351 | Value::I8(v) => stack_regs[e1 as usize] = Value::I8(v + 1), 352 | Value::U16(v) => stack_regs[e1 as usize] = Value::U16(v + 1), 353 | Value::I16(v) => stack_regs[e1 as usize] = Value::I16(v + 1), 354 | Value::U32(v) => stack_regs[e1 as usize] = Value::U32(v + 1), 355 | Value::I32(v) => stack_regs[e1 as usize] = Value::I32(v + 1), 356 | Value::U64(v) => stack_regs[e1 as usize] = Value::U64(v + 1), 357 | Value::I64(v) => stack_regs[e1 as usize] = Value::I64(v + 1), 358 | Value::F32(v) => stack_regs[e1 as usize] = Value::F32(v + 1.0), 359 | Value::F64(v) => stack_regs[e1 as usize] = Value::F64(v + 1.0), 360 | _ => {} 361 | }, 362 | _ if ins == OpCode::SDEC as u16 => match stack_regs[e1 as usize] { 363 | Value::U8(v) => { 364 | stack_regs[e1 as usize] = if v > 0 { 365 | Value::U8(v - 1) 366 | } else { 367 | panic!("ERROR! OVERFLOWING U8") 368 | } 369 | } 370 | Value::I8(v) => { 371 | stack_regs[e1 as usize] = if v > std::i8::MIN { 372 | Value::I8(v - 1) 373 | } else { 374 | panic!("ERROR! OVERFLOWING I8") 375 | } 376 | } 377 | Value::U16(v) => { 378 | stack_regs[e1 as usize] = if v > 0 { 379 | Value::U16(v - 1) 380 | } else { 381 | panic!("ERROR! OVERFLOWING U16") 382 | } 383 | } 384 | Value::I16(v) => { 385 | stack_regs[e1 as usize] = if v > std::i16::MIN { 386 | Value::I16(v - 1) 387 | } else { 388 | panic!("ERROR! OVERFLOWING I16") 389 | } 390 | } 391 | Value::U32(v) => { 392 | stack_regs[e1 as usize] = if v > 0 { 393 | Value::U32(v - 1) 394 | } else { 395 | panic!("ERROR! OVERFLOWING U32") 396 | } 397 | } 398 | Value::I32(v) => { 399 | stack_regs[e1 as usize] = if v > std::i32::MIN { 400 | Value::I32(v - 1) 401 | } else { 402 | panic!("ERROR! OVERFLOWING I32") 403 | } 404 | } 405 | Value::U64(v) => { 406 | stack_regs[e1 as usize] = if v > 0 { 407 | Value::U64(v - 1) 408 | } else { 409 | panic!("ERROR! OVERFLOWING U64") 410 | } 411 | } 412 | Value::I64(v) => { 413 | stack_regs[e1 as usize] = if v > std::i64::MIN { 414 | Value::I64(v - 1) 415 | } else { 416 | panic!("ERROR! OVERFLOWING I64") 417 | } 418 | } 419 | _ => panic!("ERROR! SDEC COULD NOT APPLY TO NONVALUE TYPES"), 420 | }, 421 | _ if ins == OpCode::SINC as u16 => match stack_regs[e1 as usize] { 422 | Value::U8(v) => { 423 | stack_regs[e1 as usize] = if v > 0 { 424 | Value::U8(v + 1) 425 | } else { 426 | panic!("ERROR! OVERFLOWING U8") 427 | } 428 | } 429 | Value::I8(v) => { 430 | stack_regs[e1 as usize] = if v > std::i8::MAX { 431 | Value::I8(v + 1) 432 | } else { 433 | panic!("ERROR! OVERFLOWING I8") 434 | } 435 | } 436 | Value::U16(v) => { 437 | stack_regs[e1 as usize] = if v > 0 { 438 | Value::U16(v + 1) 439 | } else { 440 | panic!("ERROR! OVERFLOWING U16") 441 | } 442 | } 443 | Value::I16(v) => { 444 | stack_regs[e1 as usize] = if v > std::i16::MAX { 445 | Value::I16(v + 1) 446 | } else { 447 | panic!("ERROR! OVERFLOWING I16") 448 | } 449 | } 450 | Value::U32(v) => { 451 | stack_regs[e1 as usize] = if v > 0 { 452 | Value::U32(v + 1) 453 | } else { 454 | panic!("ERROR! OVERFLOWING U32") 455 | } 456 | } 457 | Value::I32(v) => { 458 | stack_regs[e1 as usize] = if v > std::i32::MAX { 459 | Value::I32(v + 1) 460 | } else { 461 | panic!("ERROR! OVERFLOWING I32") 462 | } 463 | } 464 | Value::U64(v) => { 465 | stack_regs[e1 as usize] = if v > 0 { 466 | Value::U64(v + 1) 467 | } else { 468 | panic!("ERROR! OVERFLOWING U64") 469 | } 470 | } 471 | Value::I64(v) => { 472 | stack_regs[e1 as usize] = if v > std::i64::MAX { 473 | Value::I64(v + 1) 474 | } else { 475 | panic!("ERROR! OVERFLOWING I64") 476 | } 477 | } 478 | _ => panic!("ERROR! SINC COULD NOT APPLY TO NONVALUE TYPES"), 479 | }, 480 | 481 | _ if ins == OpCode::ADD8 as u16 => { 482 | TRI_INS_X!(stack_regs, e1, e2, e3, u8, i8, I8, U8, wrapping_add); 483 | } 484 | _ if ins == OpCode::ADD16 as u16 => { 485 | TRI_INS_X!(stack_regs, e1, e2, e3, u16, i16, I16, U16, wrapping_add); 486 | } 487 | _ if ins == OpCode::ADD32 as u16 => { 488 | TRI_INS_X!(stack_regs, e1, e2, e3, u32, i32, I32, U32, wrapping_add); 489 | } 490 | _ if ins == OpCode::ADD64 as u16 => { 491 | TRI_INS_X!(stack_regs, e1, e2, e3, u64, i64, I64, U64, wrapping_add); 492 | } 493 | _ if ins == OpCode::ADDF32 as u16 => { 494 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,+); 495 | } 496 | _ if ins == OpCode::ADDF64 as u16 => { 497 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,+); 498 | } 499 | 500 | _ if ins == OpCode::SUB8 as u16 => { 501 | TRI_INS_X!(stack_regs, e1, e2, e3, u8, i8, I8, U8, wrapping_sub); 502 | } 503 | _ if ins == OpCode::SUB16 as u16 => { 504 | TRI_INS_X!(stack_regs, e1, e2, e3, u16, i16, I16, U16, wrapping_sub); 505 | } 506 | _ if ins == OpCode::SUB32 as u16 => { 507 | TRI_INS_X!(stack_regs, e1, e2, e3, u32, i32, I32, U32, wrapping_sub); 508 | } 509 | _ if ins == OpCode::SUB64 as u16 => { 510 | TRI_INS_X!(stack_regs, e1, e2, e3, u64, i64, I64, U64, wrapping_sub); 511 | } 512 | _ if ins == OpCode::SUBF32 as u16 => { 513 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,-); 514 | } 515 | _ if ins == OpCode::SUBF64 as u16 => { 516 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,-); 517 | } 518 | 519 | _ if ins == OpCode::MUL8 as u16 => { 520 | TRI_INS_X!(stack_regs, e1, e2, e3, u8, i8, I8, U8, wrapping_mul); 521 | } 522 | _ if ins == OpCode::MUL16 as u16 => { 523 | TRI_INS_X!(stack_regs, e1, e2, e3, u16, i16, I16, U16, wrapping_mul); 524 | } 525 | _ if ins == OpCode::MUL32 as u16 => { 526 | TRI_INS_X!(stack_regs, e1, e2, e3, u32, i32, I32, U32, wrapping_mul); 527 | } 528 | _ if ins == OpCode::MUL64 as u16 => { 529 | TRI_INS_X!(stack_regs, e1, e2, e3, u64, i64, I64, U64, wrapping_mul); 530 | } 531 | _ if ins == OpCode::MULF32 as u16 => { 532 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,*); 533 | } 534 | _ if ins == OpCode::MULF64 as u16 => { 535 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,*); 536 | } 537 | 538 | _ if ins == OpCode::DIV8 as u16 => { 539 | TRI_INS_X!(stack_regs, e1, e2, e3, u8, i8, I8, U8, wrapping_div); 540 | } 541 | _ if ins == OpCode::DIV16 as u16 => { 542 | TRI_INS_X!(stack_regs, e1, e2, e3, u16, i16, I16, U16, wrapping_div); 543 | } 544 | _ if ins == OpCode::DIV32 as u16 => { 545 | TRI_INS_X!(stack_regs, e1, e2, e3, u32, i32, I32, U32, wrapping_div); 546 | } 547 | _ if ins == OpCode::DIV64 as u16 => { 548 | TRI_INS_X!(stack_regs, e1, e2, e3, u64, i64, I64, U64, wrapping_div); 549 | } 550 | _ if ins == OpCode::DIVF32 as u16 => { 551 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,/); 552 | } 553 | _ if ins == OpCode::DIVF64 as u16 => { 554 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,/); 555 | } 556 | 557 | _ if ins == OpCode::REM8 as u16 => { 558 | TRI_INS_X!(stack_regs, e1, e2, e3, u8, i8, I8, U8, wrapping_rem); 559 | } 560 | _ if ins == OpCode::REM16 as u16 => { 561 | TRI_INS_X!(stack_regs, e1, e2, e3, u16, i16, I16, U16, wrapping_rem); 562 | } 563 | _ if ins == OpCode::REM32 as u16 => { 564 | TRI_INS_X!(stack_regs, e1, e2, e3, u32, i32, I32, U32, wrapping_rem); 565 | } 566 | _ if ins == OpCode::REM64 as u16 => { 567 | TRI_INS_X!(stack_regs, e1, e2, e3, u64, i64, I64, U64, wrapping_rem); 568 | } 569 | _ if ins == OpCode::REMF32 as u16 => { 570 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,%); 571 | } 572 | _ if ins == OpCode::REMF64 as u16 => { 573 | TRI_INS_X!(stack_regs,e1,e2,e3,f32,f32,F32,%); 574 | } 575 | 576 | _ if ins == OpCode::SADD8 as u16 => { 577 | let mut sized = false; 578 | let v1 = match stack_regs[e1 as usize] { 579 | Value::U8(v) => v as u8, 580 | Value::I8(v) => { 581 | sized = true; 582 | v as u8 583 | } 584 | Value::U16(v) => v as u8, 585 | Value::I16(v) => { 586 | sized = true; 587 | v as u8 588 | } 589 | Value::U32(v) => v as u8, 590 | Value::I32(v) => { 591 | sized = true; 592 | v as u8 593 | } 594 | Value::U64(v) => v as u8, 595 | Value::I64(v) => { 596 | sized = true; 597 | v as u8 598 | } 599 | Value::F32(v) => { 600 | sized = true; 601 | v as u8 602 | } 603 | Value::F64(v) => { 604 | sized = true; 605 | v as u8 606 | } 607 | _ => { 608 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 609 | } 610 | }; 611 | let v2 = match stack_regs[e2 as usize] { 612 | Value::U8(v) => v as u8, 613 | Value::I8(v) => { 614 | sized = true; 615 | v as u8 616 | } 617 | Value::U16(v) => v as u8, 618 | Value::I16(v) => { 619 | sized = true; 620 | v as u8 621 | } 622 | Value::U32(v) => v as u8, 623 | Value::I32(v) => { 624 | sized = true; 625 | v as u8 626 | } 627 | Value::U64(v) => v as u8, 628 | Value::I64(v) => { 629 | sized = true; 630 | v as u8 631 | } 632 | Value::F32(v) => { 633 | sized = true; 634 | v as u8 635 | } 636 | Value::F64(v) => { 637 | sized = true; 638 | v as u8 639 | } 640 | _ => { 641 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 642 | } 643 | }; 644 | if sized { 645 | match (v1 as i8).checked_add(v2 as i8) { 646 | Some(v) => { 647 | stack_regs[e3 as usize] = Value::I8(v); 648 | } 649 | None => panic!("ERROR! ARITH OVERFLOW"), 650 | } 651 | } else { 652 | match v1.checked_add(v2) { 653 | Some(v) => { 654 | stack_regs[e3 as usize] = Value::U8(v); 655 | } 656 | None => panic!("ERROR! ARITH OVERFLOW"), 657 | } 658 | } 659 | } 660 | 661 | _ if ins == OpCode::BNOT as u16 => match stack_regs[e1 as usize] { 662 | Value::U8(v) => stack_regs[e2 as usize] = Value::U8(!v), 663 | Value::I8(v) => stack_regs[e2 as usize] = Value::I8(!v), 664 | Value::U16(v) => stack_regs[e2 as usize] = Value::U16(!v), 665 | Value::I16(v) => stack_regs[e2 as usize] = Value::I16(!v), 666 | Value::U32(v) => stack_regs[e2 as usize] = Value::U32(!v), 667 | Value::I32(v) => stack_regs[e2 as usize] = Value::I32(!v), 668 | Value::U64(v) => stack_regs[e2 as usize] = Value::U64(!v), 669 | Value::I64(v) => stack_regs[e2 as usize] = Value::I64(!v), 670 | Value::F32(v) => stack_regs[e2 as usize] = Value::I32(!(v as i32)), 671 | Value::F64(v) => stack_regs[e2 as usize] = Value::I64(!(v as i64)), 672 | _ => {} 673 | }, 674 | _ if ins == OpCode::BAND as u16 => { 675 | let mut sized = false; 676 | let mut max: u8 = 0b0000; 677 | let v1 = match stack_regs[e1 as usize] { 678 | Value::U8(v) => { 679 | max |= 0b0001; 680 | v as u64 681 | } 682 | Value::I8(v) => { 683 | max |= 0b0001; 684 | sized = true; 685 | v as u64 686 | } 687 | Value::U16(v) => { 688 | max |= 0b0010; 689 | v as u64 690 | } 691 | Value::I16(v) => { 692 | max |= 0b0010; 693 | sized = true; 694 | v as u64 695 | } 696 | Value::U32(v) => { 697 | max |= 0b0100; 698 | v as u64 699 | } 700 | Value::I32(v) => { 701 | max |= 0b0100; 702 | sized = true; 703 | v as u64 704 | } 705 | Value::U64(v) => { 706 | max |= 0b1000; 707 | v as u64 708 | } 709 | Value::I64(v) => { 710 | max |= 0b1000; 711 | sized = true; 712 | v as u64 713 | } 714 | Value::F32(v) => { 715 | max |= 0b1000; 716 | sized = true; 717 | v as u64 718 | } 719 | Value::F64(v) => { 720 | max |= 0b1000; 721 | sized = true; 722 | v as u64 723 | } 724 | _ => { 725 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 726 | } 727 | }; 728 | let v2 = match stack_regs[e2 as usize] { 729 | Value::U8(v) => { 730 | max |= 0b0001; 731 | v as u64 732 | } 733 | Value::I8(v) => { 734 | max |= 0b0001; 735 | sized = true; 736 | v as u64 737 | } 738 | Value::U16(v) => { 739 | max |= 0b0010; 740 | v as u64 741 | } 742 | Value::I16(v) => { 743 | max |= 0b0010; 744 | sized = true; 745 | v as u64 746 | } 747 | Value::U32(v) => { 748 | max |= 0b0100; 749 | v as u64 750 | } 751 | Value::I32(v) => { 752 | max |= 0b0100; 753 | sized = true; 754 | v as u64 755 | } 756 | Value::U64(v) => { 757 | max |= 0b1000; 758 | v as u64 759 | } 760 | Value::I64(v) => { 761 | max |= 0b1000; 762 | sized = true; 763 | v as u64 764 | } 765 | Value::F32(v) => { 766 | max |= 0b1000; 767 | sized = true; 768 | v as u64 769 | } 770 | Value::F64(v) => { 771 | max |= 0b1000; 772 | sized = true; 773 | v as u64 774 | } 775 | _ => { 776 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 777 | } 778 | }; 779 | if max & 0b1000 == 0b1000 { 780 | if sized { 781 | stack_regs[e3 as usize] = Value::I64(v1 as i64 & v2 as i64); 782 | } else { 783 | stack_regs[e3 as usize] = Value::U64(v1 as u64 & v2 as u64); 784 | } 785 | } else if max & 0b0100 == 0b0100 { 786 | if sized { 787 | stack_regs[e3 as usize] = Value::I32(v1 as i32 & v2 as i32); 788 | } else { 789 | stack_regs[e3 as usize] = Value::U32(v1 as u32 & v2 as u32); 790 | } 791 | } else if max & 0b0010 == 0b0010 { 792 | if sized { 793 | stack_regs[e3 as usize] = Value::I16(v1 as i16 & v2 as i16); 794 | } else { 795 | stack_regs[e3 as usize] = Value::U16(v1 as u16 & v2 as u16); 796 | } 797 | } else if max & 0b0001 == 0b0001 { 798 | if sized { 799 | stack_regs[e3 as usize] = Value::I8(v1 as i8 & v2 as i8); 800 | } else { 801 | stack_regs[e3 as usize] = Value::U8(v1 as u8 & v2 as u8); 802 | } 803 | } else { 804 | panic!("卧槽? 咋了?!"); 805 | } 806 | } 807 | _ if ins == OpCode::BXOR as u16 => { 808 | let mut sized = false; 809 | let mut max: u8 = 0b0000; 810 | let v1 = match stack_regs[e1 as usize] { 811 | Value::U8(v) => { 812 | max |= 0b0001; 813 | v as u64 814 | } 815 | Value::I8(v) => { 816 | max |= 0b0001; 817 | sized = true; 818 | v as u64 819 | } 820 | Value::U16(v) => { 821 | max |= 0b0010; 822 | v as u64 823 | } 824 | Value::I16(v) => { 825 | max |= 0b0010; 826 | sized = true; 827 | v as u64 828 | } 829 | Value::U32(v) => { 830 | max |= 0b0100; 831 | v as u64 832 | } 833 | Value::I32(v) => { 834 | max |= 0b0100; 835 | sized = true; 836 | v as u64 837 | } 838 | Value::U64(v) => { 839 | max |= 0b1000; 840 | v as u64 841 | } 842 | Value::I64(v) => { 843 | max |= 0b1000; 844 | sized = true; 845 | v as u64 846 | } 847 | Value::F32(v) => { 848 | max |= 0b1000; 849 | sized = true; 850 | v as u64 851 | } 852 | Value::F64(v) => { 853 | max |= 0b1000; 854 | sized = true; 855 | v as u64 856 | } 857 | _ => { 858 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 859 | } 860 | }; 861 | let v2 = match stack_regs[e2 as usize] { 862 | Value::U8(v) => { 863 | max |= 0b0001; 864 | v as u64 865 | } 866 | Value::I8(v) => { 867 | max |= 0b0001; 868 | sized = true; 869 | v as u64 870 | } 871 | Value::U16(v) => { 872 | max |= 0b0010; 873 | v as u64 874 | } 875 | Value::I16(v) => { 876 | max |= 0b0010; 877 | sized = true; 878 | v as u64 879 | } 880 | Value::U32(v) => { 881 | max |= 0b0100; 882 | v as u64 883 | } 884 | Value::I32(v) => { 885 | max |= 0b0100; 886 | sized = true; 887 | v as u64 888 | } 889 | Value::U64(v) => { 890 | max |= 0b1000; 891 | v as u64 892 | } 893 | Value::I64(v) => { 894 | max |= 0b1000; 895 | sized = true; 896 | v as u64 897 | } 898 | Value::F32(v) => { 899 | max |= 0b1000; 900 | sized = true; 901 | v as u64 902 | } 903 | Value::F64(v) => { 904 | max |= 0b1000; 905 | sized = true; 906 | v as u64 907 | } 908 | _ => { 909 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 910 | } 911 | }; 912 | if max & 0b1000 == 0b1000 { 913 | if sized { 914 | stack_regs[e3 as usize] = Value::I64(v1 as i64 ^ v2 as i64); 915 | } else { 916 | stack_regs[e3 as usize] = Value::U64(v1 as u64 ^ v2 as u64); 917 | } 918 | } else if max & 0b0100 == 0b0100 { 919 | if sized { 920 | stack_regs[e3 as usize] = Value::I32(v1 as i32 ^ v2 as i32); 921 | } else { 922 | stack_regs[e3 as usize] = Value::U32(v1 as u32 ^ v2 as u32); 923 | } 924 | } else if max & 0b0010 == 0b0010 { 925 | if sized { 926 | stack_regs[e3 as usize] = Value::I16(v1 as i16 ^ v2 as i16); 927 | } else { 928 | stack_regs[e3 as usize] = Value::U16(v1 as u16 ^ v2 as u16); 929 | } 930 | } else if max & 0b0001 == 0b0001 { 931 | if sized { 932 | stack_regs[e3 as usize] = Value::I8(v1 as i8 ^ v2 as i8); 933 | } else { 934 | stack_regs[e3 as usize] = Value::U8(v1 as u8 ^ v2 as u8); 935 | } 936 | } else { 937 | panic!("卧槽? 咋了?!"); 938 | } 939 | } 940 | _ if ins == OpCode::BOR as u16 => { 941 | let mut sized = false; 942 | let mut max: u8 = 0b0000; 943 | let v1 = match stack_regs[e1 as usize] { 944 | Value::U8(v) => { 945 | max |= 0b0001; 946 | v as u64 947 | } 948 | Value::I8(v) => { 949 | max |= 0b0001; 950 | sized = true; 951 | v as u64 952 | } 953 | Value::U16(v) => { 954 | max |= 0b0010; 955 | v as u64 956 | } 957 | Value::I16(v) => { 958 | max |= 0b0010; 959 | sized = true; 960 | v as u64 961 | } 962 | Value::U32(v) => { 963 | max |= 0b0100; 964 | v as u64 965 | } 966 | Value::I32(v) => { 967 | max |= 0b0100; 968 | sized = true; 969 | v as u64 970 | } 971 | Value::U64(v) => { 972 | max |= 0b1000; 973 | v as u64 974 | } 975 | Value::I64(v) => { 976 | max |= 0b1000; 977 | sized = true; 978 | v as u64 979 | } 980 | Value::F32(v) => { 981 | max |= 0b1000; 982 | sized = true; 983 | v as u64 984 | } 985 | Value::F64(v) => { 986 | max |= 0b1000; 987 | sized = true; 988 | v as u64 989 | } 990 | _ => { 991 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 992 | } 993 | }; 994 | let v2 = match stack_regs[e2 as usize] { 995 | Value::U8(v) => { 996 | max |= 0b0001; 997 | v as u64 998 | } 999 | Value::I8(v) => { 1000 | max |= 0b0001; 1001 | sized = true; 1002 | v as u64 1003 | } 1004 | Value::U16(v) => { 1005 | max |= 0b0010; 1006 | v as u64 1007 | } 1008 | Value::I16(v) => { 1009 | max |= 0b0010; 1010 | sized = true; 1011 | v as u64 1012 | } 1013 | Value::U32(v) => { 1014 | max |= 0b0100; 1015 | v as u64 1016 | } 1017 | Value::I32(v) => { 1018 | max |= 0b0100; 1019 | sized = true; 1020 | v as u64 1021 | } 1022 | Value::U64(v) => { 1023 | max |= 0b1000; 1024 | v as u64 1025 | } 1026 | Value::I64(v) => { 1027 | max |= 0b1000; 1028 | sized = true; 1029 | v as u64 1030 | } 1031 | Value::F32(v) => { 1032 | max |= 0b1000; 1033 | sized = true; 1034 | v as u64 1035 | } 1036 | Value::F64(v) => { 1037 | max |= 0b1000; 1038 | sized = true; 1039 | v as u64 1040 | } 1041 | _ => { 1042 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 1043 | } 1044 | }; 1045 | if max & 0b1000 == 0b1000 { 1046 | if sized { 1047 | stack_regs[e3 as usize] = Value::I64(v1 as i64 | v2 as i64); 1048 | } else { 1049 | stack_regs[e3 as usize] = Value::U64(v1 as u64 | v2 as u64); 1050 | } 1051 | } else if max & 0b0100 == 0b0100 { 1052 | if sized { 1053 | stack_regs[e3 as usize] = Value::I32(v1 as i32 | v2 as i32); 1054 | } else { 1055 | stack_regs[e3 as usize] = Value::U32(v1 as u32 | v2 as u32); 1056 | } 1057 | } else if max & 0b0010 == 0b0010 { 1058 | if sized { 1059 | stack_regs[e3 as usize] = Value::I16(v1 as i16 | v2 as i16); 1060 | } else { 1061 | stack_regs[e3 as usize] = Value::U16(v1 as u16 | v2 as u16); 1062 | } 1063 | } else if max & 0b0001 == 0b0001 { 1064 | if sized { 1065 | stack_regs[e3 as usize] = Value::I8(v1 as i8 | v2 as i8); 1066 | } else { 1067 | stack_regs[e3 as usize] = Value::U8(v1 as u8 | v2 as u8); 1068 | } 1069 | } else { 1070 | panic!("卧槽? 咋了?!"); 1071 | } 1072 | } 1073 | 1074 | _ if ins == OpCode::SHL as u16 => { 1075 | let mut sized = false; 1076 | let mut max: u8 = 0b0000; 1077 | let v1 = match stack_regs[e1 as usize] { 1078 | Value::U8(v) => { 1079 | max |= 0b0001; 1080 | v as u64 1081 | } 1082 | Value::I8(v) => { 1083 | max |= 0b0001; 1084 | sized = true; 1085 | v as u64 1086 | } 1087 | Value::U16(v) => { 1088 | max |= 0b0010; 1089 | v as u64 1090 | } 1091 | Value::I16(v) => { 1092 | max |= 0b0010; 1093 | sized = true; 1094 | v as u64 1095 | } 1096 | Value::U32(v) => { 1097 | max |= 0b0100; 1098 | v as u64 1099 | } 1100 | Value::I32(v) => { 1101 | max |= 0b0100; 1102 | sized = true; 1103 | v as u64 1104 | } 1105 | Value::U64(v) => { 1106 | max |= 0b1000; 1107 | v as u64 1108 | } 1109 | Value::I64(v) => { 1110 | max |= 0b1000; 1111 | sized = true; 1112 | v as u64 1113 | } 1114 | Value::F32(v) => { 1115 | max |= 0b1000; 1116 | sized = true; 1117 | v as u64 1118 | } 1119 | Value::F64(v) => { 1120 | max |= 0b1000; 1121 | sized = true; 1122 | v as u64 1123 | } 1124 | _ => { 1125 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 1126 | } 1127 | }; 1128 | let v2 = match stack_regs[e2 as usize] { 1129 | Value::U8(v) => { 1130 | max |= 0b0001; 1131 | v as u64 1132 | } 1133 | Value::I8(v) => { 1134 | max |= 0b0001; 1135 | sized = true; 1136 | v as u64 1137 | } 1138 | Value::U16(v) => { 1139 | max |= 0b0010; 1140 | v as u64 1141 | } 1142 | Value::I16(v) => { 1143 | max |= 0b0010; 1144 | sized = true; 1145 | v as u64 1146 | } 1147 | Value::U32(v) => { 1148 | max |= 0b0100; 1149 | v as u64 1150 | } 1151 | Value::I32(v) => { 1152 | max |= 0b0100; 1153 | sized = true; 1154 | v as u64 1155 | } 1156 | Value::U64(v) => { 1157 | max |= 0b1000; 1158 | v as u64 1159 | } 1160 | Value::I64(v) => { 1161 | max |= 0b1000; 1162 | sized = true; 1163 | v as u64 1164 | } 1165 | Value::F32(v) => { 1166 | max |= 0b1000; 1167 | sized = true; 1168 | v as u64 1169 | } 1170 | Value::F64(v) => { 1171 | max |= 0b1000; 1172 | sized = true; 1173 | v as u64 1174 | } 1175 | _ => { 1176 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 1177 | } 1178 | }; 1179 | if max & 0b1000 == 0b1000 { 1180 | if sized { 1181 | stack_regs[e3 as usize] = Value::I64((v1 as i64) << v2 as i64); 1182 | } else { 1183 | stack_regs[e3 as usize] = Value::U64((v1 as u64) << v2 as u64); 1184 | } 1185 | } else if max & 0b0100 == 0b0100 { 1186 | if sized { 1187 | stack_regs[e3 as usize] = Value::I32((v1 as i32) << v2 as i32); 1188 | } else { 1189 | stack_regs[e3 as usize] = Value::U32((v1 as u32) << v2 as u32); 1190 | } 1191 | } else if max & 0b0010 == 0b0010 { 1192 | if sized { 1193 | stack_regs[e3 as usize] = Value::I16((v1 as i16) << v2 as i16); 1194 | } else { 1195 | stack_regs[e3 as usize] = Value::U16((v1 as u16) << v2 as u16); 1196 | } 1197 | } else if max & 0b0001 == 0b0001 { 1198 | if sized { 1199 | stack_regs[e3 as usize] = Value::I8((v1 as i8) << v2 as i8); 1200 | } else { 1201 | stack_regs[e3 as usize] = Value::U8((v1 as u8) << v2 as u8); 1202 | } 1203 | } else { 1204 | panic!("卧槽? 咋了?!"); 1205 | } 1206 | } 1207 | _ if ins == OpCode::SHR as u16 => { 1208 | let mut sized = false; 1209 | let mut max: u8 = 0b0000; 1210 | let v1 = match stack_regs[e1 as usize] { 1211 | Value::U8(v) => { 1212 | max |= 0b0001; 1213 | v as u64 1214 | } 1215 | Value::I8(v) => { 1216 | max |= 0b0001; 1217 | sized = true; 1218 | v as u64 1219 | } 1220 | Value::U16(v) => { 1221 | max |= 0b0010; 1222 | v as u64 1223 | } 1224 | Value::I16(v) => { 1225 | max |= 0b0010; 1226 | sized = true; 1227 | v as u64 1228 | } 1229 | Value::U32(v) => { 1230 | max |= 0b0100; 1231 | v as u64 1232 | } 1233 | Value::I32(v) => { 1234 | max |= 0b0100; 1235 | sized = true; 1236 | v as u64 1237 | } 1238 | Value::U64(v) => { 1239 | max |= 0b1000; 1240 | v as u64 1241 | } 1242 | Value::I64(v) => { 1243 | max |= 0b1000; 1244 | sized = true; 1245 | v as u64 1246 | } 1247 | Value::F32(v) => { 1248 | max |= 0b1000; 1249 | sized = true; 1250 | v as u64 1251 | } 1252 | Value::F64(v) => { 1253 | max |= 0b1000; 1254 | sized = true; 1255 | v as u64 1256 | } 1257 | _ => { 1258 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 1259 | } 1260 | }; 1261 | let v2 = match stack_regs[e2 as usize] { 1262 | Value::U8(v) => { 1263 | max |= 0b0001; 1264 | v as u64 1265 | } 1266 | Value::I8(v) => { 1267 | max |= 0b0001; 1268 | sized = true; 1269 | v as u64 1270 | } 1271 | Value::U16(v) => { 1272 | max |= 0b0010; 1273 | v as u64 1274 | } 1275 | Value::I16(v) => { 1276 | max |= 0b0010; 1277 | sized = true; 1278 | v as u64 1279 | } 1280 | Value::U32(v) => { 1281 | max |= 0b0100; 1282 | v as u64 1283 | } 1284 | Value::I32(v) => { 1285 | max |= 0b0100; 1286 | sized = true; 1287 | v as u64 1288 | } 1289 | Value::U64(v) => { 1290 | max |= 0b1000; 1291 | v as u64 1292 | } 1293 | Value::I64(v) => { 1294 | max |= 0b1000; 1295 | sized = true; 1296 | v as u64 1297 | } 1298 | Value::F32(v) => { 1299 | max |= 0b1000; 1300 | sized = true; 1301 | v as u64 1302 | } 1303 | Value::F64(v) => { 1304 | max |= 0b1000; 1305 | sized = true; 1306 | v as u64 1307 | } 1308 | _ => { 1309 | panic!("ERROR! ARITH INSTRUCTION COULD ONLY APPLY TO NUMERICAL VALUES") 1310 | } 1311 | }; 1312 | if max & 0b1000 == 0b1000 { 1313 | if sized { 1314 | stack_regs[e3 as usize] = Value::I64((v1 as i64) >> v2 as i64); 1315 | } else { 1316 | stack_regs[e3 as usize] = Value::U64((v1 as u64) >> v2 as u64); 1317 | } 1318 | } else if max & 0b0100 == 0b0100 { 1319 | if sized { 1320 | stack_regs[e3 as usize] = Value::I32((v1 as i32) >> v2 as i32); 1321 | } else { 1322 | stack_regs[e3 as usize] = Value::U32((v1 as u32) >> v2 as u32); 1323 | } 1324 | } else if max & 0b0010 == 0b0010 { 1325 | if sized { 1326 | stack_regs[e3 as usize] = Value::I16((v1 as i16) >> v2 as i16); 1327 | } else { 1328 | stack_regs[e3 as usize] = Value::U16((v1 as u16) >> v2 as u16); 1329 | } 1330 | } else if max & 0b0001 == 0b0001 { 1331 | if sized { 1332 | stack_regs[e3 as usize] = Value::I8((v1 as i8) >> v2 as i8); 1333 | } else { 1334 | stack_regs[e3 as usize] = Value::U8((v1 as u8) >> v2 as u8); 1335 | } 1336 | } else { 1337 | panic!("卧槽? 咋了?!"); 1338 | } 1339 | } 1340 | 1341 | _ if ins == OpCode::NOT as u16 => { 1342 | if let Some(b) = value_to_bool(&stack_regs[e1 as usize]) { 1343 | stack_regs[e2 as usize] = Value::Boolean(!b); 1344 | } else { 1345 | panic!("ERROR! NOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES") 1346 | } 1347 | } 1348 | _ if ins == OpCode::LNOT as u16 => { 1349 | match stack_regs[e1 as usize] { 1350 | Value::Boolean(v) => { 1351 | stack_regs[e2 as usize] = Value::Boolean(!v); 1352 | } 1353 | _ => panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES"), 1354 | }; 1355 | } 1356 | _ if ins == OpCode::AND as u16 => { 1357 | if let Some(b1) = value_to_bool(&stack_regs[e1 as usize]) { 1358 | if let Some(b2) = value_to_bool(&stack_regs[e2 as usize]) { 1359 | stack_regs[e3 as usize] = Value::Boolean(b1 && b2); 1360 | } else { 1361 | panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES") 1362 | } 1363 | } else { 1364 | panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES") 1365 | } 1366 | } 1367 | _ if ins == OpCode::LAND as u16 => { 1368 | let b1 = match stack_regs[e1 as usize] { 1369 | Value::Boolean(v) => v, 1370 | _ => panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES"), 1371 | }; 1372 | let b2 = match stack_regs[e1 as usize] { 1373 | Value::Boolean(v) => v, 1374 | _ => panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES"), 1375 | }; 1376 | stack_regs[e3 as usize] = Value::Boolean(b1 && b2); 1377 | } 1378 | _ if ins == OpCode::OR as u16 => { 1379 | if let Some(b1) = value_to_bool(&stack_regs[e1 as usize]) { 1380 | if let Some(b2) = value_to_bool(&stack_regs[e2 as usize]) { 1381 | stack_regs[e3 as usize] = Value::Boolean(b1 || b2); 1382 | } else { 1383 | panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES") 1384 | } 1385 | } else { 1386 | panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES") 1387 | } 1388 | } 1389 | _ if ins == OpCode::LOR as u16 => { 1390 | let b1 = match stack_regs[e1 as usize] { 1391 | Value::Boolean(v) => v, 1392 | _ => panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES"), 1393 | }; 1394 | let b2 = match stack_regs[e1 as usize] { 1395 | Value::Boolean(v) => v, 1396 | _ => panic!("ERROR! LNOT INSTRUCTION COULD ONLY APPLY TO BOOLEAN VALUES"), 1397 | }; 1398 | stack_regs[e3 as usize] = Value::Boolean(b1 || b2); 1399 | } 1400 | _ if ins == OpCode::EQ as u16 => { 1401 | let mut cu1: u64 = 0; 1402 | let mut cf1: f64 = 0.0; 1403 | let mut to_f1 = false; 1404 | let mut scomp1 = false; 1405 | match stack_regs[e1 as usize] { 1406 | Value::U8(v) => cu1 = v as u64, 1407 | Value::I8(v) => cu1 = v as u64, 1408 | Value::U16(v) => cu1 = v as u64, 1409 | Value::I16(v) => cu1 = v as u64, 1410 | Value::U32(v) => cu1 = v as u64, 1411 | Value::I32(v) => cu1 = v as u64, 1412 | Value::U64(v) => cu1 = v as u64, 1413 | Value::I64(v) => cu1 = v as u64, 1414 | Value::F32(v) => { 1415 | to_f1 = true; 1416 | cf1 = v as f64 1417 | } 1418 | Value::F64(v) => { 1419 | to_f1 = true; 1420 | cf1 = v as f64 1421 | } 1422 | _ => scomp1 = true, 1423 | }; 1424 | let mut cu2: u64 = 0; 1425 | let mut cf2: f64 = 0.0; 1426 | let mut to_f2 = false; 1427 | let mut scomp2 = false; 1428 | match stack_regs[e1 as usize] { 1429 | Value::U8(v) => cu2 = v as u64, 1430 | Value::I8(v) => cu2 = v as u64, 1431 | Value::U16(v) => cu2 = v as u64, 1432 | Value::I16(v) => cu2 = v as u64, 1433 | Value::U32(v) => cu2 = v as u64, 1434 | Value::I32(v) => cu2 = v as u64, 1435 | Value::U64(v) => cu2 = v as u64, 1436 | Value::I64(v) => cu2 = v as u64, 1437 | Value::F32(v) => { 1438 | to_f2 = true; 1439 | cf2 = v as f64 1440 | } 1441 | Value::F64(v) => { 1442 | to_f2 = true; 1443 | cf2 = v as f64 1444 | } 1445 | _ => scomp2 = true, 1446 | }; 1447 | if scomp1 || scomp2 { 1448 | stack_regs[e3 as usize] = 1449 | Value::Boolean(stack_regs[e1 as usize] == stack_regs[e2 as usize]); 1450 | } else if to_f1 || to_f2 { 1451 | if to_f1 && !to_f2 { 1452 | stack_regs[e3 as usize] = Value::Boolean(cf1 == cu2 as f64); 1453 | } else if to_f2 && !to_f1 { 1454 | stack_regs[e3 as usize] = Value::Boolean(cf2 == cu1 as f64); 1455 | } else { 1456 | stack_regs[e3 as usize] = Value::Boolean(cf1 == cf2); 1457 | } 1458 | } else { 1459 | stack_regs[e3 as usize] = Value::Boolean(cu1 == cu2); 1460 | } 1461 | } 1462 | _ if ins == OpCode::SEQ as u16 => { 1463 | stack_regs[e3 as usize] = 1464 | Value::Boolean(stack_regs[e1 as usize] == stack_regs[e2 as usize]); 1465 | } 1466 | _ if ins == OpCode::LT as u16 => { 1467 | let mut cu1: u64 = 0; 1468 | let mut cf1: f64 = 0.0; 1469 | let mut to_f1 = false; 1470 | let mut scomp1 = false; 1471 | match stack_regs[e1 as usize] { 1472 | Value::U8(v) => cu1 = v as u64, 1473 | Value::I8(v) => cu1 = v as u64, 1474 | Value::U16(v) => cu1 = v as u64, 1475 | Value::I16(v) => cu1 = v as u64, 1476 | Value::U32(v) => cu1 = v as u64, 1477 | Value::I32(v) => cu1 = v as u64, 1478 | Value::U64(v) => cu1 = v as u64, 1479 | Value::I64(v) => cu1 = v as u64, 1480 | Value::F32(v) => { 1481 | to_f1 = true; 1482 | cf1 = v as f64 1483 | } 1484 | Value::F64(v) => { 1485 | to_f1 = true; 1486 | cf1 = v as f64 1487 | } 1488 | _ => scomp1 = true, 1489 | }; 1490 | let mut cu2: u64 = 0; 1491 | let mut cf2: f64 = 0.0; 1492 | let mut to_f2 = false; 1493 | let mut scomp2 = false; 1494 | match stack_regs[e1 as usize] { 1495 | Value::U8(v) => cu2 = v as u64, 1496 | Value::I8(v) => cu2 = v as u64, 1497 | Value::U16(v) => cu2 = v as u64, 1498 | Value::I16(v) => cu2 = v as u64, 1499 | Value::U32(v) => cu2 = v as u64, 1500 | Value::I32(v) => cu2 = v as u64, 1501 | Value::U64(v) => cu2 = v as u64, 1502 | Value::I64(v) => cu2 = v as u64, 1503 | Value::F32(v) => { 1504 | to_f2 = true; 1505 | cf2 = v as f64 1506 | } 1507 | Value::F64(v) => { 1508 | to_f2 = true; 1509 | cf2 = v as f64 1510 | } 1511 | _ => scomp2 = true, 1512 | }; 1513 | if scomp1 || scomp2 { 1514 | stack_regs[e3 as usize] = 1515 | Value::Boolean(stack_regs[e1 as usize] == stack_regs[e2 as usize]); 1516 | } else if to_f1 || to_f2 { 1517 | if to_f1 && !to_f2 { 1518 | stack_regs[e3 as usize] = Value::Boolean(cf1 == cu2 as f64); 1519 | } else if to_f2 && !to_f1 { 1520 | stack_regs[e3 as usize] = Value::Boolean(cf2 == cu1 as f64); 1521 | } else { 1522 | stack_regs[e3 as usize] = Value::Boolean(cf1 == cf2); 1523 | } 1524 | } else { 1525 | stack_regs[e3 as usize] = Value::Boolean(cu1 == cu2); 1526 | } 1527 | } 1528 | _ if ins == OpCode::LT as u16 => { 1529 | let mut cu1: u64 = 0; 1530 | let mut cf1: f64 = 0.0; 1531 | let mut to_f1 = false; 1532 | let mut scomp1 = false; 1533 | match stack_regs[e1 as usize] { 1534 | Value::U8(v) => cu1 = v as u64, 1535 | Value::I8(v) => cu1 = v as u64, 1536 | Value::U16(v) => cu1 = v as u64, 1537 | Value::I16(v) => cu1 = v as u64, 1538 | Value::U32(v) => cu1 = v as u64, 1539 | Value::I32(v) => cu1 = v as u64, 1540 | Value::U64(v) => cu1 = v as u64, 1541 | Value::I64(v) => cu1 = v as u64, 1542 | Value::F32(v) => { 1543 | to_f1 = true; 1544 | cf1 = v as f64 1545 | } 1546 | Value::F64(v) => { 1547 | to_f1 = true; 1548 | cf1 = v as f64 1549 | } 1550 | _ => scomp1 = true, 1551 | }; 1552 | let mut cu2: u64 = 0; 1553 | let mut cf2: f64 = 0.0; 1554 | let mut to_f2 = false; 1555 | let mut scomp2 = false; 1556 | match stack_regs[e1 as usize] { 1557 | Value::U8(v) => cu2 = v as u64, 1558 | Value::I8(v) => cu2 = v as u64, 1559 | Value::U16(v) => cu2 = v as u64, 1560 | Value::I16(v) => cu2 = v as u64, 1561 | Value::U32(v) => cu2 = v as u64, 1562 | Value::I32(v) => cu2 = v as u64, 1563 | Value::U64(v) => cu2 = v as u64, 1564 | Value::I64(v) => cu2 = v as u64, 1565 | Value::F32(v) => { 1566 | to_f2 = true; 1567 | cf2 = v as f64 1568 | } 1569 | Value::F64(v) => { 1570 | to_f2 = true; 1571 | cf2 = v as f64 1572 | } 1573 | _ => scomp2 = true, 1574 | }; 1575 | if scomp1 || scomp2 { 1576 | panic!("ERROR LT COULD NOT COMPARE NON VALUE TYPE") 1577 | } else if to_f1 || to_f2 { 1578 | if to_f1 && !to_f2 { 1579 | stack_regs[e3 as usize] = Value::Boolean(cf1 < cu2 as f64); 1580 | } else if to_f2 && !to_f1 { 1581 | stack_regs[e3 as usize] = Value::Boolean(cf2 < cu1 as f64); 1582 | } else { 1583 | stack_regs[e3 as usize] = Value::Boolean(cf1 < cf2); 1584 | } 1585 | } else { 1586 | stack_regs[e3 as usize] = Value::Boolean(cu1 < cu2); 1587 | } 1588 | } 1589 | _ if ins == OpCode::GT as u16 => { 1590 | let mut cu1: u64 = 0; 1591 | let mut cf1: f64 = 0.0; 1592 | let mut to_f1 = false; 1593 | let mut scomp1 = false; 1594 | match stack_regs[e1 as usize] { 1595 | Value::U8(v) => cu1 = v as u64, 1596 | Value::I8(v) => cu1 = v as u64, 1597 | Value::U16(v) => cu1 = v as u64, 1598 | Value::I16(v) => cu1 = v as u64, 1599 | Value::U32(v) => cu1 = v as u64, 1600 | Value::I32(v) => cu1 = v as u64, 1601 | Value::U64(v) => cu1 = v as u64, 1602 | Value::I64(v) => cu1 = v as u64, 1603 | Value::F32(v) => { 1604 | to_f1 = true; 1605 | cf1 = v as f64 1606 | } 1607 | Value::F64(v) => { 1608 | to_f1 = true; 1609 | cf1 = v as f64 1610 | } 1611 | _ => scomp1 = true, 1612 | }; 1613 | let mut cu2: u64 = 0; 1614 | let mut cf2: f64 = 0.0; 1615 | let mut to_f2 = false; 1616 | let mut scomp2 = false; 1617 | match stack_regs[e1 as usize] { 1618 | Value::U8(v) => cu2 = v as u64, 1619 | Value::I8(v) => cu2 = v as u64, 1620 | Value::U16(v) => cu2 = v as u64, 1621 | Value::I16(v) => cu2 = v as u64, 1622 | Value::U32(v) => cu2 = v as u64, 1623 | Value::I32(v) => cu2 = v as u64, 1624 | Value::U64(v) => cu2 = v as u64, 1625 | Value::I64(v) => cu2 = v as u64, 1626 | Value::F32(v) => { 1627 | to_f2 = true; 1628 | cf2 = v as f64 1629 | } 1630 | Value::F64(v) => { 1631 | to_f2 = true; 1632 | cf2 = v as f64 1633 | } 1634 | _ => scomp2 = true, 1635 | }; 1636 | if scomp1 || scomp2 { 1637 | panic!("ERROR LT COULD NOT COMPARE NON VALUE TYPE") 1638 | } else if to_f1 || to_f2 { 1639 | if to_f1 && !to_f2 { 1640 | stack_regs[e3 as usize] = Value::Boolean(cf1 > cu2 as f64); 1641 | } else if to_f2 && !to_f1 { 1642 | stack_regs[e3 as usize] = Value::Boolean(cf2 > cu1 as f64); 1643 | } else { 1644 | stack_regs[e3 as usize] = Value::Boolean(cf1 > cf2); 1645 | } 1646 | } else { 1647 | stack_regs[e3 as usize] = Value::Boolean(cu1 > cu2); 1648 | } 1649 | } 1650 | _ if ins == OpCode::LTEQ as u16 => { 1651 | let mut cu1: u64 = 0; 1652 | let mut cf1: f64 = 0.0; 1653 | let mut to_f1 = false; 1654 | let mut scomp1 = false; 1655 | match stack_regs[e1 as usize] { 1656 | Value::U8(v) => cu1 = v as u64, 1657 | Value::I8(v) => cu1 = v as u64, 1658 | Value::U16(v) => cu1 = v as u64, 1659 | Value::I16(v) => cu1 = v as u64, 1660 | Value::U32(v) => cu1 = v as u64, 1661 | Value::I32(v) => cu1 = v as u64, 1662 | Value::U64(v) => cu1 = v as u64, 1663 | Value::I64(v) => cu1 = v as u64, 1664 | Value::F32(v) => { 1665 | to_f1 = true; 1666 | cf1 = v as f64 1667 | } 1668 | Value::F64(v) => { 1669 | to_f1 = true; 1670 | cf1 = v as f64 1671 | } 1672 | _ => scomp1 = true, 1673 | }; 1674 | let mut cu2: u64 = 0; 1675 | let mut cf2: f64 = 0.0; 1676 | let mut to_f2 = false; 1677 | let mut scomp2 = false; 1678 | match stack_regs[e1 as usize] { 1679 | Value::U8(v) => cu2 = v as u64, 1680 | Value::I8(v) => cu2 = v as u64, 1681 | Value::U16(v) => cu2 = v as u64, 1682 | Value::I16(v) => cu2 = v as u64, 1683 | Value::U32(v) => cu2 = v as u64, 1684 | Value::I32(v) => cu2 = v as u64, 1685 | Value::U64(v) => cu2 = v as u64, 1686 | Value::I64(v) => cu2 = v as u64, 1687 | Value::F32(v) => { 1688 | to_f2 = true; 1689 | cf2 = v as f64 1690 | } 1691 | Value::F64(v) => { 1692 | to_f2 = true; 1693 | cf2 = v as f64 1694 | } 1695 | _ => scomp2 = true, 1696 | }; 1697 | if scomp1 || scomp2 { 1698 | panic!("ERROR LT COULD NOT COMPARE NON VALUE TYPE") 1699 | } else if to_f1 || to_f2 { 1700 | if to_f1 && !to_f2 { 1701 | stack_regs[e3 as usize] = Value::Boolean(cf1 <= cu2 as f64); 1702 | } else if to_f2 && !to_f1 { 1703 | stack_regs[e3 as usize] = Value::Boolean(cf2 <= cu1 as f64); 1704 | } else { 1705 | stack_regs[e3 as usize] = Value::Boolean(cf1 <= cf2); 1706 | } 1707 | } else { 1708 | stack_regs[e3 as usize] = Value::Boolean(cu1 <= cu2); 1709 | } 1710 | } 1711 | _ if ins == OpCode::GTEQ as u16 => { 1712 | let mut cu1: u64 = 0; 1713 | let mut cf1: f64 = 0.0; 1714 | let mut to_f1 = false; 1715 | let mut scomp1 = false; 1716 | match stack_regs[e1 as usize] { 1717 | Value::U8(v) => cu1 = v as u64, 1718 | Value::I8(v) => cu1 = v as u64, 1719 | Value::U16(v) => cu1 = v as u64, 1720 | Value::I16(v) => cu1 = v as u64, 1721 | Value::U32(v) => cu1 = v as u64, 1722 | Value::I32(v) => cu1 = v as u64, 1723 | Value::U64(v) => cu1 = v as u64, 1724 | Value::I64(v) => cu1 = v as u64, 1725 | Value::F32(v) => { 1726 | to_f1 = true; 1727 | cf1 = v as f64 1728 | } 1729 | Value::F64(v) => { 1730 | to_f1 = true; 1731 | cf1 = v as f64 1732 | } 1733 | _ => scomp1 = true, 1734 | }; 1735 | let mut cu2: u64 = 0; 1736 | let mut cf2: f64 = 0.0; 1737 | let mut to_f2 = false; 1738 | let mut scomp2 = false; 1739 | match stack_regs[e1 as usize] { 1740 | Value::U8(v) => cu2 = v as u64, 1741 | Value::I8(v) => cu2 = v as u64, 1742 | Value::U16(v) => cu2 = v as u64, 1743 | Value::I16(v) => cu2 = v as u64, 1744 | Value::U32(v) => cu2 = v as u64, 1745 | Value::I32(v) => cu2 = v as u64, 1746 | Value::U64(v) => cu2 = v as u64, 1747 | Value::I64(v) => cu2 = v as u64, 1748 | Value::F32(v) => { 1749 | to_f2 = true; 1750 | cf2 = v as f64 1751 | } 1752 | Value::F64(v) => { 1753 | to_f2 = true; 1754 | cf2 = v as f64 1755 | } 1756 | _ => scomp2 = true, 1757 | }; 1758 | if scomp1 || scomp2 { 1759 | panic!("ERROR LT COULD NOT COMPARE NON VALUE TYPE") 1760 | } else if to_f1 || to_f2 { 1761 | if to_f1 && !to_f2 { 1762 | stack_regs[e3 as usize] = Value::Boolean(cf1 >= cu2 as f64); 1763 | } else if to_f2 && !to_f1 { 1764 | stack_regs[e3 as usize] = Value::Boolean(cf2 >= cu1 as f64); 1765 | } else { 1766 | stack_regs[e3 as usize] = Value::Boolean(cf1 >= cf2); 1767 | } 1768 | } else { 1769 | stack_regs[e3 as usize] = Value::Boolean(cu1 >= cu2); 1770 | } 1771 | } 1772 | 1773 | _ if ins == OpCode::JMP as u16 => { 1774 | pc = e1 - 1; 1775 | } 1776 | _ if ins == OpCode::JPE as u16 => { 1777 | if let Value::Boolean(b) = stack_regs[e1 as usize] { 1778 | if b { 1779 | pc = e2 - 1; 1780 | } 1781 | } else { 1782 | panic!("ERROR! JPE COULD NOT PASS NON BOOLEAN VALUE") 1783 | } 1784 | } 1785 | _ if ins == OpCode::JPN as u16 => { 1786 | if let Value::Boolean(b) = stack_regs[e1 as usize] { 1787 | if !b { 1788 | pc = e2 - 1; 1789 | } 1790 | } else { 1791 | panic!("ERROR! JPN COULD NOT PASS NON BOOLEAN VALUE") 1792 | } 1793 | } 1794 | _ if ins == OpCode::ARGS as u16 => { 1795 | state.args.push(stack_regs[e1 as usize]); 1796 | } 1797 | _ if ins == OpCode::CALL as u16 => { 1798 | state.return_value = None; 1799 | state.return_values = vec![]; 1800 | if let Value::NSValue(n) = stack_regs[e1 as usize] { 1801 | if let NSValue::Closure(c) = n { 1802 | // save status 1803 | state.current_function_call_state.registers = stack_regs.to_vec(); 1804 | state.current_function_call_state.pc = pc; 1805 | // push current function to function call stack 1806 | state 1807 | .function_call_chain_states 1808 | .push(state.current_function_call_state.clone()); 1809 | // change current function 1810 | state.current_function_call_state = unsafe { c.as_ref() }.clone(); 1811 | // copy args into function args 1812 | continue 'main_interpreter; 1813 | } 1814 | } 1815 | // TODO: implement gc closure call 1816 | } 1817 | _ if ins == OpCode::GETRET as u16 => { 1818 | if let Some(ret) = state.return_value { 1819 | stack_regs[e1 as usize] = ret; 1820 | } else { 1821 | stack_regs[e1 as usize] = Value::Undef; 1822 | } 1823 | state.return_value = None; 1824 | } 1825 | _ if ins == OpCode::RET as u16 => { 1826 | if e1 == 0xFFFF { 1827 | state.return_value = None; 1828 | } else { 1829 | state.return_value = Some(stack_regs[e1 as usize]); 1830 | } 1831 | state.current_function_call_state.clean_stack_values(); 1832 | if let Some(cls) = state.function_call_chain_states.pop() { 1833 | state.current_function_call_state = cls; 1834 | state.current_function_call_state.pc += 1; 1835 | continue 'main_interpreter; 1836 | } 1837 | // the outer 1838 | else { 1839 | return; 1840 | } 1841 | } 1842 | _ if ins == OpCode::RETN as u16 => { 1843 | state.return_values.push(stack_regs[e1 as usize]); 1844 | } 1845 | _ if ins == OpCode::ERROR as u16 => { 1846 | state.current_function_call_state.status = VMClosureStatus::Error; 1847 | } 1848 | _ => unimplemented!(), 1849 | } 1850 | 1851 | pc += 1; 1852 | } 1853 | 1854 | // restore status 1855 | state.current_function_call_state = state.current_function_call_state; 1856 | } 1857 | } 1858 | --------------------------------------------------------------------------------