Skip to content

Commit fdd5f31

Browse files
committed
feat: Add core VM implementation, LLVM backend, benchmarking infrastructure, and project license.
1 parent abcc754 commit fdd5f31

6 files changed

Lines changed: 50 additions & 214 deletions

File tree

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,4 @@ term sustainability of the ProX ecosystem.
126126

127127
────────────────────────────────────────────────────────
128128
END OF PROX PROFESSIONAL LICENSE (PPL)
129-
────────────────────────────────────────────────────────
129+
────────────────────────────────────────────────────────

benchmarks/run_benchmarks.py

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,43 @@ def run_benchmark(executable, benchmark_file):
1212

1313
cmd = [executable, benchmark_file]
1414
start = time.time()
15-
try:
16-
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
17-
end = time.time()
18-
return end - start, result.stdout
19-
except subprocess.CalledProcessError as e:
20-
print(f"Error running {benchmark_file}: {e}")
21-
print(f"Stdout: {e.stdout}")
22-
print(f"Stderr: {e.stderr}")
23-
return None, None
24-
except Exception as e:
25-
print(f"Execution failed: {e}")
26-
return None, None
15+
16+
# Use a temporary file for stdout/stderr to avoid MemoryError on huge output
17+
import tempfile
18+
19+
with tempfile.TemporaryFile() as out_tmp:
20+
try:
21+
# We don't use check=True so we can capture output even on failure
22+
proc = subprocess.run(cmd, stdout=out_tmp, stderr=subprocess.STDOUT, timeout=60, text=False) # raw bytes
23+
24+
end = time.time()
25+
duration = end - start
26+
27+
# Read output back (limit size)
28+
out_tmp.seek(0)
29+
# Read first 4KB and last 4KB if large? Or just read all and catch error?
30+
# Let's read first 100KB which should be enough for any reasonable benchmark
31+
# If it's huge, we truncate.
32+
output_bytes = out_tmp.read(100 * 1024)
33+
if out_tmp.read(1): # check if there is more
34+
output_bytes += b"\n... [Output Truncated] ...\n"
35+
36+
output = output_bytes.decode('utf-8', errors='replace')
37+
38+
if proc.returncode != 0:
39+
print(f"Error running {benchmark_file}: Return Code {proc.returncode}")
40+
# Print output snippet
41+
print(f"Output:\n{output[-1000:]}") # Last 1000 chars
42+
return None, None
43+
44+
return duration, output
45+
46+
except subprocess.TimeoutExpired:
47+
print(f"Benchmark {benchmark_file} timed out.")
48+
return None, None
49+
except Exception as e:
50+
print(f"Execution failed: {e}")
51+
return None, None
2752

2853
def main():
2954
parser = argparse.ArgumentParser(description="Run ProXPL benchmarks.")

include/vm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include "table.h"
1313
#include "importer.h"
1414

15-
#define FRAMES_MAX 256
15+
#define FRAMES_MAX 1024
1616
#define STACK_MAX (FRAMES_MAX * 256)
1717

1818
// CallFrame is now defined in common.h

src/compiler/backend_llvm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ class LLVMEmitter {
466466
// Implement prox_rt_resume wrapper
467467
llvm::BasicBlock* Entry = llvm::BasicBlock::Create(*Context, "entry", FResume);
468468
llvm::IRBuilder<> ResBuilder(Entry);
469-
llvm::Function* FCoroResume = llvm::Intrinsic::getOrInsertDeclaration(ModuleOb.get(), llvm::Intrinsic::coro_resume);
469+
llvm::Function* FCoroResume = llvm::Intrinsic::getDeclaration(ModuleOb.get(), llvm::Intrinsic::coro_resume);
470470
// Note: getDeclaration is deprecated but for some LLVM versions getOrInsertDeclaration is for non-intrinsics?
471471
// Actually, for intrinsics, getDeclaration is still standard in many versions.
472472
// But the warning says use getOrInsertDeclaration?

src/runtime/vm.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ void runtimeError(VM* pvm, const char* format, ...) {
7474
}
7575

7676
void push(VM* pvm, Value value) {
77+
if (pvm->stackTop >= pvm->stack + STACK_MAX) {
78+
// Emergency stack reset or hard abort to prevent segfault
79+
// Since we can't easily return error code from push, we set a flag or just abort.
80+
// Ideally, push checks should be done before calling logic.
81+
// check frame overflow handles recursion.
82+
// check value stack overflow:
83+
fprintf(stderr, "Fatal Runtime Error: Value stack overflow.\n");
84+
exit(1);
85+
}
7786
*pvm->stackTop = value;
7887
pvm->stackTop++;
7988
}
@@ -449,7 +458,7 @@ static InterpretResult run(VM *vm) {
449458
runtimeError(vm, "Expected %d arguments but got %d.", closure->function->arity, argCount);
450459
return INTERPRET_RUNTIME_ERROR;
451460
}
452-
if (vm->frameCount == 64) { // MAX_FRAMES
461+
if (vm->frameCount == FRAMES_MAX) { // FRAMES_MAX
453462
runtimeError(vm, "Stack overflow.");
454463
return INTERPRET_RUNTIME_ERROR;
455464
}

src/vm/vm_core_opt.c

Lines changed: 0 additions & 198 deletions
This file was deleted.

0 commit comments

Comments
 (0)