Skip to content

tinyBigGAMES/NitroVM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

8 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

NitroVM

License Platform Delphi Version

A High-Performance Virtual Machine for Delphi

๐Ÿšง NitroVM is a Work in Progress

NitroVM is currently under active development and evolving quickly. Some features described in this documentation may be incomplete, experimental, or subject to significant changes as the project matures.

We welcome your feedback, ideas, and issue reports โ€” your input will directly influence the direction and quality of NitroVM as we strive to build the ultimate modern Pascal development platform.

Overview

NitroVMโ„ข is a sophisticated, high-performance virtual machine designed specifically for modern Delphi applications. It provides a comprehensive platform for executing custom bytecode with dynamic module loading, external DLL integration, cross-platform support, and hot reloading capabilities. Built with enterprise-grade architecture, NitroVM enables developers to create extensible, modular applications with unprecedented flexibility.

๐ŸŒŸ Key Features

๐Ÿš€ High-Performance Execution

  • Stack-based virtual machine with optimized bytecode execution
  • Native calling conventions with Windows x64 ABI support
  • Separate opcode and operand arrays for cache efficiency
  • Inline critical paths with minimal memory allocations

๐Ÿ“ฆ Dynamic Module System

  • Load and create modules at runtime (.nvmm format)
  • Hot reloading of modules without stopping execution
  • Cross-module function calls with symbol resolution
  • Persistent module storage with dependency management

๐ŸŒ Universal External Integration

  • Call any external DLL/shared library function
  • Automatic type marshalling between Pascal and native types
  • Native memory allocation and pointer manipulation
  • Platform abstraction layer ready for Windows/Linux/macOS (Linux and macOS coming soon)

๐Ÿ”ง Advanced Type System

  • Complete Pascal type support with RTTI integration
  • Automatic serialization/deserialization of complex types
  • Arrays, records, variants, and custom types
  • Type-safe stack operations with runtime validation

๐Ÿ”„ Development-Friendly Features

  • Fluent interface for elegant code construction
  • Step-by-step debugging and execution control
  • Comprehensive error handling with VM state information
  • Program persistence with binary format (.nvmp)

Requirements

  • Platform: Windows 64-bit (Linux x64 and macOS x64 coming in future releases)
  • Compiler: Delphi 12 Athens or higher
  • Dependencies: None (self-contained)

Installation

  1. Clone the repository:
git clone https://github.com/tinyBigGAMES/NitroVM.git
  1. Add the source files to your Delphi project:

    • NitroVM.pas - Main virtual machine unit
    • NitroVM.Platform.pas - Platform abstraction layer
  2. Add NitroVM to your uses clause:

uses
  NitroVM;

Quick Start

Basic VM Operations

uses
  NitroVM;

var
  LVM: TNitroVM;
  LResult: TNVMValue;
begin
  LVM := TNitroVM.Create();
  try
    // Build and execute a simple program
    LVM.BeginProgram()
       .AddInstruction(NVM_OP_PUSH, TNVMValue.From<Int32>(42))
       .AddInstruction(NVM_OP_PUSH, TNVMValue.From<Int32>(10))
       .AddInstruction(NVM_OP_ADD_INT32)
       .AddInstruction(NVM_OP_STOP)
       .ExecuteProgram();
    
    // Get result
    LResult := LVM.Pop();
    WriteLn('Result: ', LResult.AsType<Int32>()); // Output: 52
  finally
    LVM.Free();
  end;
end;

Dynamic Module Creation

var
  LVM: TNitroVM;
  LModule: TNVMModule;
  LResult: TNVMValue;
begin
  LVM := TNitroVM.Create();
  try
    // Create a new module with a function
    LModule := LVM.CreateModule('MathLib');
    
    LVM.BeginModuleBuilder(LModule)
       .BeginFunction('Add', 2)
       .AddModuleInstruction(LModule, NVM_OP_ADD_INT32)
       .AddModuleInstruction(LModule, NVM_OP_RETURN)
       .EndFunction()
       .EndModuleBuilder(LModule)
       .RegisterCreatedModule(LModule);
    
    // Call the module function
    LResult := LVM.CallModuleFunction('MathLib', 'Add', [25, 17]);
    WriteLn('25 + 17 = ', LResult.AsType<Int32>()); // Output: 42
  finally
    LVM.Free();
  end;
