stage1 部分功能测试00,01,02,06成功
This commit is contained in:
@@ -40,6 +40,7 @@ typedef enum {
|
||||
X(SPL_DROP, "drop", 0, 1, 0, "discard top of stack") \
|
||||
X(SPL_SWAP, "swap", 0, 2, 2, "swap top two elements") \
|
||||
X(SPL_PICK, "pick", 1, 0, 1, "push copy of stack[imm] (0=TOS)") \
|
||||
X(SPL_ROT, "rot", 0, 3, 3, "rotate top three (a b c -- b c a)") \
|
||||
/* 算术 */ \
|
||||
X(SPL_ADD, "add", 0, 2, 1, "integer addition") \
|
||||
X(SPL_SUB, "sub", 0, 2, 1, "integer subtraction") \
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
|
||||
#include "spl_syscall.h"
|
||||
#include "include/core_vec.h"
|
||||
#include "spl_ir.h"
|
||||
#include "spl_vm.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -77,36 +79,36 @@
|
||||
* OS syscalls
|
||||
* ================================================================= */
|
||||
|
||||
/* os_exit — terminate process with the given exit code */
|
||||
SYSCALL_1(os_exit, int, (exit(a1), (spl_val_t)0))
|
||||
/* vm_exit — terminate process with the given exit code */
|
||||
SYSCALL_1(vm_exit, int, (exit(a1), (spl_val_t)0))
|
||||
|
||||
/* os_putchar — write a single character to stdout */
|
||||
SYSCALL_1(os_putchar, int, putchar(a1))
|
||||
/* vm_putchar — write a single character to stdout */
|
||||
SYSCALL_1(vm_putchar, int, putchar(a1))
|
||||
|
||||
/* os_getchar — read a single character from stdin */
|
||||
SYSCALL_0(os_getchar, getchar())
|
||||
/* vm_getchar — read a single character from stdin */
|
||||
SYSCALL_0(vm_getchar, getchar())
|
||||
|
||||
/* os_putint — print an integer to stdout */
|
||||
SYSCALL_1(os_putint, int, (fprintf(stdout, "%d", a1), (spl_val_t)0))
|
||||
/* vm_putint — print an integer to stdout */
|
||||
SYSCALL_1(vm_putint, int, (fprintf(stdout, "%d", a1), (spl_val_t)0))
|
||||
|
||||
/* os_putstr — print a string to stdout (no trailing newline) */
|
||||
SYSCALL_1(os_putstr, const char *, (fputs(a1, stdout), (spl_val_t)0))
|
||||
/* vm_putstr — print a string to stdout (no trailing newline) */
|
||||
SYSCALL_1(vm_putstr, const char *, (fputs(a1, stdout), (spl_val_t)0))
|
||||
|
||||
/* os_fopen — open a file, returns FILE* as spl_val_t */
|
||||
SYSCALL_2(os_fopen, const char *, const char *, (uintptr_t)fopen(a1, a2))
|
||||
/* vm_fopen — open a file, returns FILE* as spl_val_t */
|
||||
SYSCALL_2(vm_fopen, const char *, const char *, (uintptr_t)fopen(a1, a2))
|
||||
|
||||
/* os_fclose — close a file, returns 0 on success */
|
||||
SYSCALL_1(os_fclose, FILE *, fclose(a1))
|
||||
/* vm_fclose — close a file, returns 0 on success */
|
||||
SYSCALL_1(vm_fclose, FILE *, fclose(a1))
|
||||
|
||||
/* os_fread — read from file, returns number of items read */
|
||||
SYSCALL_4(os_fread, void *, size_t, size_t, FILE *, fread(a1, a2, a3, a4))
|
||||
/* vm_fread — read from file, returns number of items read */
|
||||
SYSCALL_4(vm_fread, void *, size_t, size_t, FILE *, fread(a1, a2, a3, a4))
|
||||
|
||||
/* os_fwrite — write to file, returns number of items written */
|
||||
SYSCALL_4(os_fwrite, const void *, size_t, size_t, FILE *, fwrite(a1, a2, a3, a4))
|
||||
/* vm_fwrite — write to file, returns number of items written */
|
||||
SYSCALL_4(vm_fwrite, const void *, size_t, size_t, FILE *, fwrite(a1, a2, a3, a4))
|
||||
|
||||
/* os_fsize — get file size in bytes */
|
||||
static spl_val_t os_fsize(int nargs, spl_val_t *args) {
|
||||
CHECK_NARGS("os_fsize", 1);
|
||||
/* vm_fsize — get file size in bytes */
|
||||
static spl_val_t vm_fsize(int nargs, spl_val_t *args) {
|
||||
CHECK_NARGS("vm_fsize", 1);
|
||||
FILE *f = (FILE *)(uintptr_t)args[0];
|
||||
long cur = ftell(f);
|
||||
fseek(f, 0, SEEK_END);
|
||||
@@ -115,9 +117,9 @@ static spl_val_t os_fsize(int nargs, spl_val_t *args) {
|
||||
return (spl_val_t)(uintptr_t)sz;
|
||||
}
|
||||
|
||||
/* os_read_file — read entire file into a malloc'd, null-terminated buffer */
|
||||
static spl_val_t os_read_file(int nargs, spl_val_t *args) {
|
||||
CHECK_NARGS("os_read_file", 1);
|
||||
/* vm_read_file — read entire file into a malloc'd, null-terminated buffer */
|
||||
static spl_val_t vm_read_file(int nargs, spl_val_t *args) {
|
||||
CHECK_NARGS("vm_read_file", 1);
|
||||
const char *path = (const char *)(uintptr_t)args[0];
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f)
|
||||
@@ -136,23 +138,74 @@ static spl_val_t os_read_file(int nargs, spl_val_t *args) {
|
||||
return (spl_val_t)(uintptr_t)buf;
|
||||
}
|
||||
|
||||
/* os_alloc — allocate memory (malloc) */
|
||||
SYSCALL_1(os_alloc, size_t, (uintptr_t)malloc(a1))
|
||||
/* vm_alloc — allocate memory (malloc) */
|
||||
SYSCALL_1(vm_alloc, size_t, (uintptr_t)malloc(a1))
|
||||
|
||||
/* os_free — free memory */
|
||||
SYSCALL_1(os_free, void *, (free(a1), (spl_val_t)0))
|
||||
/* vm_free — free memory */
|
||||
SYSCALL_1(vm_free, void *, (free(a1), (spl_val_t)0))
|
||||
|
||||
/* os_realloc — reallocate memory (realloc) */
|
||||
SYSCALL_2(os_realloc, void *, size_t, (uintptr_t)realloc(a1, a2))
|
||||
/* vm_realloc — reallocate memory (realloc) */
|
||||
SYSCALL_2(vm_realloc, void *, size_t, (uintptr_t)realloc(a1, a2))
|
||||
|
||||
/* os_strlen — get string length */
|
||||
SYSCALL_1(os_strlen, const char *, strlen(a1))
|
||||
/* vm_strlen — get string length */
|
||||
SYSCALL_1(vm_strlen, const char *, strlen(a1))
|
||||
|
||||
/* os_strcmp — compare two strings */
|
||||
SYSCALL_2(os_strcmp, const char *, const char *, strcmp(a1, a2))
|
||||
/* vm_strcmp — compare two strings */
|
||||
SYSCALL_2(vm_strcmp, const char *, const char *, strcmp(a1, a2))
|
||||
|
||||
/* os_memcpy — copy memory, returns dst */
|
||||
SYSCALL_3(os_memcpy, void *, const void *, size_t, (memcpy(a1, a2, a3), (uintptr_t)a1))
|
||||
/* vm_memcpy — copy memory, returns dst */
|
||||
SYSCALL_3(vm_memcpy, void *, const void *, size_t, (memcpy(a1, a2, a3), (uintptr_t)a1))
|
||||
|
||||
static spl_val_t vm_printf(int nargs, spl_val_t *args) {
|
||||
(void)args;
|
||||
if (nargs <= 0) {
|
||||
return 0;
|
||||
}
|
||||
const char *fmt = (const char *)args[0];
|
||||
usize fmt_len = strlen(fmt);
|
||||
typedef VEC(char) string_builder_t;
|
||||
string_builder_t buffer;
|
||||
vec_init(buffer);
|
||||
if (nargs <= 1) {
|
||||
printf("%s", fmt);
|
||||
return nargs;
|
||||
}
|
||||
int arg_idx = 0;
|
||||
char tmp_buf[32];
|
||||
memset(tmp_buf, 0, sizeof(tmp_buf));
|
||||
for (int i = 0; i < fmt_len; ++i) {
|
||||
if (fmt[i] != '%') {
|
||||
vec_push(buffer, fmt[i]);
|
||||
continue;
|
||||
}
|
||||
arg_idx += 1;
|
||||
if (++i >= fmt_len) {
|
||||
continue;
|
||||
}
|
||||
switch (fmt[i]) {
|
||||
case 'd':
|
||||
snprintf(tmp_buf, sizeof(tmp_buf), "%zd", args[arg_idx]);
|
||||
for (int j = 0; j < strlen(tmp_buf); ++j) {
|
||||
vec_push(buffer, tmp_buf[j]);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
vec_push(buffer, (char)args[arg_idx]);
|
||||
break;
|
||||
case 's':
|
||||
for (int j = 0; j < strlen((const char *)args[arg_idx]); ++j) {
|
||||
vec_push(buffer, ((const char *)args[arg_idx])[j]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
vec_push(buffer, '\0');
|
||||
printf("%s", buffer.data);
|
||||
vec_free(buffer);
|
||||
return nargs;
|
||||
}
|
||||
|
||||
/* =================================================================
|
||||
* VM syscalls (for comptime — compile-time code execution)
|
||||
@@ -287,23 +340,24 @@ SYSCALL_1(vm_run, spl_vm_t *, spl_vm_run_until(a1, 0))
|
||||
void spl_syscall_register(spl_prog_t *prog) {
|
||||
static spl_native_t table[] = {
|
||||
/* OS operations */
|
||||
{"os_exit", 0, os_exit},
|
||||
{"os_putchar", 0, os_putchar},
|
||||
{"os_getchar", 0, os_getchar},
|
||||
{"os_putint", 0, os_putint},
|
||||
{"os_putstr", 0, os_putstr},
|
||||
{"os_fopen", 0, os_fopen},
|
||||
{"os_fclose", 0, os_fclose},
|
||||
{"os_fread", 0, os_fread},
|
||||
{"os_fwrite", 0, os_fwrite},
|
||||
{"os_fsize", 0, os_fsize},
|
||||
{"os_read_file", 0, os_read_file},
|
||||
{"os_alloc", 0, os_alloc},
|
||||
{"os_free", 0, os_free},
|
||||
{"os_realloc", 0, os_realloc},
|
||||
{"os_strlen", 0, os_strlen},
|
||||
{"os_strcmp", 0, os_strcmp},
|
||||
{"os_memcpy", 0, os_memcpy},
|
||||
{"vm_exit", 0, vm_exit},
|
||||
{"vm_putchar", 0, vm_putchar},
|
||||
{"vm_getchar", 0, vm_getchar},
|
||||
{"vm_putint", 0, vm_putint},
|
||||
{"vm_putstr", 0, vm_putstr},
|
||||
{"vm_fopen", 0, vm_fopen},
|
||||
{"vm_fclose", 0, vm_fclose},
|
||||
{"vm_fread", 0, vm_fread},
|
||||
{"vm_fwrite", 0, vm_fwrite},
|
||||
{"vm_fsize", 0, vm_fsize},
|
||||
{"vm_read_file", 0, vm_read_file},
|
||||
{"vm_alloc", 0, vm_alloc},
|
||||
{"vm_free", 0, vm_free},
|
||||
{"vm_realloc", 0, vm_realloc},
|
||||
{"vm_strlen", 0, vm_strlen},
|
||||
{"vm_strcmp", 0, vm_strcmp},
|
||||
{"vm_memcpy", 0, vm_memcpy},
|
||||
{"vm_printf", 0, vm_printf},
|
||||
/* VM operations (comptime) */
|
||||
{"vm_new", 0, vm_new},
|
||||
{"vm_drop", 0, vm_drop},
|
||||
|
||||
@@ -50,7 +50,7 @@ static int spl_type_size(spl_type_t t) {
|
||||
case SPL_ISIZE:
|
||||
case SPL_USIZE:
|
||||
case SPL_PTR:
|
||||
return sizeof(void *) / 8;
|
||||
return sizeof(void *);
|
||||
case SPL_TYPE_COUNT:
|
||||
return 0;
|
||||
}
|
||||
@@ -554,18 +554,27 @@ void spl_vm_set_debug(spl_vm_t *vm, int enabled) {
|
||||
vm->debug = enabled ? 1 : 0;
|
||||
}
|
||||
|
||||
#define STACK_CANARY(vm) (vm)->stacks.data[(vm)->fp - 1]
|
||||
|
||||
static inline int spl_vm_call(spl_vm_t *vm, spl_val_t addr, spl_val_t nargs) {
|
||||
if (vm->cp >= vm->config.max_call_depth)
|
||||
VM_ERROR("CALLI: call stack overflow");
|
||||
// spl_vm_stackdump(vm, vm->sp);
|
||||
PUSH(SPL_STACK_CANARY);
|
||||
/* Shift args right by 1 to create gap for canary at fp-1 */
|
||||
for (usize i = vm->sp; i >= vm->sp - nargs; --i) {
|
||||
vm->stacks.data[i] = vm->stacks.data[i - 1];
|
||||
}
|
||||
vm->frames.data[vm->cp].saved_sp = vm->sp - nargs - 1;
|
||||
vm->frames.data[vm->cp].saved_fp = vm->fp;
|
||||
vm->frames.data[vm->cp].saved_ip = vm->ip;
|
||||
vm->frames.data[vm->cp].nargs = nargs;
|
||||
vm->cp++;
|
||||
vm->ip = addr;
|
||||
vm->fp = vm->sp - nargs;
|
||||
/* Transparent canary at fp-1 — invisible to normal LADDR/ST */
|
||||
if (vm->fp > 0)
|
||||
vm->stacks.data[vm->fp - 1] = SPL_STACK_CANARY;
|
||||
STACK_CANARY(vm) = SPL_STACK_CANARY;
|
||||
// spl_vm_stackdump(vm, vm->sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -670,6 +679,18 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
break;
|
||||
}
|
||||
|
||||
case SPL_ROT: {
|
||||
if (vm->sp < 3)
|
||||
VM_ERROR("ROT: stack underflow");
|
||||
spl_val_t _a = vm->stacks.data[vm->sp - 3];
|
||||
spl_val_t _b = vm->stacks.data[vm->sp - 2];
|
||||
spl_val_t _c = vm->stacks.data[vm->sp - 1];
|
||||
vm->stacks.data[vm->sp - 3] = _b;
|
||||
vm->stacks.data[vm->sp - 2] = _c;
|
||||
vm->stacks.data[vm->sp - 1] = _a;
|
||||
break;
|
||||
}
|
||||
|
||||
/* ========== Arithmetic ========== */
|
||||
case SPL_ADD:
|
||||
ARITH_BINOP(+);
|
||||
@@ -821,6 +842,7 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
if (vm->cp <= 0)
|
||||
VM_ERROR("RET: call stack underflow");
|
||||
vm->cp--;
|
||||
intptr_t _saved_sp = vm->frames.data[vm->cp].saved_sp;
|
||||
intptr_t _saved_fp = vm->frames.data[vm->cp].saved_fp;
|
||||
intptr_t _saved_ip = vm->frames.data[vm->cp].saved_ip;
|
||||
/* entry return -> halt */
|
||||
@@ -828,11 +850,12 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
vm->exit_code = (int)_retval;
|
||||
return 1;
|
||||
}
|
||||
vm->sp = vm->fp;
|
||||
vm->sp = _saved_sp;
|
||||
vm->fp = _saved_fp;
|
||||
vm->ip = _saved_ip;
|
||||
if (ins->type != SPL_VOID)
|
||||
PUSH(_retval);
|
||||
// spl_vm_stackdump(vm, vm->sp);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -933,6 +956,9 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
VM_ERROR(vm->error_msg);
|
||||
}
|
||||
spl_val_t *_arg_base = vm->stacks.data + vm->sp - _nargs;
|
||||
// spl_vm_stackdump(vm, vm->sp);
|
||||
// printf("addr %p nargs %zd sp %zd stack %p arg_base %p\n", _nat->impl_fn, _nargs, vm->sp,
|
||||
// vm->stacks.data, _arg_base);
|
||||
spl_val_t _result = _nat->impl_fn(_nargs, _arg_base);
|
||||
vm->sp -= _nargs;
|
||||
PUSH(_result);
|
||||
@@ -969,8 +995,7 @@ int spl_vm_run_once(spl_vm_t *vm) {
|
||||
|
||||
/* canary check in debug mode (canary is at fp-1, invisible to compiled code) */
|
||||
if (vm->debug && vm->fp > 0) {
|
||||
spl_val_t val = vm->stacks.data[vm->fp - 1];
|
||||
if (val != SPL_STACK_CANARY) {
|
||||
if (STACK_CANARY(vm) != SPL_STACK_CANARY) {
|
||||
snprintf(vm->error_msg, sizeof(vm->error_msg),
|
||||
"STACK CANARY CORRUPTED at ip=%zd, fp=%zd\n", vm->ip - 1, vm->fp);
|
||||
VM_ERROR(vm->error_msg);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define SPL_STACK_CANARY ((spl_val_t)0xDEADBEEFCAFEBABEull)
|
||||
|
||||
typedef struct {
|
||||
uintptr_t saved_sp;
|
||||
uintptr_t saved_fp;
|
||||
uintptr_t saved_ip;
|
||||
spl_val_t nargs;
|
||||
|
||||
Reference in New Issue
Block a user