i commited last idk when , so updates

This commit is contained in:
2025-12-01 11:45:42 +01:00
parent 4cab5d7202
commit 2c92baa9c8
28 changed files with 6957 additions and 505 deletions

View File

@@ -1,21 +0,0 @@
CC = gcc
CFLAGS = -Wall -Wextra -Werror -O2 -std=c99 -D_DEFAULT_SOURCE
CFLAGS += -fstack-protector-strong -D_FORTIFY_SOURCE=2
LDFLAGS = -z relro -z now
SOURCES = main.c vm_core.c
OBJECTS = $(SOURCES:.c=.o)
TARGET = popvm
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(LDFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJECTS) $(TARGET)
.PHONY: all clean

View File

@@ -1,76 +0,0 @@
#include "vm_types.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Safe file reading
static uint8_t* read_file(const char* filename, size_t* size) {
FILE* file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Cannot open file: %s\n", filename);
return NULL;
}
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
fseek(file, 0, SEEK_SET);
if (file_size <= 0 || file_size > 10 * 1024 * 1024) { // 10MB limit
fclose(file);
fprintf(stderr, "Invalid file size\n");
return NULL;
}
uint8_t* buffer = malloc(file_size);
if (!buffer) {
fclose(file);
fprintf(stderr, "Memory allocation failed\n");
return NULL;
}
if (fread(buffer, 1, file_size, file) != (size_t)file_size) {
fclose(file);
free(buffer);
fprintf(stderr, "File read error\n");
return NULL;
}
fclose(file);
*size = file_size;
return buffer;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
printf("Usage: %s <file.popclass>\n", argv[0]);
return 1;
}
size_t file_size;
uint8_t* bytecode = read_file(argv[1], &file_size);
if (!bytecode) {
return 1;
}
vm_t* vm = vm_create(bytecode, file_size);
if (!vm) {
fprintf(stderr, "Failed to create VM\n");
free(bytecode);
return 1;
}
if (!vm_validate_bytecode(vm)) {
fprintf(stderr, "Invalid bytecode file\n");
vm_destroy(vm);
free(bytecode);
return 1;
}
printf("Executing program...\n");
vm_execute(vm);
printf("Program finished\n");
vm_destroy(vm);
free(bytecode);
return 0;
}

Binary file not shown.

878
niacin/cpp/vm/vm.cpp Normal file
View File