end;

External DLL Integration

var
  LVM: TNitroVM;
  LResult: TNVMValue;
begin
  LVM := TNitroVM.Create();
  try
    // Load Windows API
    LVM.LoadExternalLibrary('user32.dll');
    LVM.RegisterExternalFunction('MessageBoxW', 'user32.dll');
    
    // Call MessageBox function
    LResult := LVM.CallExternalFunction('MessageBoxW', [
      0,                                    // hWnd
      PWideChar('Hello from NitroVM!'),     // lpText
      PWideChar('NitroVM Demo'),            // lpCaption
      0                                     // uType
    ]);
    
    WriteLn('MessageBox result: ', LResult.AsType<Int64>());
  finally
    LVM.Free();
  end;
end;

Architecture

Stack-Based Execution Model

NitroVM uses a stack-based architecture where all operations manipulate values on an execution stack:

// Stack operations
LVM.Push(TNVMValue.From<Integer>(42))      // Push integer
   .Push(TNVMValue.From<String>('Hello'))  // Push string
   .Push(TNVMValue.From<Double>(3.14));    // Push double

// Stack inspection
LSize := LVM.StackSize();                 // Get current size
LTop := LVM.Peek(0);                      // Peek at top (index 0)
LSecond := LVM.Peek(1);                   // Peek at second (index 1)

// Pop values
LValue := LVM.Pop();                      // Pop and return value
LVM.ClearStack();                         // Clear all values

Module System Architecture

The module system provides dynamic loading and execution of bytecode modules:

// Load module from file
LModule := LVM.LoadModule('MyLibrary.nvmm');

// Create module programmatically
LModule := LVM.CreateModule('CustomLib')
              .BeginModuleBuilder()
              .AddModuleInstruction(NVM_OP_PUSH, TNVMValue.From<String>('Module loaded!'))
              .AddModuleInstruction(NVM_OP_WRITELN)
              .EndModuleBuilder()
              .RegisterCreatedModule();

// Hot reload support
if LVM.CanHotReload('MyLibrary') then
begin
  LVM.StartHotReload();
  LVM.ReloadModule('MyLibrary');
  LVM.CompleteHotReload();
end;

External Integration Architecture

NitroVM provides seamless integration with external libraries through platform abstraction:

// Cross-platform library loading
LHandle := LVM.LoadExternalLibrary('mylib'); // Automatically adds .dll/.so/.dylib

// Native memory management
LPtr := LVM.AllocateNativeMemory(1024);
try
  // Use native memory...
  FillChar(LPtr^, 1024, 0);
finally
  LVM.FreeNativeMemory(LPtr);
end;

// Type marshalling
LNativeValue := LVM.MarshalToNative(LPascalValue, etInt32);
LPascalValue := LVM.MarshalFromNative(LNativePtr, etString);

Standard Opcodes

Stack Operations

Opcode Name Description
0 NVM_OP_NOP No operation
1 NVM_OP_STOP Stop execution
2 NVM_OP_PUSH Push operand value onto stack
3 NVM_OP_POP Pop and discard top value
4 NVM_OP_DUP Duplicate top stack value
5 NVM_OP_SWAP Swap top two stack values

Arithmetic Operations

Opcode Name Description
10 NVM_OP_ADD_INT32 Add two Int32 values
11 NVM_OP_SUB_INT32 Subtract two Int32 values
12 NVM_OP_MUL_INT32 Multiply two Int32 values
13 NVM_OP_DIV_INT32 Divide two Int32 values
14 NVM_OP_MOD_INT32 Modulo two Int32 values
15 NVM_OP_NEG_INT32 Negate Int32 value

Double Precision Operations

Opcode Name Description
20 NVM_OP_ADD_DOUBLE Add two Double values
21 NVM_OP_SUB_DOUBLE Subtract two Double values
22 NVM_OP_MUL_DOUBLE Multiply two Double values
23 NVM_OP_DIV_DOUBLE Divide two Double values
24 NVM_OP_NEG_DOUBLE Negate Double value

String Operations

Opcode Name Description
30 NVM_OP_CONCAT_STR Concatenate two strings
31 NVM_OP_LENGTH_STR Get string length
32 NVM_OP_SUBSTR Get substring

