Skip to content

soteenstudio/lightvm

LightVM

Tagline

build status npm version nightly version total downloads github stars repo size license

A capability-based virtual machine designed for secure, predictable, and optimized bytecode execution.

The Philosophy: Deterministic & Lean

LightVM is built with a focus on execution transparency and resource efficiency:

  • Zero Magic (Deterministic): Instruction execution is linear and completely predictable. The VM operates explicitly, executing instructions exactly as they are defined.
  • Resource Conscious: Designed with a minimal memory footprint through the use of optimized data structures such as SmolStr and ahash for fast metadata management.
  • Explicit Security: Security is managed through a strict Capability system. Every VM access and operation must have permissions explicitly defined by the host from the outset.

AOT Optimization Process

LightVM isn't just a simple interpreter. Before execution, your bytecode undergoes a multi-pass optimization to ensure maximum performance and minimal footprint:

  • Constant Folding: Pre-calculates math and logic operations (e.g., Add, Sub, Xor, Concat) if the values are known at compile-time.
  • Conversion & Metadata Folding: Pre-evaluates type casting (e.g., ToInteger, ToString) and metadata checks like TypeOf to eliminate redundant runtime work.
  • Strength Reduction: Replaces "heavy" operations with lighter ones, such as converting multiplication by powers of two into bitwise Shl (Shift Left).
  • Dead Store Elimination: Analyzes variable usage and automatically removes Push, Set, or Inc operations that don't contribute to the final program state.
  • Dead Loop Elimination: Identifies and prunes "pure" loops that have no side effects (no I/O, calls, or returns), preventing unnecessary CPU cycles.
  • Redundant Load Elimination: Detects consecutive attempts to load identical values or variables onto the stack and replaces redundant operations with a high-performance Dup instruction to minimize memory access overhead.
  • Jump Optimization: Detects and removes redundant Jump instructions that point to the very next line of code.
  • Jump Threading: Optimizes control flow by collapsing chains of redirection, where a jump leads directly to another jump, ensuring the instruction pointer bypasses intermediate hops to reach the final destination immediately.

Getting Started

Installation

Installation with NPM
npm install lightvm

# or
npm install lightvm@next
Installation with Yarn
yarn add lightvm

# or
yarn add lightvm@next
Installation with Cargo
cargo add lightvm

Quick Usage

Using TypeScript:
import { LightVM, Capability } from 'lightvm';

const caps = [Capability.Control, Capability.Observe];

const vm = new LightVM(caps);
Using Rust:
use lightvm::LightVM;
use lightvm::types::capability::Capability;

fn main() {
    let caps = vec![Capability::Control, Capability::Observe];
    
    let mut vm = LightVM::new(caps);
}

Virtual Machine Capabilities

LightVM uses a strict capability-based security model. You must explicitly grant permissions when instantiating the VM.

Capability Level Description
Control Low Grants permission to start/stop execution and export functions.
Observe Medium Allows the host to inspect internal states, variable stacks, and metrics.
Debug High Opens access to verbose internal logs and hidden states for troubleshooting.
Unsafe Critical Removes safety guards, allowing manual halts and raw memory/process access.

How to use

  1. run() method:
    Permission to start bytecode execution.

    TypeScript:
    const raw = [
      ["push", 5],
      ["val", "x"],
      ["set", "x"]
    ];
    vm.load(vm.tools().optimizeBytecode(JSON.stringify(raw)))
      .run();
    Rust:
    let raw = serde_json::json!([
      ["push", 5],
      ["val", "x"],
      ["set", "x"]
    ]);
    LightVM::tools().optimize_bytecode(raw)
      .map(|opt| vm.load(serde_json::from_str(&opt).unwrap()).run(None))
      .expect("Optimization failed");

Note

Capability Required: control
Info: parameters of load() can change bytecode directly or file path to .ltc

  1. provide() method:
    Permission to inject data/variables into the VM.

    TypeScript:
    vm.provide("identity", {
      name: "John Doe", 
      force: "2021",
    });
    Rust:
    vm.provide("identity".to_string(), serde_json::json!({
        "name": "John Doe",
        "force": "2021"
    }));

Note

Capability Required: no spesific capability

  1. inspect() method:
    Permission to view state, number of instructions, and capability.

    TypeScript:
    const report = vm.inspect();
    console.log(report);
    Rust:
    let report = vm.inspect();
    println!("{}", serde_json::to_string_pretty(&report).unwrap());

Note

Capability Required: observe

  1. halt() method:
    Permission to force/manually stop VM.

    TypeScript:
    vm.halt();
    console.log("The VM has been terminated.")
    Rust:
    vm.halt();
    println!("The VM has been terminated.");

Note

Capability Required: unsafe

  1. export() method:
    Permission to export functions in the VM out.

    TypeScript:
    const add = vm.export("add");
    console.log(add(5, 6));
    Rust:
    let mut add = vm.export("add".to_string());
    let args = vec![serde_json::json!(5), serde_json::json!(6)];
    if let Some(hasil) = add_func(args) {
        println!("Hasil dari VM: {}", hasil);
    }