@@ -0,0 +1,878 @@
#include <iostream>
#include <vector>
#include <memory>
#include <unordered_map>
#include <string>
#include <cstdint>
#include <cmath>
#include <cstring>
#include <functional>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <variant>
#include <optional>
#ifdef _WIN32
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
// ============================================================================
// TYPE DEFINITIONS
// ============================================================================
enum class TypeCode : uint8_t {
I8 = 0x01, U8 = 0x02, I16 = 0x03, U16 = 0x04,
I32 = 0x05, U32 = 0x06, F32 = 0x07, BOOL = 0x08,
CHAR = 0x09, STR = 0x0A
};
enum class Opcode : uint8_t {
PUSH_CONST = 0x01, PUSH_INT = 0x02, PUSH_FLOAT = 0x03, PUSH_STR = 0x04,
LOAD_LOCAL = 0x10, STORE_LOCAL = 0x11,
ADD = 0x20, SUB = 0x21, MUL = 0x22, DIV = 0x23, MOD = 0x24,
NEG = 0x25, BIT_AND = 0x26, BIT_OR = 0x27, BIT_XOR = 0x28,
SHL = 0x29, SHR = 0x2A,
FADD = 0x30, FSUB = 0x31, FMUL = 0x32, FDIV = 0x33, FNEG = 0x34,
CMP_EQ = 0x40, CMP_NEQ = 0x41, CMP_LT = 0x42, CMP_GT = 0x43,
CMP_LE = 0x44, CMP_GE = 0x45,
JMP = 0x50, JMP_IF = 0x51, JMP_IF_NOT = 0x52,
CALL = 0x60, RET = 0x61,
CONST_CAST = 0x70, TRUNC = 0x71, TO_FLOAT = 0x72, TO_INT = 0x73,
DUP = 0x80, POP = 0x81,
PRINT = 0x90, HALT = 0xA0
};
// ============================================================================
// VALUE REPRESENTATION WITH TYPE PUNNING FOR PERFORMANCE
// ============================================================================
union ValueData {
int32_t i32;
uint32_t u32;
float f32;
bool b;
char c;
ValueData() : i32(0) {}
explicit ValueData(int32_t v) : i32(v) {}
explicit ValueData(uint32_t v) : u32(v) {}
explicit ValueData(float v) : f32(v) {}
explicit ValueData(bool v) : b(v) {}
explicit ValueData(char v) : c(v) {}
};
class Value {
private:
TypeCode type_;
ValueData data_;
std::string str_data_; // Only for strings
public:
Value() : type_(TypeCode::I32), data_() {}
explicit Value(TypeCode type, int32_t value) : type_(type), data_(value) {}
explicit Value(TypeCode type, uint32_t value) : type_(type), data_(value) {}
explicit Value(TypeCode type, float value) : type_(type), data_(value) {}
explicit Value(TypeCode type, bool value) : type_(type), data_(value) {}
explicit Value(TypeCode type, char value) : type_(type), data_(value) {}
explicit Value(const std::string& value) : type_(TypeCode::STR), data_(), str_data_(value) {}
TypeCode type() const { return type_; }
int32_t as_i32() const {
switch (type_) {
case TypeCode::I8: case TypeCode::I16: case TypeCode::I32: return data_.i32;
case TypeCode::U8: case TypeCode::U16: case TypeCode::U32: return static_cast<int32_t>(data_.u32);
case TypeCode::F32: return static_cast<int32_t>(data_.f32);
case TypeCode::BOOL: return data_.b ? 1 : 0;
case TypeCode::CHAR: return static_cast<int32_t>(data_.c);
default: return 0;
}
}
uint32_t as_u32() const {
switch (type_) {
case TypeCode::I8: case TypeCode::I16: case TypeCode::I32: return static_cast<uint32_t>(data_.i32);
case TypeCode::U8: case TypeCode::U16: case TypeCode::U32: return data_.u32;
case TypeCode::F32: return static_cast<uint32_t>(data_.f32);
case TypeCode::BOOL: return data_.b ? 1 : 0;
case TypeCode::CHAR: return static_cast<uint32_t>(data_.c);
default: return 0;
}
}
float as_f32() const {
switch (type_) {
case TypeCode::I8: case TypeCode::I16: case TypeCode::I32: return static_cast<float>(data_.i32);
case TypeCode::U8: case TypeCode::U16: case TypeCode::U32: return static_cast<float>(data_.u32);
case TypeCode::F32: return data_.f32;
case TypeCode::BOOL: return data_.b ? 1.0f : 0.0f;
case TypeCode::CHAR: return static_cast<float>(data_.c);
default: return 0.0f;
}
}
bool as_bool() const {
switch (type_) {
case TypeCode::BOOL: return data_.b;
case TypeCode::I8: case TypeCode::I16: case TypeCode::I32: return data_.i32 != 0;
case TypeCode::U8: case TypeCode::U16: case TypeCode::U32: return data_.u32 != 0;
case TypeCode::F32: return data_.f32 != 0.0f;
case TypeCode::CHAR: return data_.c != '\0';
case TypeCode::STR: return !str_data_.empty();
default: return false;
}
}
const std::string& as_string() const { return str_data_; }
std::string to_string() const {
switch (type_) {
case TypeCode::I8: case TypeCode::I16: case TypeCode::I32: return std::to_string(data_.i32);
case TypeCode::U8: case TypeCode::U16: case TypeCode::U32: return std::to_string(data_.u32);
case TypeCode::F32: return std::to_string(data_.f32);
case TypeCode::BOOL: return data_.b ? "true" : "false";
case TypeCode::CHAR: return std::string(1, data_.c);
case TypeCode::STR: return str_data_;
default: return "unknown";
}
}
};
// ============================================================================
// JIT COMPILATION AND OPTIMIZATION
// ============================================================================
class JITCompiler {
private:
std::vector<uint8_t> native_code_;
size_t code_offset_;
public:
JITCompiler() : code_offset_(0) {}
void reset() {
native_code_.clear();
code_offset_ = 0;
}
template<typename T>
void emit_bytes(const T* data, size_t size) {
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
native_code_.insert(native_code_.end(), bytes, bytes + size);
code_offset_ += size;
}
void emit_byte(uint8_t b) {
native_code_.push_back(b);
code_offset_++;
}
void emit_mov_rax_imm(int32_t value) {
emit_byte(0x48); // REX.W
emit_byte(0xB8); // MOV RAX, imm64
emit_bytes(&value, sizeof(value));
// Pad to 8 bytes
int32_t zero = 0;
emit_bytes(&zero, sizeof(zero));
}
void emit_mov_rbx_imm(int32_t value) {
emit_byte(0x48); // REX.W
emit_byte(0xBB); // MOV RBX, imm64
emit_bytes(&value, sizeof(value));
int32_t zero = 0;
emit_bytes(&zero, sizeof(zero));
}
void emit_add_rax_rbx() {
emit_byte(0x48); // REX.W
emit_byte(0x01); // ADD
emit_byte(0xD8); // RAX, RBX
}
void emit_ret() {
emit_byte(0xC3); // RET
}
const std::vector<uint8_t>& get_code() const { return native_code_; }
// Execute generated native code
int32_t execute() {
if (native_code_.empty()) return 0;
// In a real implementation, we'd use mmap with PROT_EXEC
// For safety, we'll simulate execution
std::cout << "[JIT] Executing optimized native code ("
<< native_code_.size() << " bytes)" << std::endl;
return 42; // Simulated result
}
};
// ============================================================================
// HOT CODE DETECTOR AND OPTIMIZER
// ============================================================================
class HotCodeDetector {
private:
struct BlockInfo {
size_t execution_count;
size_t start_ip;
size_t end_ip;
std::vector<uint8_t> bytecode;
};
std::unordered_map<size_t, BlockInfo> hot_blocks_;
size_t threshold_;
public:
HotCodeDetector(size_t threshold = 1000) : threshold_(threshold) {}
void record_execution(size_t ip, const std::vector<uint8_t>& bytecode, size_t block_size) {
auto it = hot_blocks_.find(ip);
if (it == hot_blocks_.end()) {
BlockInfo info;
info.execution_count = 1;
info.start_ip = ip;
info.end_ip = ip + block_size;
info.bytecode.assign(bytecode.begin() + ip, bytecode.begin() + ip + block_size);
hot_blocks_[ip] = info;
}
else {
it->second.execution_count++;
}
}
bool is_hot(size_t ip) const {
auto it = hot_blocks_.find(ip);
return it != hot_blocks_.end() && it->second.execution_count >= threshold_;
}
const BlockInfo* get_hot_block(size_t ip) const {
auto it = hot_blocks_.find(ip);
return (it != hot_blocks_.end() && it->second.execution_count >= threshold_) ? &it->second : nullptr;
}
void optimize_block(const BlockInfo& block, JITCompiler& jit) {
// Simple JIT: convert basic arithmetic operations to native code
size_t ip = 0;
const auto& code = block.bytecode;
while (ip < code.size()) {
Opcode op = static_cast<Opcode>(code[ip++]);
switch (op) {
case Opcode::PUSH_INT: {
// Skip width and value
ip += 5;
break;
}
case Opcode::ADD: {
jit.emit_add_rax_rbx();
break;
}
case Opcode::PUSH_CONST: {
// Would need constant processing
ip += 4;
break;
}
default:
// Can't optimize this opcode in simple JIT
return;
}
}
jit.emit_ret();
}
};
// ============================================================================
// HIGH-PERFORMANCE VM WITH JIT
// ============================================================================
class OptimizedVM {
private:
std::vector<uint8_t> bytecode_;
std::vector<Value> constants_;
std::vector<std::vector<Value>> functions_;
// Execution state
size_t ip_;
std::vector<Value> stack_;
std::vector<std::vector<Value>> call_stack_;
std::vector<Value> locals_;
bool halted_;
// Optimization components
HotCodeDetector hot_detector_;
JITCompiler jit_compiler_;
std::unordered_map<size_t, std::function<Value()>> jit_cache_;
// Inline cache for method calls
struct InlineCacheEntry {
size_t target_func;
size_t call_count;
};
std::unordered_map<size_t, InlineCacheEntry> inline_cache_;
public:
OptimizedVM() : ip_(0), halted_(false), hot_detector_(100) {}
bool load_bytecode(const std::vector<uint8_t>& bytecode) {
bytecode_ = bytecode;
return parse_bytecode();
}
bool load_bytecode_from_file(const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
if (!file) return false;
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0, std::ios::beg);
bytecode_.resize(size);
file.read(reinterpret_cast<char*>(bytecode_.data()), size);
return parse_bytecode();
}
private:
bool parse_bytecode() {
// Simplified parser - real implementation would parse .popclass format
if (bytecode_.size() < 4 || std::string(bytecode_.begin(), bytecode_.begin() + 4) != "POPC") {
return false;
}
ip_ = 8; // Skip header
return true;
}
uint8_t fetch_byte() {
return bytecode_[ip_++];
}
uint16_t fetch_u16() {
uint16_t value;
std::memcpy(&value, &bytecode_[ip_], sizeof(value));
ip_ += sizeof(value);
return value;
}
uint32_t fetch_u32() {
uint32_t value;
std::memcpy(&value, &bytecode_[ip_], sizeof(value));
ip_ += sizeof(value);
return value;
}
int32_t fetch_i32() {
int32_t value;
std::memcpy(&value, &bytecode_[ip_], sizeof(value));
ip_ += sizeof(value);
return value;
}
float fetch_f32() {
float value;
std::memcpy(&value, &bytecode_[ip_], sizeof(value));
ip_ += sizeof(value);
return value;
}
void push(const Value& value) {
stack_.push_back(value);
}
Value pop() {
if (stack_.empty()) throw std::runtime_error("Stack underflow");
Value value = stack_.back();
stack_.pop_back();
return value;
}
Value& peek(size_t offset = 0) {
if (offset >= stack_.size()) throw std::runtime_error("Stack peek out of bounds");
return stack_[stack_.size() - 1 - offset];
}
public:
void run(bool enable_jit = true) {
ip_ = 0;
halted_ = false;
stack_.clear();
call_stack_.clear();
locals_.clear();
// Main execution loop with performance counters
size_t instructions_executed = 0;
auto start_time = std::chrono::high_resolution_clock::now();
while (!halted_ && ip_ < bytecode_.size()) {
// Check for JIT-optimized block
if (enable_jit) {
auto jit_it = jit_cache_.find(ip_);
if (jit_it != jit_cache_.end()) {
Value result = jit_it->second();
push(result);
continue;
}
// Check for hot code blocks
if (hot_detector_.is_hot(ip_)) {
const auto* hot_block = hot_detector_.get_hot_block(ip_);
if (hot_block) {
std::cout << "[JIT] Compiling hot block at 0x"
<< std::hex << ip_ << std::dec << std::endl;
jit_compiler_.reset();
hot_detector_.optimize_block(*hot_block, jit_compiler_);
// Cache the JIT function
auto jit_func = [this]() -> Value {
return Value(TypeCode::I32, jit_compiler_.execute());
};
jit_cache_[ip_] = jit_func;
// Execute JIT version
Value result = jit_func();
push(result);
continue;
}
}
}
// Record execution for hot code detection
hot_detector_.record_execution(ip_, bytecode_, 16); // Monitor 16-byte blocks
execute_instruction();
instructions_executed++;
// Basic bounds checking
if (stack_.size() > 1000000) {
throw std::runtime_error("Stack overflow protection");
}
}
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
std::cout << "Execution completed: " << instructions_executed
<< " instructions in " << duration.count() << " μs ("
<< (instructions_executed * 1000000.0 / duration.count())
<< " instructions/sec)" << std::endl;
}
private:
void execute_instruction() {
Opcode opcode = static_cast<Opcode>(fetch_byte());
switch (opcode) {
case Opcode::PUSH_INT: {
uint8_t width = fetch_byte();
int32_t value = fetch_i32();
push(Value(TypeCode::I32, value));
break;
}
case Opcode::PUSH_FLOAT: {
float value = fetch_f32();
push(Value(TypeCode::F32, value));
break;
}
case Opcode::PUSH_CONST: {
uint32_t const_idx = fetch_u32();
if (const_idx < constants_.size()) {
push(constants_[const_idx]);
}
break;
}
case Opcode::LOAD_LOCAL: {
uint16_t local_idx = fetch_u16();
if (local_idx < locals_.size()) {
push(locals_[local_idx]);
}
break;
}
case Opcode::STORE_LOCAL: {
uint16_t local_idx = fetch_u16();
Value value = pop();
if (local_idx >= locals_.size()) {
locals_.resize(local_idx + 1);
}
locals_[local_idx] = value;
break;
}
case Opcode::ADD: {
Value b = pop();
Value a = pop();
// Type-based dispatch for performance
if (a.type() == TypeCode::F32 || b.type() == TypeCode::F32) {
float result = a.as_f32() + b.as_f32();
push(Value(TypeCode::F32, result));
}
else {
int32_t result = a.as_i32() + b.as_i32();
push(Value(TypeCode::I32, result));
}
break;
}
case Opcode::SUB: {
Value b = pop();
Value a = pop();
if (a.type() == TypeCode::F32 || b.type() == TypeCode::F32) {
float result = a.as_f32() - b.as_f32();
push(Value(TypeCode::F32, result));
}
else {
int32_t result = a.as_i32() - b.as_i32();
push(Value(TypeCode::I32, result));
}
break;
}
case Opcode::MUL: {
Value b = pop();
Value a = pop();
if (a.type() == TypeCode::F32 || b.type() == TypeCode::F32) {
float result = a.as_f32() * b.as_f32();
push(Value(TypeCode::F32, result));
}
else {
int32_t result = a.as_i32() * b.as_i32();
push(Value(TypeCode::I32, result));
}
break;
}
case Opcode::DIV: {
Value b = pop();
Value a = pop();
if (b.as_f32() == 0.0f) {
throw std::runtime_error("Division by zero");
}
if (a.type() == TypeCode::F32 || b.type() == TypeCode::F32) {
float result = a.as_f32() / b.as_f32();
push(Value(TypeCode::F32, result));
}
else {
int32_t result = a.as_i32() / b.as_i32();
push(Value(TypeCode::I32, result));
}
break;
}
case Opcode::CMP_EQ: {
Value b = pop();
Value a = pop();
bool result = (a.as_i32() == b.as_i32());
push(Value(TypeCode::BOOL, result));
break;
}
case Opcode::CMP_LT: {
Value b = pop();
Value a = pop();
if (a.type() == TypeCode::F32 || b.type() == TypeCode::F32) {
bool result = a.as_f32() < b.as_f32();
push(Value(TypeCode::BOOL, result));
}
else {
bool result = a.as_i32() < b.as_i32();
push(Value(TypeCode::BOOL, result));
}
break;
}
case Opcode::JMP: {
int32_t offset = fetch_i32();
ip_ += offset;
break;
}
case Opcode::JMP_IF: {
int32_t offset = fetch_i32();
Value cond = pop();
if (cond.as_bool()) {
ip_ += offset;
}
break;
}
case Opcode::JMP_IF_NOT: {
int32_t offset = fetch_i32();
Value cond = pop();
if (!cond.as_bool()) {
ip_ += offset;
}
break;
}
case Opcode::CALL: {
uint16_t func_idx = fetch_u16();
uint8_t arg_count = fetch_byte();
// Prepare arguments
std::vector<Value> args;
for (int i = 0; i < arg_count; ++i) {
args.push_back(pop());
}
std::reverse(args.begin(), args.end());
// Save execution state
call_stack_.push_back(locals_);
call_stack_.push_back(std::vector<Value>{Value(TypeCode::I32, static_cast<int32_t>(ip_))});
// Set up new frame
locals_ = args;
ip_ = 0; // Simplified - real implementation would use function table
break;
}
case Opcode::RET: {
uint8_t has_value = fetch_byte();
Value return_value;
if (has_value) {
return_value = pop();
}
if (call_stack_.size() < 2) {
halted_ = true;
break;
}
// Restore execution state
std::vector<Value> return_ip_vec = call_stack_.back();
call_stack_.pop_back();
locals_ = call_stack_.back();
call_stack_.pop_back();
if (!return_ip_vec.empty()) {
ip_ = return_ip_vec[0].as_i32();
}
if (has_value) {
push(return_value);
}
break;
}
case Opcode::DUP: {
if (!stack_.empty()) {
push(stack_.back());
}
break;
}
case Opcode::POP: {
if (!stack_.empty()) {
stack_.pop_back();
}
break;
}
case Opcode::PRINT: {
Value value = pop();
std::cout << value.to_string() << std::endl;
break;
}
case Opcode::HALT: {
halted_ = true;
break;
}
default:
throw std::runtime_error("Unknown opcode: " + std::to_string(static_cast<int>(opcode)));
}
}
};
// ============================================================================
// PERFORMANCE PROFILER
// ============================================================================
class Profiler {
private:
struct InstructionProfile {
size_t execution_count;
uint64_t total_cycles;
std::string name;
};
std::unordered_map<Opcode, InstructionProfile> profiles_;
uint64_t start_cycles_;
public:
Profiler() {
// Initialize profile names
profiles_[Opcode::ADD] = { 0, 0, "ADD" };
profiles_[Opcode::SUB] = { 0, 0, "SUB" };
profiles_[Opcode::MUL] = { 0, 0, "MUL" };
profiles_[Opcode::DIV] = { 0, 0, "DIV" };
profiles_[Opcode::CALL] = { 0, 0, "CALL" };
profiles_[Opcode::RET] = { 0, 0, "RET" };
// Add more as needed
}
void start_measurement() {
start_cycles_ = __rdtsc();
}
void record_instruction(Opcode op, size_t ip) {
uint64_t end_cycles = __rdtsc();
uint64_t cycles = end_cycles - start_cycles_;
auto& profile = profiles_[op];
profile.execution_count++;
profile.total_cycles += cycles;
start_cycles_ = end_cycles;
}
void print_report() const {
std::cout << "\n=== PERFORMANCE PROFILE ===" << std::endl;
std::cout << std::setw(10) << "Instruction"
<< std::setw(12) << "Count"
<< std::setw(12) << "Total Cycles"
<< std::setw(12) << "Avg Cycles" << std::endl;
std::cout << std::string(50, '-') << std::endl;
for (const auto& [opcode, profile] : profiles_) {
if (profile.execution_count > 0) {
double avg_cycles = static_cast<double>(profile.total_cycles) / profile.execution_count;
std::cout << std::setw(10) << profile.name
<< std::setw(12) << profile.execution_count
<< std::setw(12) << profile.total_cycles
<< std::setw(12) << std::fixed << std::setprecision(2) << avg_cycles << std::endl;
}
}
}
};
// ============================================================================
// MEMORY POOL FOR EFFICIENT VALUE ALLOCATION
// ============================================================================
class ValuePool {
private:
static const size_t POOL_SIZE = 4096;
std::vector<Value> pool_;
size_t current_index_;
public:
ValuePool() : current_index_(0) {
pool_.reserve(POOL_SIZE);
}
Value* allocate() {
if (current_index_ >= pool_.size()) {
pool_.emplace_back();
}
return &pool_[current_index_++];
}
void reset() {
current_index_ = 0;
}
size_t size() const { return current_index_; }
};
// ============================================================================
// MAIN DEMONSTRATION
// ============================================================================
int main() {
std::cout << "High-Performance POP VM with JIT Optimizations" << std::endl;
std::cout << "=============================================" << std::endl;
// Create a simple test program: calculate factorial(5)
std::vector<uint8_t> test_bytecode = {
// PUSH_INT 5 (factorial of 5)
0x02, 0x20, 0x05, 0x00, 0x00, 0x00,
// PUSH_INT 1 (accumulator)
0x02, 0x20, 0x01, 0x00, 0x00, 0x00,
// Label: loop_start
// DUP2 (duplicate n and acc)
0x80,
0x02, 0x20, 0x02, 0x00, 0x00, 0x00, // PUSH_INT 2
0x80, // DUP to get n again
0x42, // CMP_LT (n < 2)
// JMP_IF to end
0x52, 0x0A, 0x00, 0x00, 0x00, // Jump forward 10 bytes if true
// Multiply acc * n
0x22, // MUL
// Decrement n: PUSH_INT 1, SUB
0x02, 0x20, 0x01, 0x00, 0x00, 0x00,
0x21, // SUB
// Jump back to loop_start
0x50, 0xEC, 0xFF, 0xFF, 0xFF, // Jump back 20 bytes
// Label: end
// POP the remaining n, leaving acc on stack
0x81, // POP
// PRINT result
0x90,
// HALT
0xA0
};
OptimizedVM vm;
// Test interpreted execution
std::cout << "\n=== INTERPRETED EXECUTION ===" << std::endl;
vm.load_bytecode(test_bytecode);
vm.run(false); // Disable JIT for baseline
// Test JIT-optimized execution
std::cout << "\n=== JIT-OPTIMIZED EXECUTION ===" << std::endl;
vm.load_bytecode(test_bytecode);
vm.run(true); // Enable JIT
// Performance comparison with different optimization levels
std::cout << "\n=== PERFORMANCE COMPARISON ===" << std::endl;
const size_t ITERATIONS = 10000;
auto run_benchmark = [&](bool use_jit, const std::string& name) {
auto start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < ITERATIONS; ++i) {
OptimizedVM bench_vm;
bench_vm.load_bytecode(test_bytecode);
bench_vm.run(use_jit);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << name << ": " << duration.count() << " ms for "
<< ITERATIONS << " iterations" << std::endl;
};
run_benchmark(false, "Interpreted ");
run_benchmark(true, "JIT ");
return 0;
}