Comparison Operations

Opcode Name Description
40-45 NVM_OP_EQ/NE/LT/LE/GT/GE_INT32 Integer comparisons
50-55 NVM_OP_EQ/NE/LT/LE/GT/GE_DOUBLE Double comparisons
60-61 NVM_OP_EQ/NE_STR String comparisons

Logical Operations

Opcode Name Description
70 NVM_OP_AND_BOOL Logical AND
71 NVM_OP_OR_BOOL Logical OR
72 NVM_OP_NOT_BOOL Logical NOT

Control Flow

Opcode Name Description
80 NVM_OP_JUMP Unconditional jump
81 NVM_OP_JUMP_TRUE Jump if true
82 NVM_OP_JUMP_FALSE Jump if false
83 NVM_OP_CALL Call function
84 NVM_OP_RETURN Return from function
85 NVM_OP_EXIT Exit program

Variable Operations

Opcode Name Description
90 NVM_OP_LOAD_VAR Load variable value
91 NVM_OP_STORE_VAR Store variable value
92 NVM_OP_LOAD_GLOBAL Load global variable
93 NVM_OP_STORE_GLOBAL Store global variable

Module Operations

Opcode Name Description
100 NVM_OP_LOAD_MODULE Load .nvmm module
101 NVM_OP_CALL_MODULE Call function in module
102 NVM_OP_CALL_RESOLVED Call with pre-resolved symbol ID
103 NVM_OP_RETURN_MODULE Return from cross-module call
104 NVM_OP_UNLOAD_MODULE Unload module
105 NVM_OP_GET_SYMBOL Get symbol address
106 NVM_OP_HOT_RELOAD Hot reload module

Built-in Functions

Opcode Name Description
110 NVM_OP_WRITELN WriteLn output
111 NVM_OP_READLN ReadLn input
112 NVM_OP_INT_TO_STR Convert integer to string
113 NVM_OP_STR_TO_INT Convert string to integer
114 NVM_OP_DOUBLE_TO_STR Convert double to string
115 NVM_OP_STR_TO_DOUBLE Convert string to double

External Call Operations

Opcode Name Description
120 NVM_OP_LOAD_LIBRARY Load external DLL
121 NVM_OP_UNLOAD_LIBRARY Unload external DLL
122 NVM_OP_REGISTER_EXTERNAL Register external function
123 NVM_OP_CALL_EXTERNAL Call external function
124 NVM_OP_ALLOC_NATIVE Allocate native memory
125 NVM_OP_FREE_NATIVE Free native memory
126 NVM_OP_MARSHAL_TO_NATIVE Marshal Pascal value to native
127 NVM_OP_MARSHAL_FROM_NATIVE Marshal native value to Pascal
128 NVM_OP_GET_PROC_ADDRESS Get function address from DLL
129 NVM_OP_REGISTER_CALLBACK Register Pascal callback

File Formats

Module Format (.nvmm)

NitroVM modules use a binary format with the following structure:

Header (48 bytes):
  Magic: 'NVM1' (4 bytes)
  Version: Format version (2 bytes)
  Flags: Module type flags (2 bytes)
  CodeSize: Number of opcodes (4 bytes)
  DataSize: Number of operands (4 bytes)
  ExportCount: Number of exported symbols (4 bytes)
  ImportCount: Number of imported symbols (4 bytes)
  EntryPoint: Module initialization entry point (4 bytes)
  ModuleNameOffset: Offset to module name (4 bytes)
  Checksum: Header + code checksum (4 bytes)
  Reserved: Future expansion (16 bytes)

Data Sections:
  Module Name: Length-prefixed UTF-16 string
  Bytecode: Encoded opcodes array
  Operands: RTTI-serialized operand values
  Exports: Function export table
  Imports: Import dependency table
  External Libraries: Required DLL dependencies
  External Functions: Function-to-library mappings

Program Format (.nvmp)

Complete programs with multiple modules and external dependencies:

Program File Structure:
  Module Count: Number of embedded modules (4 bytes)
  Modules: Array of serialized module data
  Library Count: Number of external libraries (4 bytes)
  Libraries: Array of library names
  Function Count: Number of external functions (4 bytes)
  Functions: Function-to-library mappings
  Program State: VM execution state
  Bytecode: Integrated program opcodes
  Operands: Integrated program operands

