Phasor 3.3.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
PhasorVM.hpp
Go to the documentation of this file.
1// Copyright 2026 Daniel McGuire
2// Licensed under the Apache License (with LLVM-Exceptions), Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5// https://llvm.org/LICENSE.txt
6// Unless required by applicable law or agreed to in writing, software
7// distributed under the License is distributed on an "AS IS" BASIS,
8// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9// See the License for the specific language governing permissions and
10// limitations under the License.
11
12// README
13//
14// Because the VM is such a complex component, this readme only covers
15// basic high-level use cases.
16// For more information, please refer to the below, and the internal header
17// at src/Runtime/VM/VM.hpp, as well as the [doxygen](phasor-docs.pages.dev)
18//
19// Usage:
20// ```cpp
21// // Initialize VM
22// Phasor::VM vm;
23// // Run bytecode
24// vm.run(bytecode);
25// ```
26
27#pragma once
28
29#include <vector>
30#include <filesystem>
31#include <functional>
32#include <map>
33#include <array>
34#include <ranges>
35#include <iostream>
36#include <stdexcept>
37#include <memory_resource>
38#include "../phsint.hpp"
39
40#ifndef SANDBOXED
41#include "PhasorFFI.hpp"
42#endif
43#include "PhasorISA.hpp"
44#include "../Value.hpp"
45#include <platform.h>
46
47#define BAD_STATUS -1
48
50namespace Phasor
51{
52
55class VM
56{
57 public:
58 VM();
59 VM(const Bytecode &bytecode);
60 VM(const OpCode &op, const int &operand1 = 0, const int &operand2 = 0, const int &operand3 = 0);
61 ~VM();
62
64 void initFFI(const std::filesystem::path &path);
65
67 std::string getVersion();
68
71 class Halt : public std::exception
72 {
73 public:
74 const char *what() const noexcept override
75 {
76 return "";
77 }
78 };
79
82 int run(const Bytecode &bytecode, const size_t startPC = 0);
83
85 Value runFunction(const std::string &name, const Bytecode &bytecode, const bool &argsInit = false);
86
88 using NativeFunction = std::function<Value(const std::vector<Value> &args, VM *vm)>;
89
91 void registerNativeFunction(const std::string &name, NativeFunction fn);
92
93 using ImportHandler = std::function<void(const std::filesystem::path &path)>;
95 void setImportHandler(const ImportHandler &handler);
96
98 void freeVariable(size_t index);
99
101 void freeVariableByName(const std::string &name);
102
106 size_t addVariable(const Value &value);
107
111 void setVariable(size_t index, const Value &value);
112
114 Value getVariable(size_t index);
115
118
122 void setRegister(u8 index, const Value &value);
123
126 void freeRegister(u8 index);
127
132
136
139 {
140 r0,
141 r1,
142 r2,
143 r3,
144 r4,
145 r5,
146 r6,
147 r7,
148 r8,
149 r9,
150 r10,
151 r11,
152 r12,
153 r13,
154 r14,
155 r15,
156 r16,
157 r17,
158 r18,
159 r19,
160 r20,
161 r21,
162 r22,
163 r23,
164 r24,
165 r25,
166 r26,
167 r27,
168 r28,
169 r29,
170 r30,
171 r31
172 };
173
174#define REGISTER1 VM::Register::r0
175#define REGISTER2 VM::Register::r1
176#define REGISTER3 VM::Register::r2
177
178#ifdef _WIN32
180 Value __fastcall operation(const OpCode &op, const int &operand1 = 0, const int &operand2 = 0,
181 const int &operand3 = 0);
182#else
184 Value operation(const OpCode &op, const int &operand1 = 0, const int &operand2 = 0, const int &operand3 = 0);
185#endif
187 void push(const Value &value);
188
191
194
196 void cleanup();
197
199 void reset(const bool &resetStack = true, const bool &resetFunctions = true, const bool &resetVariables = true);
200
202 std::string getInformation();
203
206
208 void log(const Value &msg);
209
211 void logerr(const Value &msg);
212
214 void flush();
215
217 void flusherr();
218
220 void setStatus(int newStatus);
224
232 template <typename... Args> inline Value regRun(OpCode opcode, Args &&...args)
233 {
234 int regIndex = 0;
235 (setRegister(regIndex++, std::forward<Args>(args)), ...);
236 operation(opcode);
237 return getRegister(REGISTER1);
238 }
239
247 template <typename... Args> inline Value stackRun(OpCode opcode, Args &&...args)
248 {
249 Value arr[] = {Value(std::forward<Args>(args))...};
250 for (Value &v : arr | std::views::reverse)
251 push(v);
252 operation(opcode);
253 return pop();
254 }
255
256 private:
257 void setup(const Bytecode &bc, const size_t initialPC);
258 void evalLoop();
259
260 bool isDirectCall = false;
261
262#ifndef SANDBOXED
264 std::unique_ptr<FFI> ffi;
265#endif
267 int status = 0;
268
270 bool isError = false;
271
274
276 std::array<Value, MAX_REGISTERS> registers;
277
279 std::pmr::monotonic_buffer_resource stack_pool;
280 std::pmr::vector<Value> stack;
281
283 std::vector<int> callStack;
284
286 std::vector<Value> variables;
287
289 const Bytecode *m_bytecode{};
290
292 size_t pc = 0;
293
295 std::map<std::string, NativeFunction> nativeFunctions;
296};
297} // namespace Phasor
#define msg
#define REGISTER1
Definition VM.hpp:154
Expanded opcode set for Phasor VM.
Throws when the HALT opcode is reached.
Definition VM.hpp:52
const char * what() const noexcept override
Definition PhasorVM.hpp:74
std::array< Value, MAX_REGISTERS > registers
Virtual registers for register-based operations (v2.0).
Definition VM.hpp:261
ImportHandler importHandler
Import handler for loading modules.
Definition VM.hpp:258
Value operation(const OpCode &op, const int &operand1=0, const int &operand2=0, const int &operand3=0)
Execute a single operation.
std::vector< Value > variables
Variable storage indexed by variable index, or simply: the managed heap.
Definition VM.hpp:271
std::function< Value(const std::vector< Value > &args, VM *vm)> NativeFunction
Native function signature.
Definition VM.hpp:68
Value pop()
Pop a value from the stack.
void setImportHandler(const ImportHandler &handler)
Set the import handler for importing modules.
Value getRegister(u8 index)
Get a register value.
std::function< void(const std::filesystem::path &path)> ImportHandler
Definition VM.hpp:73
void logerr(const Value &msg)
Log a Value to stderr.
void freeRegister(u8 index)
Free a register (reset to null).
std::string getVersion()
Get Phasor VM version.
VM(const Bytecode &bytecode)
void evalLoop()
std::unique_ptr< FFI > ffi
FFI.
Definition VM.hpp:249
bool isDirectCall
is a direct call to a function
Definition VM.hpp:245
Value getVariable(size_t index)
Get a variable from the VM.
void registerNativeFunction(const std::string &name, NativeFunction fn)
Register a native function.
void setStatus(int newStatus)
Set VM exit code.
bool isErrorStatus()
void freeVariableByName(const std::string &name)
Free a variable by name in the VM.
size_t getVariableCount()
Get the number of variables in the VM.
std::vector< int > callStack
Call stack for function calls.
Definition VM.hpp:268
std::string getBytecodeInformation()
Get bytecode information for debugging.
Register
Enum for registers.
Definition VM.hpp:119
void log(const Value &msg)
Log a Value to stdout.
size_t addVariable(const Value &value)
Add a variable to the VM.
int getStatus()
void flush()
Flush stdout.
VM(const OpCode &op, const int &operand1=0, const int &operand2=0, const int &operand3=0)
std::pmr::vector< Value > stack
Definition VM.hpp:265
bool isError
Is status an error code.
Definition VM.hpp:255
void cleanup()
Clean up the virtual machine.
size_t pc
Program counter.
Definition VM.hpp:277
void push(const Value &value)
Push a value onto the stack.
Value stackRun(OpCode opcode, Args &&...args)
Run an opcode with values pushed to the stack.
Definition PhasorVM.hpp:247
void resetStatus()
void setVariable(size_t index, const Value &value)
Set a variable in the VM.
int run(const Bytecode &bytecode, const size_t startPC=0)
Run the virtual machine Exits -1 on uncaught exception.
void initFFI(const std::filesystem::path &path)
Initialize the FFI plugins.
std::map< std::string, NativeFunction > nativeFunctions
Native function registry.
Definition VM.hpp:280
void setRegister(u8 index, const Value &value)
Set a register value.
const Bytecode * m_bytecode
Bytecode to execute.
Definition VM.hpp:274
void setup(const Bytecode &bc, const size_t initialPC)
std::pmr::monotonic_buffer_resource stack_pool
Stack.
Definition VM.hpp:264
int status
Exit code.
Definition VM.hpp:252
Value regRun(OpCode opcode, Args &&...args)
Run an opcode with arguments pre-loaded into registers.
Definition PhasorVM.hpp:232
Value peek()
Peek at the top value on the stack.
void flusherr()
Flush stderr.
size_t getRegisterCount()
Get the total number of registers.
Value runFunction(const std::string &name, const Bytecode &bytecode, const bool &argsInit=false)
Run a function from bytecode on the virtual machine.
void reset(const bool &resetStack=true, const bool &resetFunctions=true, const bool &resetVariables=true)
Reset the virtual machine.
void freeVariable(size_t index)
Free a variable in the VM.
std::string getInformation()
Get VM information for debugging.
A value in the Phasor VM.
Definition Value.hpp:59
The Phasor Programming Language and Runtime.
Definition AST.hpp:13
uint8_t u8
Definition phsint.hpp:9
OpCode
Definition ISA.hpp:12
Complete bytecode structure.
Definition CodeGen.hpp:50