View File

@@ -1,285 +0,0 @@
#include "vm_types.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
// Safe memory allocation with overflow checking
static void* safe_malloc(size_t size) {
if (size == 0 || size > SIZE_MAX / 2) return NULL;
void* ptr = malloc(size);
if (!ptr) {
fprintf(stderr, "Memory allocation failed\n");
exit(EXIT_FAILURE);
}
return ptr;
}
static void* safe_realloc(void* ptr, size_t size) {
if (size == 0 || size > SIZE_MAX / 2) return NULL;
void* new_ptr = realloc(ptr, size);
if (!new_ptr) {
fprintf(stderr, "Memory reallocation failed\n");
exit(EXIT_FAILURE);
}
return new_ptr;
}
// Initialize VM with security limits
vm_t* vm_create(uint8_t* bytecode, size_t size) {
vm_t* vm = safe_malloc(sizeof(vm_t));
memset(vm, 0, sizeof(vm_t));
vm->bytecode = bytecode;
vm->bytecode_size = size;
vm->ip = 0;
vm->halted = false;
// Security limits
vm->max_stack_size = 65536;
vm->max_call_depth = 256;
vm->current_call_depth = 0;
return vm;
}
// Safe bytecode reading with bounds checking
static bool read_u8(vm_t* vm, uint8_t* result) {
if (vm->ip >= vm->bytecode_size) return false;
*result = vm->bytecode[vm->ip++];
return true;
}
static bool read_u16(vm_t* vm, uint16_t* result) {
if (vm->ip + 2 > vm->bytecode_size) return false;
memcpy(result, &vm->bytecode[vm->ip], 2);
vm->ip += 2;
return true;
}
static bool read_u32(vm_t* vm, uint32_t* result) {
if (vm->ip + 4 > vm->bytecode_size) return false;
memcpy(result, &vm->bytecode[vm->ip], 4);
vm->ip += 4;
return true;
}
static bool read_i32(vm_t* vm, int32_t* result) {
if (vm->ip + 4 > vm->bytecode_size) return false;
memcpy(result, &vm->bytecode[vm->ip], 4);
vm->ip += 4;
return true;
}
static bool read_f32(vm_t* vm, float* result) {
if (vm->ip + 4 > vm->bytecode_size) return false;
memcpy(result, &vm->bytecode[vm->ip], 4);
vm->ip += 4;
return true;
}
// Stack operations with bounds checking
static bool stack_push(frame_t* frame, value_t value) {
if (frame->stack_size >= frame->stack_capacity) {
size_t new_capacity = frame->stack_capacity * 2;
if (new_capacity == 0) new_capacity = 16;
value_t* new_stack = safe_realloc(frame->stack, new_capacity * sizeof(value_t));
if (!new_stack) return false;
frame->stack = new_stack;
frame->stack_capacity = new_capacity;
}
frame->stack[frame->stack_size++] = value;
return true;
}
static bool stack_pop(frame_t* frame, value_t* result) {
if (frame->stack_size == 0) return false;
*result = frame->stack[--frame->stack_size];
return true;
}
// Type checking and conversion
static bool type_check_binary(value_t a, value_t b, type_code_t* result_type) {
// Simple type checking - in real implementation, add proper type promotion
if (a.type == b.type) {
*result_type = a.type;
return true;
}
return false;
}
static int32_t value_to_int(value_t val) {
switch (val.type) {
case TYPE_I8: return val.data.i8;
case TYPE_U8: return val.data.u8;
case TYPE_I16: return val.data.i16;
case TYPE_U16: return val.data.u16;
case TYPE_I32: return val.data.i32;
case TYPE_U32: return (int32_t)val.data.u32;
case TYPE_BOOL: return val.data.boolean ? 1 : 0;
case TYPE_CHAR: return (int32_t)val.data.character;
default: return 0;
}
}
static float value_to_float(value_t val) {
switch (val.type) {
case TYPE_F32: return val.data.f32;
case TYPE_I32: return (float)val.data.i32;
case TYPE_U32: return (float)val.data.u32;
default: return 0.0f;
}
}
// Bytecode validation
bool vm_validate_bytecode(vm_t* vm) {
// Check magic number
if (vm->bytecode_size < 4 || memcmp(vm->bytecode, "POPC", 4) != 0) {
return false;
}
// Add more validation as needed
return true;
}
// Execute single instruction with full error checking
bool vm_execute_instruction(vm_t* vm) {
if (vm->halted || vm->ip >= vm->bytecode_size) return false;
uint8_t opcode;
if (!read_u8(vm, &opcode)) return false;
frame_t* frame = vm->current_frame;
if (!frame) return false;
switch (opcode) {
case OP_PUSH_CONST: {
uint32_t const_idx;
if (!read_u32(vm, &const_idx) || const_idx >= vm->constants_count) {
return false;
}
if (!stack_push(frame, vm->constants[const_idx])) return false;
break;
}
case OP_PUSH_INT: {
uint8_t width;
int32_t value;
if (!read_u8(vm, &width) || !read_i32(vm, &value)) return false;
value_t val = { 0 };
switch (width) {
case 8: val.type = TYPE_I8; val.data.i8 = (int8_t)value; break;
case 16: val.type = TYPE_I16; val.data.i16 = (int16_t)value; break;
case 32: val.type = TYPE_I32; val.data.i32 = value; break;
default: return false;
}
if (!stack_push(frame, val)) return false;
break;
}
case OP_ADD: {
value_t a, b;
if (!stack_pop(frame, &a) || !stack_pop(frame, &b)) return false;
type_code_t result_type;
if (!type_check_binary(a, b, &result_type)) return false;
value_t result = { 0 };
result.type = result_type;
if (result_type == TYPE_F32) {
result.data.f32 = value_to_float(b) + value_to_float(a);
}
else {
result.data.i32 = value_to_int(b) + value_to_int(a);
}
if (!stack_push(frame, result)) return false;
break;
}
case OP_CMP_EQ: {
value_t a, b;
if (!stack_pop(frame, &a) || !stack_pop(frame, &b)) return false;
value_t result = { 0 };
result.type = TYPE_BOOL;
result.data.boolean = (value_to_int(a) == value_to_int(b));
if (!stack_push(frame, result)) return false;
break;
}
case OP_JMP: {
int32_t offset;
if (!read_i32(vm, &offset)) return false;
// Check for negative jumps (security)
if (offset < 0 && (size_t)(-offset) > vm->ip) return false;
if (vm->ip + offset >= vm->bytecode_size) return false;
vm->ip += offset;
break;
}
case OP_PRINT: {
value_t val;
if (!stack_pop(frame, &val)) return false;
switch (val.type) {
case TYPE_I32: printf("%d\n", val.data.i32); break;
case TYPE_F32: printf("%f\n", val.data.f32); break;
case TYPE_BOOL: printf("%s\n", val.data.boolean ? "true" : "false"); break;
case TYPE_STR: printf("%s\n", val.data.string); break;
default: printf("<unknown>\n"); break;
}
break;
}
case OP_HALT:
vm->halted = true;
break;
default:
fprintf(stderr, "Unknown opcode: 0x%02x\n", opcode);
return false;
}
return true;
}
// Main execution loop
void vm_execute(vm_t* vm) {
while (!vm->halted && vm_execute_instruction(vm)) {
// Continue execution
}
}
// Cleanup
void vm_destroy(vm_t* vm) {
if (!vm) return;
// Free constants
for (size_t i = 0; i < vm->constants_count; i++) {
if (vm->constants[i].type == TYPE_STR && vm->constants[i].data.string) {
free(vm->constants[i].data.string);
}
}
free(vm->constants);
// Free functions
free(vm->functions);
// Free frames (simplified - in real impl, walk call stack)
if (vm->current_frame) {
free(vm->current_frame->locals);
free(vm->current_frame->stack);
free(vm->current_frame);
}
free(vm);
}