Library Format (.nvml)

Library collections containing multiple related modules:

Library File Structure:
  Module Count: Number of modules in library (4 bytes)
  Module Entries: Array of:
    Name Length: Module name length (4 bytes)
    Name: Module name string
    Data Size: Module data size (4 bytes)
    Data: Complete module binary data

Advanced Features

Custom Opcode Registration

Register your own opcodes for domain-specific operations:

// Opcode without operand
LVM.RegisterOpcode(200, procedure(const AVM: TNitroVM)
  begin
    // Custom operation
    AVM.Push(TNVMValue.From<String>('Custom opcode executed!'));
  end);

// Opcode with operand
LVM.RegisterOpcode(201, procedure(const AVM: TNitroVM; const AOperand: TNVMValue)
  begin
    // Process operand and push result
    AVM.Push(AOperand);
  end);

Step-by-Step Debugging

// Execute one instruction at a time
while LVM.IsRunning() and not LVM.IsHalted() do
begin
  WriteLn('PC: ', LVM.GetProgramCounter(), ' Stack: ', LVM.StackSize());
  
  LVM.ExecuteStep();
  
  // Implement breakpoints, variable inspection, etc.
  if LVM.GetProgramCounter() = LBreakpoint then
  begin
    WriteLn('Breakpoint hit!');
    // Inspect VM state...
  end;
end;

// Limited execution with step count
LVM.ExecuteUntil(1000); // Execute maximum 1000 instructions

Program Persistence

// Save complete program with all modules and dependencies
LVM.SaveProgram('myapp.nvmp');

// Load and restore complete state
LVM.Reset()
   .LoadProgram('myapp.nvmp')
   .ExecuteProgram();

// Save/load individual modules
LModule.SaveToFile('mathlib.nvmm');
LLoadedModule := LVM.LoadModule('mathlib.nvmm');

// Save/load module collections
LVM.SaveLibrary('utilities.nvml');
LVM.LoadLibrary('utilities.nvml');

Cross-Platform Library Loading

// Currently supported: Windows
{$IFDEF MSWINDOWS}
  LVM.LoadExternalLibrary('kernel32.dll');
  LVM.RegisterExternalFunction('GetCurrentProcessId', 'kernel32.dll');
{$ENDIF}

// Planned for future releases:
{$IFDEF LINUX}
  LVM.LoadExternalLibrary('libc.so.6');
  LVM.RegisterExternalFunction('getpid', 'libc.so.6');
{$ENDIF}

{$IFDEF MACOS}
  LVM.LoadExternalLibrary('libSystem.dylib');
  LVM.RegisterExternalFunction('getpid', 'libSystem.dylib');
{$ENDIF}

// Platform information (works on all platforms)
WriteLn('Platform: ', NVMGetPlatformName());        // Windows/Linux/macOS
WriteLn('Architecture: ', NVMGetArchitectureName()); // x64/x86/ARM64
WriteLn('Library ext: ', NVMGetLibraryExtension());  // .dll/.so/.dylib

Error Handling and Debugging

NitroVM provides comprehensive error information with VM state:

try
  LVM.ExecuteProgram();
except
  on E: ENVMException do
  begin
    WriteLn('VM Error: ', E.Message);
    WriteLn('Error Category: ', E.ErrorCategory);
    
    if E.HasVMState then
    begin
      WriteLn('Program Counter: ', E.VMProgramCounter);
      WriteLn('Stack Size: ', E.VMStackSize);
      WriteLn('Current Module: ', E.VMCurrentModule);
      WriteLn('Execution State: ', E.VMExecutionState);
    end;
    
    if E.HasOpcodeInfo then
      WriteLn('Current Opcode: ', E.VMOpcode);
    
    // Get detailed debug information
    WriteLn('Debug Info: ', E.GetVMDebugInfo());
    WriteLn('Detailed Message: ', E.GetDetailedMessage());
  end;
end;

Variable Management

// Global variables
LVM.SetVariable('GlobalCounter', TNVMValue.From<Integer>(0));
LCounter := LVM.GetVariable('GlobalCounter');

// Check variable existence
if LVM.HasVariable('MyVar') then
  WriteLn('Variable exists: ', LVM.GetVariable('MyVar').AsType<String>());

