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
39#ifndef SANDBOXED
40#include "PhasorFFI.hpp"
41#endif
42#include "PhasorISA.hpp"
43#include "../Value.hpp"
44#include <platform.h>
45
47namespace Phasor
48{
49
52class VM
53{
54 public:
55 VM();
56 VM(const Bytecode &bytecode);
57 VM(const OpCode &op, const int &operand1 = 0, const int &operand2 = 0, const int &operand3 = 0);
58 ~VM();
59
61 void initFFI(const std::filesystem::path &path);
62
64 std::string getVersion();
65
68 class Halt : public std::exception
69 {
70 public:
71 const char *what() const noexcept override
72 {
73 return "";
74 }
75 };
76
79 int run(const Bytecode &bytecode, const size_t startPC = 0);
80
82 Value runFunction(const std::string &name, const Bytecode &bytecode);
83
85 using NativeFunction = std::function<Value(const std::vector<Value> &args, VM *vm)>;
86
88 void registerNativeFunction(const std::string &name, NativeFunction fn);
89
90 using ImportHandler = std::function<void(const std::filesystem::path &path)>;
92 void setImportHandler(const ImportHandler &handler);
93
95 void freeVariable(size_t index);
96
98 void freeVariableByName(const std::string &name);
99
103 size_t addVariable(const Value &value);
104
108 void setVariable(size_t index, const Value &value);
109
111 Value getVariable(size_t index);
112
115
119 void setRegister(uint8_t index, const Value &value);
120
123 void freeRegister(uint8_t index);
124
128 Value getRegister(uint8_t index);
129
133
135 enum Register : uint8_t
136 {
137 r0,
138 r1,
139 r2,
140 r3,
141 r4,
142 r5,
143 r6,
144 r7,
145 r8,
146 r9,
147 r10,
148 r11,
149 r12,
150 r13,
151 r14,
152 r15,
153 r16,
154 r17,
155 r18,
156 r19,
157 r20,
158 r21,
159 r22,
160 r23,
161 r24,
162 r25,
163 r26,
164 r27,
165 r28,
166 r29,
167 r30,
168 r31
169 };
170
171#define REGISTER1 VM::Register::r0
172#define REGISTER2 VM::Register::r1
173#define REGISTER3 VM::Register::r2
174
175#ifdef _WIN32
177 Value __fastcall operation(const OpCode &op, const int &operand1 = 0, const int &operand2 = 0,
178 const int &operand3 = 0);
179#else
181 Value operation(const OpCode &op, const int &operand1 = 0, const int &operand2 = 0, const int &operand3 = 0);
182#endif
184 void push(const Value &value);
185
188
191
193 void cleanup();
194
196 void reset(const bool &resetStack = true, const bool &resetFunctions = true, const bool &resetVariables = true);
197
199 std::string getInformation();
200
203
205 void log(const Value &msg);
206
208 void logerr(const Value &msg);
209
211 void flush();
212
214 void flusherr();
215
217 void setStatus(int newStatus);
220
228 template <typename... Args> inline Value regRun(OpCode opcode, Args &&...args)
229 {
230 int regIndex = 0;
231 (setRegister(regIndex++, std::forward<Args>(args)), ...);
232 operation(opcode);
233 return getRegister(REGISTER1);
234 }
235
243 template <typename... Args> inline Value stackRun(OpCode opcode, Args &&...args)
244 {
245 Value arr[] = {Value(std::forward<Args>(args))...};
246 for (Value &v : arr | std::views::reverse)
247 push(v);
248 operation(opcode);
249 return pop();
250 }
251
252 private:
253 void setup(const Bytecode &bc, const size_t initialPC);
254 void evalLoop();
255
256 bool isDirectCall = false;
257
258#ifndef SANDBOXED
260 std::unique_ptr<FFI> ffi;
261#endif
263 int status = 0;
264
267
269 std::array<Value, MAX_REGISTERS> registers;
270
272 std::pmr::monotonic_buffer_resource stack_pool;
273 std::pmr::vector<Value> stack;
274
276 std::vector<int> callStack;
277
279 std::vector<Value> variables;
280
282 const Bytecode *m_bytecode{};
283
285 size_t pc = 0;
286
288 std::map<std::string, NativeFunction> nativeFunctions;
289};
290} // namespace Phasor
#define msg
#define REGISTER1
Definition VM.hpp:151
Expanded opcode set for Phasor VM.
Throws when the HALT opcode is reached.
Definition VM.hpp:49
const char * what() const noexcept override
Definition PhasorVM.hpp:71
Virtual Machine.
Definition VM.hpp:33
std::array< Value, MAX_REGISTERS > registers
Virtual registers for register-based operations (v2.0).
Definition VM.hpp:249
ImportHandler importHandler
Import handler for loading modules.
Definition VM.hpp:246
Value operation(const OpCode &op, const int &operand1=0, const int &operand2=0, const int &operand3=0)
Execute a single operation.
Definition Operations.cpp:8
std::vector< Value > variables
Variable storage indexed by variable index, or simply: the managed heap.
Definition VM.hpp:259
std::function< Value(const std::vector< Value > &args, VM *vm)> NativeFunction
Native function signature.
Definition VM.hpp:65
Value pop()
Pop a value from the stack.
void setImportHandler(const ImportHandler &handler)
Set the import handler for importing modules.
std::function< void(const std::filesystem::path &path)> ImportHandler
Definition VM.hpp:70
void logerr(const Value &msg)
Log a Value to stderr.
std::string getVersion()
Get Phasor VM version.
VM(const Bytecode &bytecode)
void evalLoop()
std::unique_ptr< FFI > ffi
FFI.
Definition VM.hpp:240
bool isDirectCall
is a direct call to a function
Definition VM.hpp:236
Value getVariable(size_t index)
Get a variable from the VM.
void registerNativeFunction(const std::string &name, NativeFunction fn)
Register a native function.
Value getRegister(uint8_t index)
Get a register value.
void setStatus(int newStatus)
Set VM exit code.
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:256
std::string getBytecodeInformation()
Get bytecode information for debugging.
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:253
void cleanup()
Clean up the virtual machine.
Register
Enum for registers.
Definition VM.hpp:116
size_t pc
Program counter.
Definition VM.hpp:265
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:243
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.
void setRegister(uint8_t index, const Value &value)
Set a register value.
std::map< std::string, NativeFunction > nativeFunctions
Native function registry.
Definition VM.hpp:268
Value runFunction(const std::string &name, const Bytecode &bytecode)
Run a function from bytecode on the virtual machine.
void freeRegister(uint8_t index)
Free a register (reset to null).
const Bytecode * m_bytecode
Bytecode to execute.
Definition VM.hpp:262
void setup(const Bytecode &bc, const size_t initialPC)
std::pmr::monotonic_buffer_resource stack_pool
Stack.
Definition VM.hpp:252
int status
Exit code.
Definition VM.hpp:243
Value regRun(OpCode opcode, Args &&...args)
Run an opcode with arguments pre-loaded into registers.
Definition PhasorVM.hpp:228
Value peek()
Peek at the top value on the stack.
void flusherr()
Flush stderr.
size_t getRegisterCount()
Get the total number of registers.
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:58
The Phasor Programming Language and Runtime.
Definition AST.hpp:12
OpCode
Definition ISA.hpp:12
Complete bytecode structure.
Definition CodeGen.hpp:50