13#include <unordered_map>
20 using StackValue = std::variant<int64_t, void *, double, std::string>;
31 data.push_back(value);
47 [[nodiscard]]
bool empty()
const {
return data.empty(); }
50 [[nodiscard]]
size_t size()
const {
return data.size(); }
58 if (index >=
data.size())
59 throw mx::Exception(
"Stack index out of bounds: " + std::to_string(index));
64 std::vector<StackValue>
data;
106 void call(
Program *program, std::vector<Operand> &operands);
111 static std::unordered_map<std::string, void *>
handles;
145 void add_label(
const std::string &
name, uint64_t address,
bool f);
165 void add_extern(
const std::string &mod,
const std::string &
name,
bool module);
173 void add_runtime_extern(
const std::string &mod_name,
const std::string &mod,
const std::string &func_name,
const std::string &
name);
192 std::vector<Instruction>
inc;
193 std::unordered_map<std::string, Variable>
vars;
194 std::unordered_map<std::string, std::pair<uint64_t, bool>>
labels;
200 static std::unordered_map<std::string, Variable>
allocated;
201 static std::unordered_map<std::string, Program *>
object_map;
222 :
Base(std::move(other)),
223 filename(std::move(other.filename)),
224 objects(std::move(other.objects)),
234 args(std::move(other.args)),
237 stack(std::move(other.stack)),
238 result(std::move(other.result)),
242 other.running =
false;
244 for (
auto &var_pair :
vars) {
245 var_pair.second.obj_name =
name;
251 if (
this != &other) {
253 filename = std::move(other.filename);
254 objects = std::move(other.objects);
255 object = other.object;
264 args = std::move(other.args);
267 stack = std::move(other.stack);
268 result = std::move(other.result);
271 other.running =
false;
273 for (
auto &var_pair :
vars) {
274 var_pair.second.obj_name =
name;
295 void print(std::ostream &out);
300 void post(std::ostream &out);
334 void setArgs(
const std::vector<std::string> &
argv);
340 std::vector<std::unique_ptr<Program>>
objects;
830 std::string
printFormatted(
const std::string &format,
const std::vector<Variable *> &
args,
bool output =
true);
General-purpose exception with errno-aware factory method.
static std::unordered_map< std::string, Program * > object_map
object name -> Program mapping
void add_global(const std::string &objname, const std::string &name, const Variable &v)
Declare a global variable scoped to an object.
void add_filename(const std::string &fname)
Record a source filename for debug/error reporting.
std::unordered_map< std::string, std::pair< uint64_t, bool > > labels
label -> (address, is_function)
std::vector< Instruction > inc
instruction stream
void add_runtime_extern(const std::string &mod_name, const std::string &mod, const std::string &func_name, const std::string &name)
Register and resolve a runtime-loaded external function.
void add_variable(const std::string &name, const Variable &v)
Declare a local variable in the symbol table.
void add_allocated(const std::string &name, Variable &v)
Track a heap-allocated variable for cleanup.
void setMainBase(Base *b)
Set the root program base pointer (used for global variable lookup).
void add_extern(const std::string &mod, const std::string &name, bool module)
Register an external function import.
void add_object(const std::string &name, Program *prog)
Register a child object program.
std::unordered_map< std::string, Variable > vars
variable symbol table
std::string assembly_code
generated assembly output for objects
Base & operator=(Base &&other) noexcept
Move-assignment operator.
void add_label(const std::string &name, uint64_t address, bool f)
Register a label at the given instruction address.
static Base * base
pointer to the main program base
static std::vector< std::string > filenames
std::unordered_map< std::string, RuntimeFunction > external_functions
resolved runtime function bindings
static std::unordered_map< std::string, Variable > allocated
heap-allocated variables
void add_instruction(const Instruction &i)
Append an instruction to the instruction stream.
static std::string root_name
std::vector< ExternalFunction > external
declared external function imports
Complete MXVM program: instruction interpreter and native x64 code generator.
Variable createTempVariable(VarType type, const std::string &value)
Create a temporary unnamed variable with the given type and value.
void gen_jp(std::ostream &out, const Instruction &i)
void setVariableFromConstant(Variable &var, const std::string &value)
Set a variable's value from a constant string (integer, float, or string literal).
void gen_lea(std::ostream &out, const Instruction &i)
void exec_jns(const Instruction &instr)
void exec_jae(const Instruction &instr)
Variable & getVariable(const std::string &name)
Look up a variable by name, searching local scope then global.
void exec_mul(const Instruction &instr)
void x64_generateInstruction(std::ostream &out, const Instruction &i)
Dispatch a single instruction to its Win64 code generator.
void exec_jc(const Instruction &instr)
void x64_gen_load(std::ostream &out, const Instruction &i)
void x64_gen_jae(std::ostream &out, const Instruction &i)
void sysv_emitSaveRegs(std::ostream &out)
Save callee-saved registers at function prologue.
void exec_free(const Instruction &instr)
void exec_load(const Instruction &instr)
int exec()
Execute the program via the interpreter.
void exec_exit(const Instruction &instr)
void sysv_emitFlushRegs(std::ostream &out)
Write all register-allocated variables back to memory.
void x64_gen_getline(std::ostream &out, const Instruction &i)
void x64_gen_free(std::ostream &out, const Instruction &i)
void flatten_label(Program *root, int64_t offset, const std::string &label, bool func)
Copy a label from a child object into the root label map with an address offset.
void x64_gen_pop(std::ostream &out, const Instruction &i)
void x64_gen_print(std::ostream &out, const Instruction &i)
void divVariables(Variable &dest, Variable &src1, Variable &src2)
Divide src1 by src2 and store the result in dest.
void exec_push(const Instruction &instr)
Execute a PUSH instruction — save a variable or constant onto the VM stack.
void stop()
Halt the interpreter loop.
void x64_gen_jc(std::ostream &out, const Instruction &i)
void x64_gen_neg(std::ostream &out, const Instruction &i)
void gen_cmp(std::ostream &out, const Instruction &i)
VarType last_call_ret_type
void x64_emitStoreVar(std::ostream &out, const std::string &srcReg, const Operand &dest)
Store a register value into a variable (register-allocated or memory).
std::vector< std::string > sysv_reg_save_order
bool isFunctionValid(const std::string &label)
Check whether a label exists and is marked as a function entry.
void gen_jc(std::ostream &out, const Instruction &i)
void x64_emitStoreVarImm(std::ostream &out, const std::string &imm, const Operand &dest)
Store an immediate value into a variable.
void x64_gen_to_float(std::ostream &out, const Instruction &i)
void x64_emitSaveRegs(std::ostream &out)
Save callee-saved registers at function prologue.
int x64_generateLoadVar(std::ostream &out, int r, const Operand &op)
Load a variable or constant into a numbered Win64 register.
void x64_gen_mov(std::ostream &out, const Instruction &i)
bool less_flag
comparison less-than flag
Program * getObjectByName(const std::string &name)
Look up a child object program by name.
void exec_mod(const Instruction &instr)
void exec_jg(const Instruction &instr)
void x64_gen_jns(std::ostream &out, const Instruction &i)
void x64_emit_iob_func(std::ostream &out, int index, const std::string &dstReg)
Emit an integer-or-byte function argument load for Win64 ABI.
void sysv_emitRestoreRegs(std::ostream &out)
Restore callee-saved registers at function epilogue.
void add_standard()
Register standard library runtime functions.
void gen_add(std::ostream &out, const Instruction &i)
void exec_jl(const Instruction &instr)
std::string optimize_darwin(const std::string &code)
Darwin-specific assembly optimizations.
void exec_stack_load(const Instruction &instr)
void x64_gen_ret(std::ostream &out, const Instruction &i)
bool isVariable(const std::string &name)
Check whether a variable exists in local or global scope.
void x64_gen_cmp(std::ostream &out, const Instruction &i)
void sysv_emitStoreVar(std::ostream &out, const std::string &srcReg, const Operand &dest)
Store a register value into a variable (register-allocated or memory).
void x64_gen_jp(std::ostream &out, const Instruction &i)
void gen_pop(std::ostream &out, const Instruction &i)
Emit x86-64 POP into a variable.
void gen_not(std::ostream &out, const Instruction &i)
void gen_return(std::ostream &out, const Instruction &i)
std::unordered_map< std::string, std::string > x64_reg_vars
Win64 variable-to-register mapping.
void exec_to_int(const Instruction &instr)
void x64_release_call_area(std::ostream &out, size_t frame)
Release a Win64 call frame previously reserved.
void gen_jno(std::ostream &out, const Instruction &i)
void exec_jz(const Instruction &instr)
void x64_gen_stack_store(std::ostream &out, const Instruction &i)
void gen_realloc(std::ostream &out, const Instruction &i)
Generate System V x86-64 assembly for the REALLOC instruction (dynamic array resize).
void exec_fcmp(const Instruction &instr)
void gen_jns(std::ostream &out, const Instruction &i)
std::vector< std::string > args
~Program()
Destructor — frees any heap-allocated variables.
static std::string escapeNewLines(const std::string &text)
Escape newline characters in a string literal for assembly output.
void gen_call(std::ostream &out, const Instruction &i)
void flatten_external(Program *root, const std::string &e, RuntimeFunction &r)
Copy an external function binding from a child object into the root.
void print(std::ostream &out)
Print all instructions and data to an output stream.
std::string getPlatformSymbolName(const std::string &name)
Mangle a symbol name with the platform prefix (e.g. _name for Darwin).
void post(std::ostream &out)
Generate native data section (variable declarations) into the output stream.
void exec_to_float(const Instruction &instr)
void exec_done(const Instruction &instr)
void exec_store(const Instruction &instr)
Execute a STORE instruction — write a value into a pointer at a given offset.
bool last_call_returns_owned_ptr
tracks ownership of last call's return value
void gen_push(std::ostream &out, const Instruction &i)
Emit x86-64 PUSH for a variable or constant.
void exec_sub(const Instruction &instr)
void sysv_analyzeRegAlloc(bool uses_std_module)
Analyze variable usage and assign System V callee-saved registers.
std::unordered_map< std::string, std::string > sysv_reg_vars
SysV variable-to-register mapping.
void x64_gen_to_int(std::ostream &out, const Instruction &i)
void exec_or(const Instruction &instr)
std::vector< std::unique_ptr< Program > > objects
void gen_invoke(std::ostream &out, const Instruction &i)
void setObject(bool obj)
Mark this program as an object (no main entry point).
void exec_mov(const Instruction &instr)
void sysv_emitLoadVar(std::ostream &out, const std::string &dstReg, const Operand &src)
Load a variable into a destination register.
void exec_return(const Instruction &instr)
void x64_gen_not(std::ostream &out, const Instruction &i)
void gen_done(std::ostream &out, const Instruction &i)
std::string getMangledName(const std::string &var)
Mangle a variable name with its owning object prefix.
void exec_not(const Instruction &instr)
bool carry_flag
comparison carry flag
void generateCode(const Platform &platform, bool obj, std::ostream &out)
Generate native x64 assembly for the entire program.
LastCmpType last_cmp_type
void exec_cmp(const Instruction &instr)
void x64_gen_jno(std::ostream &out, const Instruction &i)
void gen_to_int(std::ostream &out, const Instruction &i)
void generateInstruction(std::ostream &out, const Instruction &i)
Dispatch a single instruction to its System V code generator.
bool main_function
true if this program has a main entry point
void x64_gen_return(std::ostream &out, const Instruction &i)
void gen_stack_load(std::ostream &out, const Instruction &i)
std::vector< std::string > x64_reg_save_order
void exec_je(const Instruction &instr)
void x64_gen_arth(std::ostream &out, std::string arth, const Instruction &i)
void exec_invoke(const Instruction &instr)
void exec_js(const Instruction &instr)
void x64_gen_invoke(std::ostream &out, const Instruction &i)
void x64_emitReloadRegs(std::ostream &out)
Reload register-allocated variables from memory.
LastCmpType
Tracks type of last comparison for conditional jumps.
size_t x64_reserve_call_area(std::ostream &out, size_t spill_bytes)
Reserve stack space for a Win64 call frame including spill area.
void gen_jnc(std::ostream &out, const Instruction &i)
void exec_jo(const Instruction &instr)
Variable variableFromOperand(const Operand &op)
Resolve an Operand to its corresponding Variable.
void exec_realloc(const Instruction &instr)
Execute the REALLOC instruction in the interpreter.
void exec_add(const Instruction &instr)
void exec_and(const Instruction &instr)
void x64_gen_jnp(std::ostream &out, const Instruction &i)
void exec_xor(const Instruction &instr)
Program & operator=(Program &&other) noexcept
Move-assignment operator.
void memoryDump(std::ostream &out)
Dump all variable values to a stream for debugging.
void exec_jnz(const Instruction &instr)
void x64_emitLoadVar(std::ostream &out, const std::string &dstReg, const Operand &src)
Load a variable into a destination register.
void gen_mov(std::ostream &out, const Instruction &i)
void gen_mod(std::ostream &out, const Instruction &i)
std::string x64_getRegisterByIndex(int index, VarType type)
Get the Win64 register name for a given index and variable type.
void flatten(Program *program)
Flatten child object programs into the root instruction stream.
void x64_gen_call(std::ostream &out, const Instruction &i)
void exec_neg(const Instruction &instr)
void gen_jmp(std::ostream &out, const Instruction &i)
void x64_gen_alloc(std::ostream &out, const Instruction &i)
void x64_gen_jmp(std::ostream &out, const Instruction &i)
void sysv_emitReloadRegs(std::ostream &out)
Reload register-allocated variables from memory.
void gen_arth(std::ostream &out, std::string arth, const Instruction &i)
std::string gen_optimize(const std::string &code, const Platform &platform)
Peephole optimizer for generated assembly.
void gen_jo(std::ostream &out, const Instruction &i)
void x64_gen_jnc(std::ostream &out, const Instruction &i)
void exec_stack_sub(const Instruction &instr)
bool isConstant(const std::string &value)
Check whether a string represents a compile-time constant (number or quoted string).
void x64_generateInvokeCall(std::ostream &out, std::vector< Operand > &op)
Generate a Win64 dynamic invoke call.
void exec_call(const Instruction &instr)
void gen_free(std::ostream &out, const Instruction &i)
void exec_string_print(const Instruction &instr)
void gen_mul(std::ostream &out, const Instruction &i)
void exec_jne(const Instruction &instr)
void gen_js(std::ostream &out, const Instruction &i)
void exec_jge(const Instruction &instr)
void exec_div(const Instruction &instr)
void exec_jmp(const Instruction &instr)
bool zero_flag
comparison zero flag
void x64_gen_jbe(std::ostream &out, const Instruction &i)
void exec_jle(const Instruction &instr)
void gen_div(std::ostream &out, const Instruction &i)
void gen_jbe(std::ostream &out, const Instruction &i)
void exec_getline(const Instruction &instr)
void gen_sub(std::ostream &out, const Instruction &i)
void exec_alloc(const Instruction &instr)
std::string optimize_core(const std::string &code)
Platform-independent peephole optimizations.
void gen_stack_store(std::ostream &out, const Instruction &i)
void gen_jae(std::ostream &out, const Instruction &i)
void exec_jbe(const Instruction &instr)
int getExitCode() const
Get the program's exit code after execution.
void x64_gen_mod(std::ostream &out, const Instruction &i)
void exec_jb(const Instruction &instr)
void x64_gen_stack_load(std::ostream &out, const Instruction &i)
void generateInvokeCall(std::ostream &out, std::vector< Operand > &op)
Generate a dynamic invoke call (runtime-resolved external function).
void x64_gen_stack_sub(std::ostream &out, const Instruction &i)
void x64_gen_done(std::ostream &out, const Instruction &i)
void generateFunctionCall(std::ostream &out, const std::string &name, std::vector< Operand > &op)
Generate a System V ABI function call with operands as arguments.
void x64_gen_fcmp(std::ostream &out, const Instruction &i)
void exec_jnp(const Instruction &instr)
bool greater_flag
comparison greater-than flag
void gen_bitop(std::ostream &out, const std::string &opc, const Instruction &i)
void gen_store(std::ostream &out, const Instruction &i)
bool last_call_returns_owned
void exec_lea(const Instruction &instr)
void addVariables(Variable &dest, Variable &src1, Variable &src2)
Add two variables and store the result in dest.
void gen_getline(std::ostream &out, const Instruction &i)
void flatten_inc(Program *root, Instruction &i)
Rewrite object-qualified operand references in a single instruction.
bool validateNames(Validator &v)
Validate all variable and label names against the Validator.
int xmm_offset
current XMM register allocation offset
Operand result
return value operand from last invoke
void exec_jno(const Instruction &instr)
void exec_ja(const Instruction &instr)
void x64_gen_div(std::ostream &out, const Instruction &i)
void x64_gen_js(std::ostream &out, const Instruction &i)
void exec_pop(const Instruction &instr)
Execute a POP instruction — restore a value from the VM stack into a variable.
void x64_gen_jo(std::ostream &out, const Instruction &i)
void gen_to_float(std::ostream &out, const Instruction &i)
void gen_stack_sub(std::ostream &out, const Instruction &i)
void exec_jp(const Instruction &instr)
void x64_gen_push(std::ostream &out, const Instruction &i)
void mulVariables(Variable &dest, Variable &src1, Variable &src2)
Multiply two variables and store the result in dest.
void x64_gen_exit(std::ostream &out, const Instruction &i)
void gen_alloc(std::ostream &out, const Instruction &i)
void gen_jnp(std::ostream &out, const Instruction &i)
Program()
Default constructor — initializes execution state (pc, flags, etc.).
void gen_exit(std::ostream &out, const Instruction &i)
void gen_load(std::ostream &out, const Instruction &i)
void x64_gen_bitop(std::ostream &out, const std::string &opc, const Instruction &i)
void x64_emitRestoreRegs(std::ostream &out)
Restore callee-saved registers at function epilogue.
std::string getRegisterByIndex(int index, VarType type)
Get the register name for a given index and variable type.
void setVariableFromString(Variable &var, const std::string &value)
Set a variable's value from a string representation, coercing types.
void setArgs(const std::vector< std::string > &argv)
Set the command-line arguments available to the program.
void x64_analyzeRegAlloc(bool uses_std_module)
Analyze variable usage and assign Win64 callee-saved registers.
void exec_jnc(const Instruction &instr)
void gen_print(std::ostream &out, const Instruction &i)
std::string printFormatted(const std::string &format, const std::vector< Variable * > &args, bool output=true)
Format and optionally print a printf-style format string with variable arguments.
Program * parent
parent program (for object programs)
void gen_ret(std::ostream &out, const Instruction &i)
void exec_print(const Instruction &instr)
Program(Program &&other) noexcept
Move constructor — transfers all execution state and child objects.
void exec_ret(const Instruction &instr)
bool running
interpreter running flag
void x64_gen_realloc(std::ostream &out, const Instruction &i)
Generate Win64 x86-64 assembly for the REALLOC instruction (dynamic array resize).
void exec_stack_store(const Instruction &instr)
void x64_generateCode(const Platform &platform, bool obj, std::ostream &out)
Top-level Win64 code generation entry point.
void subVariables(Variable &dest, Variable &src1, Variable &src2)
Subtract src2 from src1 and store the result in dest.
void x64_generateFunctionCall(std::ostream &out, const std::string &name, std::vector< Operand > &args)
Generate a Win64 ABI function call with operands as arguments.
void x64_direct_stack_adjust(std::ostream &out, int64_t bytes)
Emit a direct stack pointer adjustment.
void gen_fcmp(std::ostream &out, const Instruction &i)
void sysv_emitStoreVarImm(std::ostream &out, const std::string &imm, const Operand &dest)
Store an immediate value into a variable.
void x64_gen_lea(std::ostream &out, const Instruction &i)
void gen_neg(std::ostream &out, const Instruction &i)
void x64_gen_store(std::ostream &out, const Instruction &i)
void x64_emitFlushRegs(std::ostream &out)
Write all register-allocated variables back to memory.
int generateLoadVar(std::ostream &out, int reg, const Operand &op)
Load a variable or constant into a numbered register.
Wraps a dynamically loaded native function from a shared library module.
RuntimeFunction(const RuntimeFunction &r)
Copy constructor.
RuntimeFunction()
Default constructor — null function pointer and handle.
std::string fname
function symbol name
void * handle
dlopen handle
void call(Program *program, std::vector< Operand > &operands)
Invoke the loaded function.
static std::unordered_map< std::string, void * > handles
cached library handles
void * func
resolved function pointer
RuntimeFunction & operator=(const RuntimeFunction &r)
Copy-assignment operator.
std::string mod_name
module name
~RuntimeFunction()=default
Runtime operand stack for the MXVM interpreter.
StackValue & operator[](size_t index)
Random access into the stack.
StackValue pop()
Pop and return the top value.
size_t size() const
Return the number of elements on the stack.
bool empty() const
Check whether the stack is empty.
void push(const StackValue &value)
Push a value onto the stack.
std::vector< StackValue > data
Validates MXVM source for correct variable/label usage and instruction operands.
Exception class, hex formatting utilities, and terminal color definitions.
Parser that tokenizes and parses MXVM source into programs, handles modules/objects,...
Instruction set enum, operand/instruction structs, variable types, and Variable/Variable_Value defini...
const char * argv(int idx)
Return the command-line argument at the given index.
std::function< void(Program *program, std::vector< Operand > &operands)> runtime_call
Callback type for runtime-registered native functions.
bool isFunctionReturningOwnedPtr(const std::string &funcName)
Check whether a named function returns an owned (heap-allocated) pointer.
Platform
Target platform for native code generation.
void except_assert(std::string reason, bool value)
Assert a condition, throwing an Exception with the given reason on failure.
std::variant< int64_t, void *, double, std::string > StackValue
Stack element: integer, pointer, double, or string.
VarType
MXVM variable type discriminator.
A complete MXVM instruction with opcode, operands, and optional label.
A single instruction operand (constant value or variable reference).
A named variable with type, value, and optional object association.