// Local scope management (automatic with function calls)
// Variables are automatically scoped to function call frames

Native Memory Operations

// Allocate native memory block
LPtr := LVM.AllocateNativeMemory(4096);
try
  // Direct memory access
  PInteger(LPtr)^ := 42;
  WriteLn('Value: ', PInteger(LPtr)^);
  
  // Reallocate if needed
  LPtr := LVM.ReallocateNativeMemory(LPtr, 8192);
  
  // Check memory validity
  if LVM.IsNativeMemoryValid(LPtr) then
    WriteLn('Memory block is valid');
    
finally
  LVM.FreeNativeMemory(LPtr);
end;

// Memory statistics
WriteLn('Total memory usage: ', LVM.GetMemoryUsage(), ' bytes');
WriteLn('Active memory blocks: ', Length(LVM.GetAllocatedMemoryBlocks()));

Performance Considerations

  • Separate Arrays: Opcodes and operands stored separately for optimal cache usage
  • Inline Functions: Critical execution paths use inlined methods for speed
  • Minimal Allocations: Pre-allocated arrays and efficient memory management
  • Direct Dispatch: Fast opcode handler lookup without virtual method calls
  • Native Calling: Direct calling conventions for external functions
  • Symbol Caching: O(1) symbol resolution with pre-computed lookup tables

Cross-Platform Support

NitroVM is designed with cross-platform support in mind through the NitroVM.Platform abstraction layer:

Currently Supported:

  • Windows x64: Full support with Windows API integration and x64 calling convention

Planned for Future Releases:

  • Linux x64: System V ABI calling convention and shared library support
  • macOS x64: Native macOS support with dylib integration

The platform abstraction layer is already in place to handle cross-platform differences:

// Platform detection (works on all platforms)
WriteLn('Running on: ', NVMGetPlatformName());        // Windows/Linux/macOS
WriteLn('Architecture: ', NVMGetArchitectureName());   // x64/x86/ARM64
WriteLn('64-bit platform: ', NVMIs64BitPlatform());

// Platform-specific operations are abstracted
LHandle := NVMLoadLibrary('mylib');  // Will handle .dll/.so/.dylib
LFuncPtr := NVMGetProcAddress(LHandle, 'MyFunction');
LResult := NVMCallExternalFunction(LFuncPtr, @LParams[0], LParamCount);

Current Windows-specific example:

// Windows API access (currently supported)
LVM.LoadExternalLibrary('kernel32.dll');
LVM.RegisterExternalFunction('GetCurrentProcessId', 'kernel32.dll');
LResult := LVM.CallExternalFunction('GetCurrentProcessId', []);

Future Linux/macOS support will include:

{$IFDEF LINUX}
  LVM.LoadExternalLibrary('libc.so.6');
  LVM.RegisterExternalFunction('getpid', 'libc.so.6');
{$ENDIF}

{$IFDEF MACOS}
  LVM.LoadExternalLibrary('libSystem.dylib');
  LVM.RegisterExternalFunction('getpid', 'libSystem.dylib');
{$ENDIF}

๐Ÿ† Contributors

Join our growing community of developers building the future of Pascal development!

๐Ÿ“„ License

This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.

BSD 3-Clause License

Copyright ยฉ 2025-present tinyBigGAMESโ„ข LLC
All Rights Reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice
2. Redistributions in binary form must reproduce the above copyright notice
3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

๐Ÿ“ž Support & Community

๐Ÿ’ฌ Community Channels

๐ŸŒŸ Acknowledgments

  • ๐Ÿ’– Built with love for the Delphi community
  • ๐Ÿš€ Focused on practical, real-world usage scenarios
  • ๐Ÿ† Committed to enterprise-grade quality and performance
  • ๐ŸŒ Supporting the future of Pascal application development

๐ŸŽ–๏ธ Special Thanks

  • Delphi Community - For continued support and feedback
  • Beta Testers - Early adopters who helped shape NitroVM
  • Contributors - Everyone who has submitted issues, PRs, and improvements

Made with โค๏ธ by tinyBigGAMESโ„ข

NitroVM - Powering the next generation of Delphi applications with high-performance virtual machine technology.

About

A High-Performance Virtual Machine for Delphi

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Languages