Note

Capability Required: control

References

Supported Primitive Types

LightVM requires explicit type definitions for certain instructions to maintain deterministic execution and peak performance.

Type Aliases Reference Target Value Type
sht i16 Short 16-bit Integer (Int16)
int i32 Integer 32-bit Integer (Int32)
lng i64 Long 64-bit Integer (Int64)
oct i128 Octa 128-bit Integer (Int128)
hlf f16 Half 16-bit Floating Point (Float16)
flt f32 Float 32-bit Floating Point (Float32)
dbl f64 Double 64-bit Floating Point (Float64)
str - String String / Text data

Warning

Preview Type: hlf (Half-precision) is currently in Preview. It's more stable than Nightly but may still undergo refinements or behavior changes.

Bytecode Instructions

LightVM has a total of 40+ instructions for bytecode.

  1. Stack & Variable Management
    A group of instructions for basic data manipulation and memory (variable) allocation.
Opcode Arguments Description
push value Inserting data into the stack
val name Declaring a new variable
set name Take the top stack and then save it to the variable name
get name Take the contents of the name variable and push it onto the stack
dup - Duplicate the top value in the stack
  1. Arithmetic & Logic
    Instructions for calculations. Note that for optimization, these instructions require a PrimitiveTypes (sht, hlf, int, flt, lng, dbl) to prevent the VM from guessing the data type during execution.
Opcode Arguments Description
add / sub type Addition or Subtraction
mul / div type Multiplication or Division
mod type Modulo (Remainder)
inc / dec name, type Directly add/remove variable contents (without going through the stack)
gt / lt type Greater Than or Less Than
ge / le type Greater/Less Than or Equal
eq / neq type Equal or Not Equal
shl / shr type Shift Left or Shift Right bitwise operation based on data type
rol / ror type Circular Shift Left or Right (Rotate) bitwise operation based on data type
and / or - Boolean logic operations (&& / ||)
xor - Bitwise Exclusive OR operation between two values
not - Bitwise NOT (Inversion) operation on a single value

Note

Specific Opcode: shl, shr, rol, and ror only accepts sht, int, and lng types from PrimitiveTypes.

  1. Control Flow & Function
    Instructions for managing program flow, looping, and function calls.
Opcode Arguments Description
jump target_ip Jump to a specific instruction line (Instruction Pointer)
if_false target_ip Jump if the value on the stack is false
func name, argc, start, end, [params] Function block definition (scope)
call name, argc Call a function with a specified number of arguments
return - Exit the function and return to the caller
stop - Kill all VM processes (Halt)
  1. Data Structures & Metadata
    Create complex data handles like JS Objects or Arrays, plus data type matters.
Opcode Arguments Description
make_obj count Create Object from n key-value pairs in stack
make_array count Create an Array of n elements in a stack
access prop_name Access Object's properties
access_index - Access Array elements by index on the stack
length - Check the length of a string or the number of items in an array/object
typeof - Get the data type from the top value of the stack
concat - Combine two values (usually strings)
  1. Type Casting (Conversion)
    For those of you who want to force a certain data type to ensure consistent performance.
Opcode Description
to_string Change the value to String
to_short Change value to Short (16-bit)
to_integer Change value to Integer (32-bit)
to_long Change the value to Long (64-bit)
to_half Change value to Half-precision (16-bit Float)
to_float Change value to Float (32-bit)
to_double Change the value to Double (64-bit)
  1. Objects & OOP Instructions for handling class instances and modifying object properties dynamically.
Opcode Arguments Description
set_prop prop_name Set the value of an object property (retrieve value and target_obj from the stack)
instantiate class_name, argc Creates a new instance of a class with a specified number of constructor arguments
inspect_obj - Prints the internal structure of an Object to the console
inspect_array - Print the internal contents of an Array to the console

Warning

Nightly Opcode: The instantiate instruction is still experimental. The API may change without notice in the @next version.

  1. Module & Export System Instructions for communication between modules or with external runtimes.
Opcode Arguments Description
import module_name, alias_idx Importing external libraries/modules into a specific variable index
export name Mark a function or variable to be accessible from outside the VM

Warning

Nightly Opcode: The export and import instructions are still experimental. The API may change without notice in the @next version.

  1. Basic I/O & Loop Control Instructions for standard output and more specific iteration control.
Opcode Arguments Description
print - Prints the top value of the stack to the console without a newline
println - Prints the top value of the stack to the console with a newline
break target_ip Stops the loop and jumps to the specified target_ip
nop - Empty instructions (usually for placeholders or alignment)

Supported Architectures

LightVM supports a wide range of platforms and architectures to ensure maximum operational flexibility. Here's the current compatibility list:

OS / Runtime Architecture Toolchain Rust Node.js
Windows x64, ia32 MSVC
Linux x64, ia32, arm64 GNU (glibc)
Linux (musl) x64, ia32, arm64 musl
macOS (Darwin) x64 Apple Clang
Android arm64, arm NDK
FreeBSD x64 Clang

📜 License

This project is distributed using the Apache-2.0 license

Packages

 
 
 

Contributors