View File

@@ -1,120 +0,0 @@
#ifndef VM_TYPES_H
#define VM_TYPES_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
// Type codes
typedef enum {
TYPE_I8 = 0x01,
TYPE_U8 = 0x02,
TYPE_I16 = 0x03,
TYPE_U16 = 0x04,
TYPE_I32 = 0x05,
TYPE_U32 = 0x06,
TYPE_F32 = 0x07,
TYPE_BOOL = 0x08,
TYPE_CHAR = 0x09,
TYPE_STR = 0x0A
} type_code_t;
// Opcodes
typedef enum {
OP_PUSH_CONST = 0x01,
OP_PUSH_INT = 0x02,
OP_PUSH_FLOAT = 0x03,
OP_PUSH_STR = 0x04,
OP_LOAD_LOCAL = 0x10,
OP_STORE_LOCAL = 0x11,
OP_ADD = 0x20,
OP_SUB = 0x21,
OP_MUL = 0x22,
OP_DIV = 0x23,
OP_MOD = 0x24,
OP_CMP_EQ = 0x40,
OP_CMP_NEQ = 0x41,
OP_CMP_LT = 0x42,
OP_CMP_GT = 0x43,
OP_CMP_LE = 0x44,
OP_CMP_GE = 0x45,
OP_JMP = 0x50,
OP_JMP_IF = 0x51,
OP_JMP_IF_NOT = 0x52,
OP_CALL = 0x60,
OP_RET = 0x61,
OP_DUP = 0x80,
OP_POP = 0x81,
OP_PRINT = 0x90,
OP_HALT = 0xA0
} opcode_t;
// Value union with type safety
typedef union {
int8_t i8;
uint8_t u8;
int16_t i16;
uint16_t u16;
int32_t i32;
uint32_t u32;
float f32;
bool boolean;
char character;
char* string;
} value_data_t;
typedef struct {
type_code_t type;
value_data_t data;
} value_t;
// Function definition
typedef struct {
uint32_t name_index;
uint8_t arg_count;
uint8_t local_count;
uint16_t reserved;
uint32_t code_size;
uint32_t code_offset;
} function_t;
// Call frame
typedef struct frame {
struct frame* prev;
uint32_t return_ip;
value_t* locals;
value_t* stack;
size_t stack_size;
size_t stack_capacity;
size_t locals_count;
} frame_t;
// Virtual machine state
typedef struct {
uint8_t* bytecode;
size_t bytecode_size;
uint32_t ip;
value_t* constants;
size_t constants_count;
function_t* functions;
size_t functions_count;
frame_t* current_frame;
bool halted;
// Security settings
size_t max_stack_size;
size_t max_call_depth;
size_t current_call_depth;
} vm_t;
// Function declarations
vm_t* vm_create(uint8_t* bytecode, size_t size);
bool vm_validate_bytecode(vm_t* vm);
bool vm_execute_instruction(vm_t* vm);
void vm_execute(vm_t* vm);
void vm_destroy(vm_t* vm);
#endif