Compare commits

..
2 Commits
20 changed files with 2452 additions and 1576 deletions

No files matched your search

+1 -1
View File
@@ -202,7 +202,7 @@ const char *build_target(const char *name) {
return target_exe;
nob_cc(&cmd);
nob_cmd_append(&cmd, "-I./stage2/sys", "-O2", "-D_CRT_SECURE_NO_WARNINGS");
nob_cmd_append(&cmd, "-I./stage0", "-O2", "-D_CRT_SECURE_NO_WARNINGS");
nob_cc_inputs(&cmd, target_c);
nob_cc_output(&cmd, target_exe);
if (!nob_cmd_run(&cmd)) {
+82 -12
View File
@@ -3,6 +3,13 @@
/* clang-format off */
#define VM_SRCS "stage0/spl_mcode.c", "stage0/spl_syscall.c", "stage0/spl_vm.c",
static const char *stage0_headers[] = {
"stage0/spl_asp.h", "stage0/spl_mcode.h", "stage0/spl_syscall.h",
"stage0/spl_vm.h", "stage0/spl_rt_core.h", "stage0/spl_rt.h",
"stage0/spl_vm_embed.h",
};
static const char *spl_cli_srcs[] = {"stage0/spl_cli.c", VM_SRCS};
static const char *vm_test_srcs[] = {"stage0/test_spl_vm.c", VM_SRCS};
static const char *splc0_srcs[] = {
@@ -30,8 +37,8 @@ static const char *splc0_srcs[] = {
};
static const char *splc1_crt_deps[] ={
"stage2/sys/spl_rt.h",
"stage2/sys/spl_vm_embed.h",
"stage0/spl_rt.h",
"stage0/spl_vm_embed.h",
// TODO
};
@@ -88,10 +95,73 @@ static const char* splc1_deps[] = {
};
static const char* splc2_deps[] = {
/* stage3 */
"stage3/builtin.spl",
"stage3/hir.spl",
"stage3/hir2ir.spl",
"stage3/lang_type.spl",
"stage3/lower.spl",
"stage3/scope.spl",
"stage3/sema.spl",
"stage3/splc2.spl",
"stage3/tag.spl",
/* stage2 */
"stage2/sys/exit.spl",
"stage2/sys/file.spl",
"stage2/sys/mem.spl",
"stage2/sys/time.spl",
"stage2/sys/vm.spl",
"stage2/utils/algorithm.spl",
"stage2/utils/arena.spl",
"stage2/utils/ascii.spl",
"stage2/utils/byte_buffer.spl",
"stage2/utils/byte_view.spl",
"stage2/utils/error.spl",
"stage2/utils/fmt.spl",
"stage2/utils/hash.spl",
"stage2/utils/io.spl",
"stage2/utils/json.spl",
"stage2/utils/log.spl",
"stage2/utils/lsp_frame.spl",
"stage2/utils/map.spl",
"stage2/utils/memory.spl",
"stage2/utils/mp.spl",
"stage2/utils/path.spl",
"stage2/utils/profile.spl",
"stage2/utils/set.spl",
"stage2/utils/source.spl",
"stage2/utils/str.spl",
"stage2/utils/utf8.spl",
"stage2/utils/value.spl",
"stage2/utils/vec.spl",
"stage2/ast.spl",
"stage2/ast2ir.spl",
"stage2/attr.spl",
"stage2/def.spl",
"stage2/diag.spl",
"stage2/eval.spl",
"stage2/intrin.spl",
"stage2/ir.spl",
"stage2/ir2c.spl",
"stage2/ir2vm.spl",
"stage2/ir_builder.spl",
"stage2/lang_type.spl",
"stage2/layout.spl",
"stage2/lexer.spl",
"stage2/mcode.spl",
"stage2/parser.spl",
"stage2/scope.spl",
"stage2/sema.spl",
"stage2/splc1.spl",
"stage2/token.spl",
"stage2/type_table.spl",
};
static const char *splc2_crt_deps[] = {};
static const char *splc2_crt_deps[] = {
"stage0/spl_rt.h", "stage0/spl_rt_core.h", "stage0/spl_asp.h",
"stage0/spl_mcode.h", "stage0/spl_vm.h", "stage0/spl_syscall.h",
"stage0/spl_vm_embed.h",
};
/* clang-format on */
@@ -138,32 +208,32 @@ static build_t targets[] = {
BUILD_EXE_WITH_OPTIMIZATION,
.exe = {.srcs = spl_cli_srcs,
.srcs_count = NOB_ARRAY_LEN(spl_cli_srcs),
.headers = NULL,
.headers_count = 0},
.headers = stage0_headers,
.headers_count = NOB_ARRAY_LEN(stage0_headers)},
},
{
"spl_cli_g",
BUILD_EXE,
.exe = {.srcs = spl_cli_srcs,
.srcs_count = NOB_ARRAY_LEN(spl_cli_srcs),
.headers = NULL,
.headers_count = 0},
.headers = stage0_headers,
.headers_count = NOB_ARRAY_LEN(stage0_headers)},
},
{
"vm_test",
BUILD_EXE,
.exe = {.srcs = vm_test_srcs,
.srcs_count = NOB_ARRAY_LEN(vm_test_srcs),
.headers = NULL,
.headers_count = 0},
.headers = stage0_headers,
.headers_count = NOB_ARRAY_LEN(stage0_headers)},
},
{
"splc0",
BUILD_EXE,
.exe = {.srcs = splc0_srcs,
.srcs_count = NOB_ARRAY_LEN(splc0_srcs),
.headers = NULL,
.headers_count = 0},
.headers = stage0_headers,
.headers_count = NOB_ARRAY_LEN(stage0_headers)},
},
{
"splc1",
+38
View File
@@ -0,0 +1,38 @@
#ifndef __SPL_ASP_H__
#define __SPL_ASP_H__
/* spl_asp.h - 地址空间抽象(Address SPace)
*
* SPL 侧指针语义由 spl_asp_t 统一描述:
* - native(编译器自身):identity,指针就是宿主地址。
* - VM:句柄/偏移,offset = (handle<<32) | 区内字节偏移,0 为 null。
*
* runtime(spl_rt_core.h)的解引用/分配一律经此接口,从而同一份 SPL
* 源的 Vec/Map/mem 在两种后端下都自洽。
*/
#include <stdint.h>
#include <stddef.h>
#ifndef SPL_USIZE_TYPEDEF
#define SPL_USIZE_TYPEDEF
typedef uintptr_t usize;
#endif
typedef struct spl_asp spl_asp_t;
struct spl_asp {
void *ctx;
/* offset -> 宿主地址;size>0 时做边界检查;失败返回 NULL。 */
unsigned char *(*xlate)(void *ctx, uintptr_t off, uintptr_t size);
/* 分配 size 字节,返回 offset(0=失败)。 */
uintptr_t (*alloc)(void *ctx, uintptr_t size);
/* 重新分配 offset@old,返回新 offset(0=失败)。 */
uintptr_t (*realloc)(void *ctx, uintptr_t off, uintptr_t size);
/* 释放 offset。 */
void (*free)(void *ctx, uintptr_t off);
/* 宿主地址 -> offset;size>0 时校验范围。不属于该空间返回 0。 */
uintptr_t (*to_off)(void *ctx, const void *host, uintptr_t size);
};
#endif /* __SPL_ASP_H__ */
+118
View File
@@ -0,0 +1,118 @@
#ifndef __SPL_RT_H__
#define __SPL_RT_H__
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define SPL_FN static inline
#elif defined(__GNUC__) || defined(__clang__)
#define SPL_FN static __inline__
#else
#define SPL_FN static
#endif
#include <stdint.h>
typedef uint8_t u8;
typedef int8_t i8;
typedef uint16_t u16;
typedef int16_t i16;
typedef uint32_t u32;
typedef int32_t i32;
typedef uint64_t u64;
typedef int64_t i64;
#ifndef SPL_USIZE_TYPEDEF
#define SPL_USIZE_TYPEDEF
typedef u64 usize;
#endif
#ifndef SPL_ISIZE_TYPEDEF
#define SPL_ISIZE_TYPEDEF
typedef i64 isize;
#endif
SPL_FN void spl_panic(const char *msg) {
fprintf(stderr, "%s\n", msg ? msg : "panic");
exit(1);
}
SPL_FN void spl_trap(void) { abort(); }
#include "spl_rt_core.h"
SPL_FN void *vm_fopen(void *path, void *mode) {
return (void *)fopen((const char *)path, (const char *)mode);
}
SPL_FN i32 vm_fclose(void *f) { return f ? fclose((FILE *)f) : 0; }
SPL_FN u64 vm_fread(void *buf, u64 sz, u64 n, void *f) {
return f ? (u64)fread(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0;
}
SPL_FN u64 vm_fwrite(void *buf, u64 sz, u64 n, void *f) {
return f ? (u64)fwrite(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0;
}
SPL_FN u64 vm_fsize(void *f) {
long cur, end;
if (!f)
return 0;
cur = ftell((FILE *)f);
if (cur < 0)
return 0;
if (fseek((FILE *)f, 0, SEEK_END) != 0)
return 0;
end = ftell((FILE *)f);
fseek((FILE *)f, cur, SEEK_SET);
return end < 0 ? 0 : (u64)end;
}
SPL_FN void *vm_stdin(void) { return (void *)stdin; }
SPL_FN void *vm_stdout(void) { return (void *)stdout; }
SPL_FN void *vm_stderr(void) { return (void *)stderr; }
SPL_FN i32 vm_putchar(i32 c) { return fputc(c, stdout); }
SPL_FN i32 vm_getchar(void) { return fgetc(stdin); }
SPL_FN void vm_exit(i32 code) { exit(code); }
SPL_FN u64 vm_timestamp(u64 kind) {
time_t sec = time(NULL);
if (kind == 1)
return (u64)sec;
if (kind == 2)
return 0;
if (kind == 4)
return (u64)sec * 1000000000ull;
return 0;
}
#define SPL_VM_EMBED_IMPLIMENTATION
#include "spl_vm_embed.h"
/* 配置层外部函数处理器(native 端):把 nested VM 未解析的 native 按名分发到
* 编译器生成的 `ct_*` 函数(表由 ir2c 生成,见 stage2/ir2c.spl)。 */
extern void *spl_ct_lookup(const char *name);
typedef spl_vm_val_t (*spl_native_ct_fn_t)(void *, spl_vm_val_t, spl_vm_val_t, spl_vm_val_t);
SPL_FN spl_vm_val_t spl_native_foreign(spl_vm_t *vm, const spl_vm_call_t *call, void *user) {
void *fn;
spl_vm_val_t a0 = 0, a1 = 0;
(void)vm;
if (!call)
return 0;
fn = spl_ct_lookup(call->name);
if (!fn)
return 0;
if (call->nargs > 0)
a0 = call->args[0];
if (call->nargs > 1)
a1 = call->args[1];
/* ct_* 统一形状:返回 u64,参数 (ctx, u64, u64);多余参数被忽略。 */
return ((spl_native_ct_fn_t)fn)(user, a0, a1, 0);
}
SPL_FN void vm_set_foreign(void *p, unsigned long long handler, void *ctx) {
(void)handler;
spl_vm_set_foreign((spl_vm_t *)p, spl_native_foreign, ctx);
}
#endif /* __SPL_RT_H__ */
+691
View File
@@ -0,0 +1,691 @@
#ifndef __SPL_RT_CORE_H__
#define __SPL_RT_CORE_H__
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "spl_asp.h"
#ifndef SPL_CORE_FN
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define SPL_CORE_FN static inline
#elif defined(__GNUC__) || defined(__clang__)
#define SPL_CORE_FN static __inline__
#else
#define SPL_CORE_FN static
#endif
#endif
/* ================================================================
* 地址空间:identity(native/编译器自身)
* ================================================================ */
SPL_CORE_FN unsigned char *spl_asp_id_xlate(void *ctx, uintptr_t off, uintptr_t size) {
(void)ctx;
(void)size;
return (unsigned char *)off;
}
SPL_CORE_FN uintptr_t spl_asp_id_alloc(void *ctx, uintptr_t size) {
(void)ctx;
return (uintptr_t)malloc((size_t)size);
}
SPL_CORE_FN uintptr_t spl_asp_id_realloc(void *ctx, uintptr_t off, uintptr_t size) {
(void)ctx;
return (uintptr_t)realloc((void *)off, (size_t)size);
}
SPL_CORE_FN void spl_asp_id_free(void *ctx, uintptr_t off) {
(void)ctx;
free((void *)off);
}
SPL_CORE_FN uintptr_t spl_asp_id_to_off(void *ctx, const void *host, uintptr_t size) {
(void)ctx;
(void)size;
return (uintptr_t)host;
}
static const spl_asp_t spl_asp_identity = {
NULL, spl_asp_id_xlate, spl_asp_id_alloc, spl_asp_id_realloc, spl_asp_id_free,
spl_asp_id_to_off,
};
#define SPL_ASP_ID ((spl_asp_t *)&spl_asp_identity)
/* 偏移 -> 宿主(不做边界检查)。 */
SPL_CORE_FN unsigned char *spl_x(spl_asp_t *asp, uintptr_t off) {
return asp->xlate(asp->ctx, off, 0);
}
SPL_CORE_FN void *spl_xp(spl_asp_t *asp, uintptr_t off, uintptr_t size) {
return asp->xlate(asp->ctx, off, size);
}
/* ---------------- mem ---------------- */
SPL_CORE_FN void *spl_alloc_ex(spl_asp_t *asp, uintptr_t sz) {
if (sz == 0)
return NULL;
return (void *)asp->alloc(asp->ctx, sz);
}
SPL_CORE_FN void spl_free_ex(spl_asp_t *asp, void *p) {
if (p)
asp->free(asp->ctx, (uintptr_t)p);
}
SPL_CORE_FN void *spl_realloc_ex(spl_asp_t *asp, void *p, uintptr_t sz) {
if (!p)
return spl_alloc_ex(asp, sz);
if (sz == 0) {
asp->free(asp->ctx, (uintptr_t)p);
return NULL;
}
return (void *)asp->realloc(asp->ctx, (uintptr_t)p, sz);
}
SPL_CORE_FN void *vm_memcpy(void *dst, const void *src, uintptr_t n) {
if (n)
memcpy(dst, src, (size_t)n);
return dst;
}
SPL_CORE_FN void *vm_memmove(void *dst, const void *src, uintptr_t n) {
if (n)
memmove(dst, src, (size_t)n);
return dst;
}
SPL_CORE_FN intptr_t vm_memcmp(const void *a, const void *b, uintptr_t n) {
if (n == 0)
return 0;
return (intptr_t)memcmp(a, b, (size_t)n);
}
SPL_CORE_FN int spl_bytes_eq_ex(spl_asp_t *asp, const void *a, uintptr_t alen, const void *b,
uintptr_t blen) {
(void)asp;
if (alen != blen)
return 0;
if (alen == 0)
return 1;
if (!a || !b)
return 0;
return memcmp(a, b, (size_t)alen) == 0;
}
/* ---------------- Vec ---------------- */
typedef struct {
uintptr_t raw;
uintptr_t data;
uintptr_t len;
uintptr_t cap;
uintptr_t elem_size;
uintptr_t elem_align;
} spl_vec_t;
SPL_CORE_FN int spl_align_ok(uintptr_t a) { return a != 0 && (a & (a - 1)) == 0; }
SPL_CORE_FN int spl_vec_is_valid(const spl_vec_t *v) {
uintptr_t a;
if (v->elem_size == 0)
return 0;
a = v->elem_align;
if (a == 0 || (a & (a - 1)) != 0)
return 0;
if (v->len > v->cap)
return 0;
if (v->cap == 0)
return v->raw == 0 && v->data == 0 && v->len == 0;
if (v->raw == 0 || v->data == 0)
return 0;
return (v->data & (a - 1)) == 0;
}
SPL_CORE_FN void spl_grow_capacity(uintptr_t current, uintptr_t min_cap, uintptr_t need,
uintptr_t *out) {
uintptr_t cap = current < min_cap ? min_cap : current;
uintptr_t limit = ~(uintptr_t)0;
while (cap < need) {
if (cap > limit / 2) {
cap = need;
break;
}
cap = cap * 2;
}
*out = cap;
}
SPL_CORE_FN int spl_vec_allocate_ex(spl_asp_t *asp, spl_vec_t *out, uintptr_t capacity,
uintptr_t elem_size, uintptr_t elem_align) {
uintptr_t bytes, mask, addr;
uintptr_t raw;
if (elem_size == 0)
return 1;
if (!spl_align_ok(elem_align))
return 4;
out->raw = 0;
out->data = 0;
out->len = 0;
out->cap = 0;
out->elem_size = elem_size;
out->elem_align = elem_align;
if (capacity == 0)
return 0;
if (capacity > ~(uintptr_t)0 / elem_size)
return 3;
bytes = capacity * elem_size;
mask = elem_align - 1;
if (bytes > ~(uintptr_t)0 - mask)
return 3;
raw = asp->alloc(asp->ctx, bytes + mask);
if (!raw)
return 3;
addr = raw;
if (addr > ~(uintptr_t)0 - mask) {
asp->free(asp->ctx, raw);
return 3;
}
out->raw = raw;
out->data = (addr + mask) & ~mask;
out->cap = capacity;
return 0;
}
SPL_CORE_FN int spl_vec_reserve_raw_ex(spl_asp_t *asp, spl_vec_t *v, uintptr_t need) {
uintptr_t new_cap = 0, used = 0, old;
spl_vec_t fresh;
int rc;
if (need <= v->cap)
return 0;
spl_grow_capacity(v->cap, 8, need, &new_cap);
rc = spl_vec_allocate_ex(asp, &fresh, new_cap, v->elem_size, v->elem_align);
if (rc)
return rc;
if (v->len != 0) {
if (v->len > ~(uintptr_t)0 / v->elem_size) {
asp->free(asp->ctx, fresh.raw);
return 3;
}
used = v->len * v->elem_size;
}
if (used)
memcpy(spl_x(asp, fresh.data), spl_x(asp, v->data), used);
fresh.len = v->len;
old = v->raw;
*v = fresh;
if (old)
asp->free(asp->ctx, old);
return 0;
}
SPL_CORE_FN void spl_vec_release_ex(spl_asp_t *asp, spl_vec_t *v) {
uintptr_t es = v->elem_size, ea = v->elem_align;
if (v->raw)
asp->free(asp->ctx, v->raw);
v->raw = 0;
v->data = 0;
v->len = 0;
v->cap = 0;
v->elem_size = es;
v->elem_align = ea;
}
SPL_CORE_FN int spl_vec_valid_ex(const void *vv) {
return vv ? spl_vec_is_valid((const spl_vec_t *)vv) : 0;
}
SPL_CORE_FN int spl_vec_push_raw_ex(spl_asp_t *asp, void *vv, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !elem)
return 0;
if (v->len < v->cap) {
memcpy(spl_x(asp, v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 1;
}
return 0;
}
SPL_CORE_FN int spl_vec_push_ex(spl_asp_t *asp, void *vv, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
int rc;
if (!v || !elem || !spl_vec_is_valid(v))
return 1;
if (v->len < v->cap) {
memcpy(spl_x(asp, v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 0;
}
rc = spl_vec_reserve_raw_ex(asp, v, v->len + 1);
if (rc)
return rc;
memmove(spl_x(asp, v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 0;
}
SPL_CORE_FN int spl_vec_get_ex(spl_asp_t *asp, const void *vv, uintptr_t index, void **out) {
const spl_vec_t *v = (const spl_vec_t *)vv;
unsigned char *p;
if (!v || !out)
return 1;
if (!spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
p = spl_x(asp, v->data) + index * v->elem_size;
*out = (void *)(uintptr_t)asp->to_off(asp->ctx, p, v->elem_size);
return 0;
}
SPL_CORE_FN int spl_vec_allocate_out_ex(spl_asp_t *asp, void *out, uintptr_t capacity,
uintptr_t elem_size, uintptr_t elem_align) {
if (!out)
return 1;
return spl_vec_allocate_ex(asp, (spl_vec_t *)out, capacity, elem_size, elem_align);
}
SPL_CORE_FN int spl_vec_reserve_raw_void_ex(spl_asp_t *asp, void *vv, uintptr_t need) {
if (!vv)
return 1;
return spl_vec_reserve_raw_ex(asp, (spl_vec_t *)vv, need);
}
SPL_CORE_FN int spl_vec_append_ex(spl_asp_t *asp, void *vv, const void *elems, uintptr_t count) {
spl_vec_t *v = (spl_vec_t *)vv;
uintptr_t copy_bytes, new_len, used, source_offset = 0;
int source_inside = 0, rc;
if (!v || !spl_vec_is_valid(v))
return 1;
if (count == 0)
return 0;
if (!elems)
return 1;
if (count > ~(uintptr_t)0 / v->elem_size)
return 3;
copy_bytes = count * v->elem_size;
if (v->len > ~(uintptr_t)0 - count)
return 3;
new_len = v->len + count;
used = v->len * v->elem_size;
if (used) {
unsigned char *base = spl_x(asp, v->data);
uintptr_t source = (uintptr_t)elems;
if (source >= (uintptr_t)base && source - (uintptr_t)base < used) {
source_offset = source - (uintptr_t)base;
if (copy_bytes > used - source_offset)
return 2;
source_inside = 1;
}
}
rc = spl_vec_reserve_raw_ex(asp, v, new_len);
if (rc)
return rc;
if (source_inside)
elems = (const void *)(spl_x(asp, v->data) + source_offset);
memmove(spl_x(asp, v->data + used), elems, copy_bytes);
v->len = new_len;
return 0;
}
SPL_CORE_FN int spl_vec_set_ex(spl_asp_t *asp, void *vv, uintptr_t index, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !elem || !spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
memmove(spl_x(asp, v->data + index * v->elem_size), elem, v->elem_size);
return 0;
}
SPL_CORE_FN int spl_vec_pop_ex(spl_asp_t *asp, void *vv, void *out) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !out || !spl_vec_is_valid(v))
return 1;
if (v->len == 0)
return 2;
memmove(out, spl_x(asp, v->data + (v->len - 1) * v->elem_size), v->elem_size);
v->len--;
return 0;
}
SPL_CORE_FN int spl_vec_clone_ex(spl_asp_t *asp, void *outp, const void *srcp) {
spl_vec_t *out = (spl_vec_t *)outp;
const spl_vec_t *src = (const spl_vec_t *)srcp;
spl_vec_t fresh;
uintptr_t bytes;
int rc;
if (!out || !src || !spl_vec_is_valid(out) || !spl_vec_is_valid(src))
return 1;
if (out->elem_size != src->elem_size || out->elem_align != src->elem_align)
return 1;
fresh.raw = 0;
fresh.data = 0;
fresh.len = 0;
fresh.cap = 0;
fresh.elem_size = src->elem_size;
fresh.elem_align = src->elem_align;
rc = spl_vec_reserve_raw_ex(asp, &fresh, src->len);
if (rc)
return rc;
bytes = src->len * src->elem_size;
if (bytes)
memcpy(spl_x(asp, fresh.data), spl_x(asp, src->data), bytes);
fresh.len = src->len;
if (out->raw)
asp->free(asp->ctx, out->raw);
*out = fresh;
return 0;
}
SPL_CORE_FN int spl_vec_drop_ex(spl_asp_t *asp, void *vv) {
if (vv)
spl_vec_release_ex(asp, (spl_vec_t *)vv);
return 0;
}
/* ---------------- Map ---------------- */
typedef struct {
spl_vec_t keys;
spl_vec_t vals;
spl_vec_t states;
uintptr_t size;
uintptr_t key_size;
uintptr_t val_size;
uintptr_t hash_kind;
} spl_map_t;
SPL_CORE_FN uintptr_t spl_hash_usize_value(uintptr_t value) {
uintptr_t prime = 1099511628211ull;
uintptr_t h = value;
h = (h ^ (h >> 30)) * prime;
h = h ^ (h >> 27);
h = h * prime;
h = h ^ (h >> 31);
if (h == 0)
return prime;
return h;
}
SPL_CORE_FN uintptr_t spl_hash_bytes(const void *data, uintptr_t len) {
const unsigned char *p = (const unsigned char *)data;
uintptr_t h = 14695981039346656037ull;
uintptr_t prime = 1099511628211ull;
uintptr_t i;
for (i = 0; i < len; i++)
h = (h ^ (uintptr_t)p[i]) * prime;
return h;
}
SPL_CORE_FN uintptr_t spl_hash_bytes_ex(spl_asp_t *asp, const void *data, uintptr_t len) {
return spl_hash_bytes(spl_x(asp, (uintptr_t)data), len);
}
SPL_CORE_FN uintptr_t spl_map_hash_ex(spl_asp_t *asp, const spl_map_t *m, const void *key) {
const uintptr_t *v;
if (m->hash_kind == 0)
return spl_hash_usize_value(*(const uintptr_t *)key);
if (m->hash_kind == 2)
return 3;
v = (const uintptr_t *)key;
return spl_hash_bytes_ex(asp, (const void *)v[0], v[1]);
}
SPL_CORE_FN int spl_map_eq_ex(spl_asp_t *asp, const spl_map_t *m, const void *a, const void *b) {
const uintptr_t *x;
const uintptr_t *y;
if (m->hash_kind == 0 || m->hash_kind == 2)
return *(const uintptr_t *)a == *(const uintptr_t *)b;
x = (const uintptr_t *)a;
y = (const uintptr_t *)b;
if (x[1] != y[1])
return 0;
if (x[1] == 0)
return 1;
return memcmp(spl_x(asp, x[0]), spl_x(asp, y[0]), (size_t)x[1]) == 0;
}
SPL_CORE_FN int spl_map_valid(const spl_map_t *m) {
if (m->key_size == 0 || m->val_size == 0)
return 0;
if (m->keys.len != m->states.len || m->vals.len != m->states.len)
return 0;
if (m->size > m->states.len)
return 0;
return 1;
}
SPL_CORE_FN uintptr_t spl_map_find_slot_ex(spl_asp_t *asp, const spl_map_t *m, const void *key) {
uintptr_t mask, i, probes;
unsigned char *st;
if (m->states.cap == 0)
return ~(uintptr_t)0;
mask = m->states.cap - 1;
i = spl_map_hash_ex(asp, m, key) & mask;
st = spl_x(asp, m->states.data);
probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 1 &&
spl_map_eq_ex(asp, m, spl_x(asp, m->keys.data + i * m->key_size), key))
return i;
i = (i + 1) & mask;
probes++;
}
return ~(uintptr_t)0;
}
SPL_CORE_FN void spl_map_place_ex(spl_asp_t *asp, spl_map_t *m, const void *key, const void *val) {
uintptr_t mask = m->states.cap - 1;
uintptr_t i = spl_map_hash_ex(asp, m, key) & mask;
unsigned char *st = spl_x(asp, m->states.data);
uintptr_t first_deleted = ~(uintptr_t)0;
uintptr_t probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 2 && first_deleted == ~(uintptr_t)0)
first_deleted = i;
i = (i + 1) & mask;
probes++;
}
if (first_deleted != ~(uintptr_t)0)
i = first_deleted;
memcpy(spl_x(asp, m->keys.data + i * m->key_size), key, m->key_size);
memcpy(spl_x(asp, m->vals.data + i * m->val_size), val, m->val_size);
st[i] = 1;
m->size++;
}
SPL_CORE_FN int spl_map_reserve_ex(spl_asp_t *asp, spl_map_t *m, uintptr_t need) {
uintptr_t new_cap = 0, i;
spl_map_t fresh;
int rc;
if (!spl_map_valid(m))
return 1;
if (need <= m->states.cap)
return 0;
spl_grow_capacity(m->states.cap, 8, need, &new_cap);
fresh = *m;
fresh.keys.raw = 0;
fresh.keys.data = 0;
fresh.keys.len = 0;
fresh.keys.cap = 0;
fresh.vals.raw = 0;
fresh.vals.data = 0;
fresh.vals.len = 0;
fresh.vals.cap = 0;
fresh.states.raw = 0;
fresh.states.data = 0;
fresh.states.len = 0;
fresh.states.cap = 0;
fresh.size = 0;
rc = spl_vec_reserve_raw_ex(asp, &fresh.keys, new_cap);
if (rc)
goto fail;
rc = spl_vec_reserve_raw_ex(asp, &fresh.vals, new_cap);
if (rc)
goto fail;
rc = spl_vec_reserve_raw_ex(asp, &fresh.states, new_cap);
if (rc)
goto fail;
fresh.keys.len = new_cap;
fresh.vals.len = new_cap;
fresh.states.len = new_cap;
memset(spl_x(asp, fresh.states.data), 0, new_cap);
for (i = 0; i < m->states.len; i++) {
if (spl_x(asp, m->states.data)[i] == 1)
spl_map_place_ex(asp, &fresh, spl_x(asp, m->keys.data + i * m->key_size),
spl_x(asp, m->vals.data + i * m->val_size));
}
spl_vec_release_ex(asp, &m->keys);
spl_vec_release_ex(asp, &m->vals);
spl_vec_release_ex(asp, &m->states);
*m = fresh;
return 0;
fail:
spl_vec_release_ex(asp, &fresh.keys);
spl_vec_release_ex(asp, &fresh.vals);
spl_vec_release_ex(asp, &fresh.states);
return rc;
}
SPL_CORE_FN int spl_map_valid_ex(const void *mm) {
return mm ? spl_map_valid((const spl_map_t *)mm) : 0;
}
SPL_CORE_FN int spl_map_reserve_void_ex(spl_asp_t *asp, void *mm, uintptr_t need) {
if (!mm)
return 1;
return spl_map_reserve_ex(asp, (spl_map_t *)mm, need);
}
SPL_CORE_FN int spl_map_put_ex(spl_asp_t *asp, void *mm, const void *key, const void *val) {
spl_map_t *m = (spl_map_t *)mm;
uintptr_t existing;
if (!m || !key || !val || !spl_map_valid(m))
return 1;
existing = spl_map_find_slot_ex(asp, m, key);
if (existing != ~(uintptr_t)0) {
memcpy(spl_x(asp, m->vals.data + existing * m->val_size), val, m->val_size);
return 0;
}
if (m->states.cap == 0) {
int rc = spl_map_reserve_ex(asp, m, 8);
if (rc)
return rc;
} else {
uintptr_t next_size, scaled;
if (m->size > ~(uintptr_t)0 - 1)
return 3;
next_size = m->size + 1;
if (next_size > ~(uintptr_t)0 / 128)
return 3;
scaled = next_size * 128;
if (scaled / m->states.cap >= 70) {
int rc;
if (m->states.cap > ~(uintptr_t)0 / 2)
return 3;
rc = spl_map_reserve_ex(asp, m, m->states.cap * 2);
if (rc)
return rc;
}
}
spl_map_place_ex(asp, m, key, val);
return 0;
}
SPL_CORE_FN int spl_map_get_ex(spl_asp_t *asp, void *mm, const void *key, void *out) {
spl_map_t *m = (spl_map_t *)mm;
uintptr_t i;
if (!m || !key || !out || !spl_map_valid(m))
return 1;
i = spl_map_find_slot_ex(asp, m, key);
if (i == ~(uintptr_t)0)
return 1;
memcpy(out, spl_x(asp, m->vals.data + i * m->val_size), m->val_size);
return 0;
}
SPL_CORE_FN int spl_map_del_ex(spl_asp_t *asp, void *mm, const void *key) {
spl_map_t *m = (spl_map_t *)mm;
uintptr_t i;
if (!m || !key || !spl_map_valid(m))
return 1;
i = spl_map_find_slot_ex(asp, m, key);
if (i == ~(uintptr_t)0)
return 1;
spl_x(asp, m->states.data)[i] = 2;
m->size--;
return 0;
}
SPL_CORE_FN int spl_map_clear_ex(spl_asp_t *asp, void *mm) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return 0;
if (m->states.data && m->states.len)
memset(spl_x(asp, m->states.data), 0, m->states.len);
m->size = 0;
return 0;
}
SPL_CORE_FN int spl_map_drop_ex(spl_asp_t *asp, void *mm) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return 0;
spl_vec_release_ex(asp, &m->keys);
spl_vec_release_ex(asp, &m->vals);
spl_vec_release_ex(asp, &m->states);
m->size = 0;
return 0;
}
/* ================================================================
* 公开 C 符号(identity):供 native 编译器直接调用
* ================================================================ */
SPL_CORE_FN void *vm_alloc(uintptr_t sz) { return spl_alloc_ex(SPL_ASP_ID, sz); }
SPL_CORE_FN void vm_free(void *p) { spl_free_ex(SPL_ASP_ID, p); }
SPL_CORE_FN void *vm_realloc(void *p, uintptr_t sz) { return spl_realloc_ex(SPL_ASP_ID, p, sz); }
SPL_CORE_FN int vm_bytes_eq(const void *a, uintptr_t alen, const void *b, uintptr_t blen) {
return spl_bytes_eq_ex(SPL_ASP_ID, a, alen, b, blen);
}
SPL_CORE_FN int vm_vec_valid(const void *v) { return spl_vec_valid_ex(v); }
SPL_CORE_FN int vm_vec_push_raw(void *v, const void *e) {
return spl_vec_push_raw_ex(SPL_ASP_ID, v, e);
}
SPL_CORE_FN int vm_vec_push(void *v, const void *e) { return spl_vec_push_ex(SPL_ASP_ID, v, e); }
SPL_CORE_FN int vm_vec_get(const void *v, uintptr_t i, void **o) {
return spl_vec_get_ex(SPL_ASP_ID, v, i, o);
}
SPL_CORE_FN int vm_vec_allocate(void *o, uintptr_t c, uintptr_t es, uintptr_t ea) {
return spl_vec_allocate_out_ex(SPL_ASP_ID, o, c, es, ea);
}
SPL_CORE_FN int vm_vec_reserve_raw(void *v, uintptr_t n) {
return spl_vec_reserve_raw_void_ex(SPL_ASP_ID, v, n);
}
SPL_CORE_FN int vm_vec_append(void *v, const void *e, uintptr_t n) {
return spl_vec_append_ex(SPL_ASP_ID, v, e, n);
}
SPL_CORE_FN int vm_vec_set(void *v, uintptr_t i, const void *e) {
return spl_vec_set_ex(SPL_ASP_ID, v, i, e);
}
SPL_CORE_FN int vm_vec_pop(void *v, void *o) { return spl_vec_pop_ex(SPL_ASP_ID, v, o); }
SPL_CORE_FN int vm_vec_clone(void *o, const void *s) { return spl_vec_clone_ex(SPL_ASP_ID, o, s); }
SPL_CORE_FN int vm_vec_drop(void *v) { return spl_vec_drop_ex(SPL_ASP_ID, v); }
SPL_CORE_FN int vm_map_valid(const void *m) { return spl_map_valid_ex(m); }
SPL_CORE_FN int vm_map_reserve(void *m, uintptr_t n) {
return spl_map_reserve_void_ex(SPL_ASP_ID, m, n);
}
SPL_CORE_FN int vm_map_put(void *m, const void *k, const void *v) {
return spl_map_put_ex(SPL_ASP_ID, m, k, v);
}
SPL_CORE_FN int vm_map_get(void *m, const void *k, void *o) {
return spl_map_get_ex(SPL_ASP_ID, m, k, o);
}
SPL_CORE_FN int vm_map_del(void *m, const void *k) { return spl_map_del_ex(SPL_ASP_ID, m, k); }
SPL_CORE_FN int vm_map_clear(void *m) { return spl_map_clear_ex(SPL_ASP_ID, m); }
SPL_CORE_FN int vm_map_drop(void *m) { return spl_map_drop_ex(SPL_ASP_ID, m); }
#endif /* __SPL_RT_CORE_H__ */
+544 -828
View File
File diff suppressed because it is too large. Load diff
+401 -28
View File
@@ -568,6 +568,18 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) {
vec_realloc(vm->frames, (usize)vm->config.max_call_depth);
vec_init(vm->breakpoints);
vec_init(vm->fn_breakpoints);
vec_init(vm->gdata_off);
vec_init(vm->regions);
/* regions[0] 保留;regions[1] = 栈区。 */
vec_push(vm->regions, ((spl_vm_region_t){NULL, 0, 0}));
vec_push(vm->regions, ((spl_vm_region_t){
(unsigned char *)vm->stacks.data,
(usize)vm->config.max_stack_depth * sizeof(spl_vm_val_t), 1}));
vm->stdio_off[0] = vm->stdio_off[1] = vm->stdio_off[2] = 0;
vm->ret_val = 0;
vm->foreign = NULL;
vm->foreign_ctx = NULL;
vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0;
vm->steps = 0;
@@ -593,9 +605,206 @@ void spl_vm_drop(spl_vm_t *vm) {
free(vm->fn_breakpoints.data[i]);
vec_free(vm->fn_breakpoints);
vec_free(vm->breakpoints);
vec_free(vm->gdata_off);
for (usize i = 2; i < vec_size(vm->regions); i++) {
spl_vm_region_t *r = &vec_at(vm->regions, i);
if (r->used && r->base)
free(r->base);
}
vec_free(vm->regions);
spl_vm_profile_free(vm);
}
/* ================================================================
* 统一偏移地址空间:offset = (handle<<32) | 区内字节偏移
* ================================================================ */
#define SPL_ASP_HANDLE_OF(off) ((usize)((spl_vm_val_t)(off) >> 32))
#define SPL_ASP_BYTE_OF(off) ((usize)((spl_vm_val_t)(off) & 0xFFFFFFFFull))
static spl_vm_region_t *spl_vm_region_at(spl_vm_t *vm, usize handle) {
if (handle == 0 || handle >= vec_size(vm->regions))
return NULL;
return &vec_at(vm->regions, handle);
}
void *spl_vm_xlate(spl_vm_t *vm, spl_vm_val_t off, usize size) {
usize handle, byte;
spl_vm_region_t *r;
if (!vm || off == SPL_OFF_NULL)
return NULL;
handle = SPL_ASP_HANDLE_OF(off);
byte = SPL_ASP_BYTE_OF(off);
r = spl_vm_region_at(vm, handle);
if (!r || !r->used)
return NULL;
if (byte > r->size || (size > 0 && byte + size > r->size))
return NULL;
return (void *)(r->base + byte);
}
spl_vm_val_t spl_vm_to_off(spl_vm_t *vm, const void *ptr) {
if (!vm || !ptr)
return SPL_OFF_NULL;
{
unsigned char *p = (unsigned char *)ptr;
usize i;
for (i = 1; i < vec_size(vm->regions); i++) {
spl_vm_region_t *r = &vec_at(vm->regions, i);
if (r->used && r->base && p >= r->base && p < r->base + r->size)
return SPL_ASP_OFF(i, (usize)(p - r->base));
}
}
return SPL_OFF_NULL;
}
/* 返回用于存放该偏移的 handle 槽;找不到空闲/空间不足返回 0。 */
static usize spl_vm_region_new(spl_vm_t *vm, void *base, usize size) {
usize i;
for (i = 2; i < vec_size(vm->regions); i++) {
spl_vm_region_t *r = &vec_at(vm->regions, i);
if (!r->used) {
r->base = (unsigned char *)base;
r->size = size;
r->used = 1;
return i;
}
}
if (vec_size(vm->regions) >= (usize)1 << 32)
return 0;
vec_push(vm->regions, ((spl_vm_region_t){(unsigned char *)base, size, 1}));
return vec_size(vm->regions) - 1;
}
/* ---- spl_asp_t 实现 ---- */
static unsigned char *spl_vm_asp_xlate(void *ctx, uintptr_t off, uintptr_t size) {
return (unsigned char *)spl_vm_xlate((spl_vm_t *)ctx, (spl_vm_val_t)off, (usize)size);
}
static uintptr_t spl_vm_asp_alloc(void *ctx, uintptr_t size) {
spl_vm_t *vm = (spl_vm_t *)ctx;
void *p;
usize h;
if (size == 0 || size > 0xFFFFFFFFull)
return 0;
p = malloc((size_t)size);
if (!p)
return 0;
h = spl_vm_region_new(vm, p, (usize)size);
if (h == 0) {
free(p);
return 0;
}
return (uintptr_t)SPL_ASP_OFF(h, 0);
}
static uintptr_t spl_vm_asp_realloc(void *ctx, uintptr_t off, uintptr_t size) {
spl_vm_t *vm = (spl_vm_t *)ctx;
spl_vm_region_t *r;
void *np;
usize h;
if (size == 0 || size > 0xFFFFFFFFull)
return 0;
if (off == 0)
return spl_vm_asp_alloc(ctx, size);
h = SPL_ASP_HANDLE_OF(off);
r = spl_vm_region_at(vm, h);
if (!r || !r->used)
return 0;
np = realloc(r->base, (size_t)size);
if (!np)
return 0;
r->base = (unsigned char *)np;
r->size = (usize)size;
return (uintptr_t)SPL_ASP_OFF(h, SPL_ASP_BYTE_OF(off) & 0);
}
static void spl_vm_asp_free(void *ctx, uintptr_t off) {
spl_vm_t *vm = (spl_vm_t *)ctx;
usize h;
spl_vm_region_t *r;
if (off == 0 || !vm)
return;
h = SPL_ASP_HANDLE_OF(off);
if (h < 2) /* 0/1 不可释放 */
return;
r = spl_vm_region_at(vm, h);
if (!r || !r->used)
return;
free(r->base);
r->base = NULL;
r->size = 0;
r->used = 0;
}
static uintptr_t spl_vm_asp_to_off(void *ctx, const void *host, uintptr_t size) {
(void)size;
return (uintptr_t)spl_vm_to_off((spl_vm_t *)ctx, host);
}
spl_asp_t *spl_vm_asp(spl_vm_t *vm) {
if (!vm)
return NULL;
vm->asp.ctx = vm;
vm->asp.xlate = spl_vm_asp_xlate;
vm->asp.alloc = spl_vm_asp_alloc;
vm->asp.realloc = spl_vm_asp_realloc;
vm->asp.free = spl_vm_asp_free;
vm->asp.to_off = spl_vm_asp_to_off;
return &vm->asp;
}
/* ================================================================
* 动态外部回调 + 栈/结果/内存访问
* ================================================================ */
void spl_vm_set_foreign(spl_vm_t *vm, spl_vm_foreign_fn fn, void *ctx) {
if (!vm)
return;
vm->foreign = fn;
vm->foreign_ctx = ctx;
}
spl_vm_val_t spl_vm_ret_val(spl_vm_t *vm) { return vm ? vm->ret_val : 0; }
usize spl_vm_sp(spl_vm_t *vm) { return vm ? (usize)vm->sp : 0; }
usize spl_vm_fp(spl_vm_t *vm) { return vm ? (usize)vm->fp : 0; }
spl_vm_val_t spl_vm_stack_get(spl_vm_t *vm, usize index) {
if (!vm || index >= (usize)vm->config.max_stack_depth || !vm->stacks.data)
return 0;
return vm->stacks.data[index];
}
int spl_vm_stack_set(spl_vm_t *vm, usize index, spl_vm_val_t val) {
if (!vm || index >= (usize)vm->config.max_stack_depth || !vm->stacks.data)
return -1;
vm->stacks.data[index] = val;
return 0;
}
spl_vm_val_t spl_vm_mem_alloc(spl_vm_t *vm, usize size) { return spl_vm_asp_alloc(vm, size); }
int spl_vm_mem_read(spl_vm_t *vm, spl_vm_val_t off, void *dst, usize n) {
void *src = spl_vm_xlate(vm, off, n);
if ((!src || !dst) && n)
return -1;
if (n)
memcpy(dst, src, n);
return 0;
}
int spl_vm_mem_write(spl_vm_t *vm, spl_vm_val_t off, const void *src, usize n) {
void *dst = spl_vm_xlate(vm, off, n);
if ((!dst || !src) && n)
return -1;
if (n)
memcpy(dst, src, n);
return 0;
}
// FIXME
int spl_vm_addr_valid(uintptr_t p, usize size) {
if (p == 0)
@@ -685,6 +894,35 @@ int spl_vm_load_prog(spl_vm_t *vm, spl_prog_t *prog) {
if (!vm || !prog)
return -1;
vm->prog = prog;
/* 释放上一次加载的堆分配(保留 regions[0]/[1])。 */
for (usize i = 2; i < vec_size(vm->regions); i++) {
spl_vm_region_t *r = &vec_at(vm->regions, i);
if (r->used && r->base)
free(r->base);
r->base = NULL;
r->size = 0;
r->used = 0;
}
/* 把 prog 的常量段搬进本 VM 空间,并记录每个 gdata 的偏移;
* gdata 索引 0 为哨兵,偏移 0(null)。 */
vm->gdata_off.size = 0;
vec_push(vm->gdata_off, (usize)SPL_OFF_NULL);
for (usize i = 1; i < vec_size(prog->gdata); i++) {
spl_vm_gdata_t *gd = &vec_at(prog->gdata, i);
usize sz = gd->size ? gd->size : 1;
spl_vm_val_t off = spl_vm_asp_alloc(vm, sz);
unsigned char *dst;
if (off == SPL_OFF_NULL)
return -1;
dst = (unsigned char *)spl_vm_xlate(vm, off, sz);
if (!dst)
return -1;
if (gd->data && gd->size)
memcpy(dst, gd->data, gd->size);
vec_push(vm->gdata_off, (usize)off);
}
return 0;
}
@@ -707,21 +945,53 @@ void spl_vm_set_debug(spl_vm_t *vm, int enabled) {
#define STACK_CANARY(vm) (vm)->stacks.data[(vm)->fp - 1]
/* 把 C 字符串复制进 VM 空间,返回其偏移。 */
static spl_vm_val_t spl_vm_marshal_cstr(spl_vm_t *vm, const char *s) {
usize n = s ? strlen(s) + 1 : 1;
spl_vm_val_t off = spl_vm_asp_alloc(vm, n);
unsigned char *d;
if (off == 0)
return 0;
d = (unsigned char *)spl_vm_xlate(vm, off, n);
if (!d)
return 0;
if (s)
memcpy(d, s, n);
else
d[0] = 0;
return off;
}
/* 把 argv/envp 指针数组整体编组进 VM 空间,返回数组偏移。 */
static spl_vm_val_t spl_vm_marshal_argv(spl_vm_t *vm, int argc, const char **argv) {
usize bytes = (usize)(argc + 1) * sizeof(spl_vm_val_t);
spl_vm_val_t arr = spl_vm_asp_alloc(vm, bytes);
spl_vm_val_t *slots;
int i;
if (arr == 0)
return 0;
slots = (spl_vm_val_t *)spl_vm_xlate(vm, arr, bytes);
if (!slots)
return 0;
for (i = 0; i < argc; i++)
slots[i] = spl_vm_marshal_cstr(vm, argv ? argv[i] : NULL);
slots[argc] = 0;
return arr;
}
/* ABI:调用者在实参下方预留 2 个空闲 slot(PAD0/PAD1)。
* fp 指向 arg0;fp-1 为栈金丝雀槽,fp-2 为空闲槽。
* saved_sp = fp-2(调用者压参数前的 sp)。 */
#define SPL_CALL_PADS 2
static inline int spl_vm_call(spl_vm_t *vm, spl_vm_val_t addr, spl_vm_val_t nargs) {
uintptr_t saved_sp;
if (vm->cp >= vm->config.max_call_depth)
VM_ERROR("call depth exceeded");
if (vm->sp < nargs + SPL_CALL_PADS)
VM_ERROR("call: stack underflow (missing pads)");
uintptr_t saved_sp;
if (vm->debug) {
/* debug:在 fp-1 留金丝雀位,需要把实参右移一格。 */
PUSH(SPL_STACK_CANARY);
for (usize i = vm->sp; i >= vm->sp - nargs; --i)
vm->stacks.data[i] = vm->stacks.data[i - 1];
saved_sp = vm->sp - nargs - 1;
} else {
/* 非 debug:不做金丝雀搬移;实参在 sp-nargs..sp-1,fp 指向 arg0。 */
saved_sp = vm->sp - nargs;
}
saved_sp = vm->sp - nargs - SPL_CALL_PADS;
spl_callframe_t *fr = &vm->frames.data[vm->cp];
fr->saved_sp = saved_sp;
@@ -736,6 +1006,33 @@ static inline int spl_vm_call(spl_vm_t *vm, spl_vm_val_t addr, spl_vm_val_t narg
return 0;
}
/* 入口调用:按名字调用顶层函数(同 CALL 的 ABI,实参+2 pads 已由调用方压好)。 */
int spl_vm_call_entry(spl_vm_t *vm, const char *name, int nargs) {
spl_vm_func_t *func;
if (!vm || !vm->prog || !name)
return -1;
func = spl_prog_get_func(vm->prog, name);
if (!func)
return -1;
if (vm->cp >= vm->config.max_call_depth)
return -1;
if (vm->sp < (usize)nargs + SPL_CALL_PADS)
return -1;
vm->ip = (usize)-1;
vm->cp = 0;
vm->fp = 0;
vm->frames.data[0].saved_sp = vm->sp - (usize)nargs - SPL_CALL_PADS;
vm->frames.data[0].saved_fp = vm->fp;
vm->frames.data[0].saved_ip = vm->ip;
vm->frames.data[0].nargs = (spl_vm_val_t)nargs;
vm->cp = 1;
vm->ip = (usize)func->address;
vm->fp = vm->sp - (usize)nargs;
if (vm->debug && vm->fp > 0)
STACK_CANARY(vm) = SPL_STACK_CANARY;
return 0;
}
int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv,
const char **envp) {
if (!vm || !vm->prog) {
@@ -757,15 +1054,22 @@ int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv,
vm->cp = 0;
vm->ip = -1;
vm->exit_code = 0;
vm->ret_val = 0;
/* ABI:入口也在实参下方预留 2 个空闲 slot。 */
PUSH(0);
PUSH(0);
if (fn->nargs >= 1) {
PUSH(argc);
}
if (fn->nargs >= 2) {
PUSH(argv);
PUSH(spl_vm_marshal_argv(vm, argc, argv));
}
if (fn->nargs >= 3) {
PUSH(envp);
int envc = 0;
while (envp && envp[envc])
envc++;
PUSH(spl_vm_marshal_argv(vm, envc, envp));
}
if (fn->nargs >= 4) {
printf("the start symbol can't using more than 3 args");
@@ -777,6 +1081,53 @@ int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv,
return 0;
}
/* 外部 -> VM 的调用:保存外层状态,按当前深度建帧跑到边界,读结果后恢复。
* 可在 VM 运行中(如外部回调内)安全调用。 */
int spl_vm_invoke(spl_vm_t *vm, spl_vm_call_t *call) {
spl_vm_func_t *fn;
uintptr_t s_ip, s_fp, s_sp, s_cp;
int s_exit, i, r;
spl_vm_val_t s_ret;
if (!vm || !vm->prog || !call || !call->name)
return -1;
fn = spl_prog_get_func(vm->prog, call->name);
if (!fn)
return -1;
s_ip = vm->ip;
s_fp = vm->fp;
s_sp = vm->sp;
s_cp = vm->cp;
s_exit = vm->exit_code;
s_ret = vm->ret_val;
PUSH(0);
PUSH(0);
for (i = 0; i < (int)call->nargs; i++)
PUSH(call->args ? call->args[i] : 0);
/* sentinel:本次调用的 RET 视为边界(与入口调用一致)。 */
vm->ip = (spl_vm_val_t)-1;
if (spl_vm_call(vm, fn->address, (spl_vm_val_t)call->nargs) != 0) {
vm->ip = s_ip;
vm->fp = s_fp;
vm->sp = s_sp;
vm->cp = s_cp;
vm->exit_code = s_exit;
vm->ret_val = s_ret;
return -1;
}
r = spl_vm_run_until(vm, 0);
call->ret = vm->ret_val;
vm->ip = s_ip;
vm->fp = s_fp;
vm->sp = s_sp;
vm->cp = s_cp;
vm->exit_code = s_exit;
vm->ret_val = s_ret;
return r < 0 ? -1 : 0;
}
/* ================================================================
* spl_vm_run_once - execute one instruction
*
@@ -817,7 +1168,7 @@ static uint64_t prof_now_ns(void) {
}
static void spl_vm_sample(spl_vm_t *vm) {
spl_prof_t *p = (spl_prof_t *)vm->profile;
spl_prof_t *p = vm->profile;
spl_prog_t *prog = vm->prog;
if (!p || !prog)
return;
@@ -862,7 +1213,7 @@ static void spl_vm_sample(spl_vm_t *vm) {
usize old = 0;
if (map_get(p->stacks, buf, &old)) {
map_put(p->stacks, buf, old + 1);
map_put(p->stacks, strdup(buf), old + 1);
} else {
map_put(p->stacks, strdup(buf), (usize)1);
}
@@ -1250,6 +1601,8 @@ L_SPL_RET:
intptr_t _saved_ip = vm->frames.data[vm->cp].saved_ip;
/* entry return -> halt */
if (_saved_ip < 0) {
PUSH(_retval);
vm->ret_val = _retval;
vm->exit_code = (int)_retval;
return 1;
}
@@ -1263,6 +1616,7 @@ L_SPL_RET:
}
L_SPL_HALT:
vm->ret_val = ins->imm;
if (ins->imm)
vm->exit_code = (int)ins->imm;
return 1;
@@ -1281,7 +1635,8 @@ L_SPL_ALLOC:
}
L_SPL_LADDR:
PUSH((spl_vm_val_t)((char *)(vm->stacks.data + vm->fp) + ins->imm));
PUSH(SPL_ASP_OFF(SPL_ASP_HANDLE_STACK,
(spl_vm_val_t)vm->fp * sizeof(spl_vm_val_t) + ins->imm));
DISPATCH();
L_SPL_GADDR:
@@ -1289,20 +1644,22 @@ L_SPL_GADDR:
spl_vm_val_t _idx = ins->imm;
if (_idx == 0 || _idx >= vec_size(prog->gdata))
VM_ERROR("GADDR: global data index out of range");
spl_vm_gdata_t *gd = &vec_at(prog->gdata, _idx);
if (!gd->data)
VM_ERROR("GADDR: null gdata entry");
PUSH((spl_vm_val_t)(uintptr_t)gd->data);
if (_idx >= vec_size(vm->gdata_off))
VM_ERROR("GADDR: global data not mapped");
PUSH((spl_vm_val_t)vec_at(vm->gdata_off, _idx));
DISPATCH();
}
/* ========== Indirect Memory (load/store with types) ========== */
L_SPL_LOAD:
{
void *_addr = (void *)POP();
CHECK_ADDR(_addr, "LOAD");
spl_vm_val_t _off = POP();
void *_addr;
spl_vm_val_t _v = 0;
usize _sz = spl_type_size(ins->type);
_addr = spl_vm_xlate(vm, _off, _sz);
if (!_addr)
VM_ERROR("LOAD: invalid address");
memcpy(&_v, _addr, _sz);
/* Sign-extend signed integer types smaller than 64 bits */
if (_sz > 0 && _sz < sizeof(spl_vm_val_t) && spl_is_signed(ins->type)) {
@@ -1315,8 +1672,10 @@ L_SPL_LOAD:
L_SPL_STORE:
{
spl_vm_val_t _v = POP();
void *_addr = (void *)POP();
CHECK_ADDR(_addr, "STORE");
spl_vm_val_t _off = POP();
void *_addr = spl_vm_xlate(vm, _off, spl_type_size(ins->type));
if (!_addr)
VM_ERROR("STORE: invalid address");
memcpy(_addr, &_v, spl_type_size(ins->type));
DISPATCH();
}
@@ -1374,13 +1733,23 @@ L_SPL_NCALL:
if (_nat_idx >= vec_size(prog->natives))
VM_ERROR("NCALL: native index out of range");
_nat = &vec_at(prog->natives, _nat_idx);
if (!_nat->impl_fn) {
spl_vm_val_t *_arg_base = vm->stacks.data + vm->sp - _nargs;
spl_vm_val_t _result;
if (_nat->impl_fn) {
_result = _nat->impl_fn(vm, _nargs, _arg_base);
} else if (vm->foreign) {
/* 线 1 动态:交给按名的外部函数处理器。 */
spl_vm_call_t _call;
_call.name = _nat->name ? _nat->name : "";
_call.args = _arg_base;
_call.nargs = (usize)_nargs;
_call.ret = 0;
_result = vm->foreign(vm, &_call, vm->foreign_ctx);
} else {
snprintf(vm->error_msg, sizeof(vm->error_msg),
"NCALL: NULL native function pointer expect %s", _nat->name);
VM_ERROR(vm->error_msg);
}
spl_vm_val_t *_arg_base = vm->stacks.data + vm->sp - _nargs;
spl_vm_val_t _result = _nat->impl_fn(vm, _nargs, _arg_base);
if (vm->exit_code) {
snprintf(vm->error_msg, sizeof(vm->error_msg), "NCALL %s failed (ip=%zd)",
_nat->name ? _nat->name : "?", vm->ip - 1);
@@ -1442,7 +1811,11 @@ L_default:
return -1;
}
int spl_vm_run_once(spl_vm_t *vm) { return vm_loop(vm, 1); }
int spl_vm_run_once(spl_vm_t *vm) {
if (!vm)
return -1;
return vm_loop(vm, 1);
}
int spl_vm_run_until(spl_vm_t *vm, size_t step) {
if (!vm)
+68 -5
View File
@@ -5,11 +5,25 @@
#include "include/core_map.h"
#include "include/core_vec.h"
#include "spl_asp.h"
#include "spl_mcode.h"
#include <stdint.h>
#define SPL_STACK_CANARY ((spl_vm_val_t)0xDEADBEEFCAFEBABEull)
/* 统一偏移地址空间:SPL 侧指针一律是句柄/偏移,0 保留为 null。
* offset = (handle<<32) | 区内字节偏移;handle 1 = 栈,handle>=2 = 堆分配。 */
#define SPL_OFF_NULL ((spl_vm_val_t)0)
#define SPL_ASP_HANDLE_STACK ((spl_vm_val_t)1)
#define SPL_ASP_OFF(handle, byte) ((((spl_vm_val_t)(handle)) << 32) | (spl_vm_val_t)(byte))
typedef struct {
unsigned char *base;
usize size;
int used;
} spl_vm_region_t;
typedef VEC(spl_vm_region_t) spl_vm_region_vec_t;
typedef struct {
uintptr_t saved_sp;
uintptr_t saved_fp;
@@ -20,6 +34,18 @@ typedef struct {
typedef VEC(spl_vm_val_t) spl_stack_vec_t;
typedef VEC(spl_callframe_t) spl_frame_vec_t;
/* 一次调用描述(VM <-> 外部两侧统一形状)。 */
typedef struct {
const char *name;
const spl_vm_val_t *args;
usize nargs;
spl_vm_val_t ret;
} spl_vm_call_t;
/* 线 1 动态形态:VM 调“外部(非 VM)函数”的按名处理器。
* 当 NCALL 的 native 无 impl_fn 时调用;返回被调函数的返回值。 */
typedef spl_vm_val_t (*spl_vm_foreign_fn)(spl_vm_t *vm, const spl_vm_call_t *call, void *ctx);
typedef struct {
MAP(const char *, usize) stacks;
VEC(usize) self_samples;
@@ -32,11 +58,11 @@ typedef struct {
typedef struct spl_vm {
spl_stack_vec_t stacks;
spl_frame_vec_t frames;
uintptr_t gp; // global pointer
uintptr_t sp; // stack pointer
uintptr_t fp; // frame pointer
uintptr_t cp; // call pointer
uintptr_t ip; // instr pointer
uintptr_t gp; // global pointer
uintptr_t sp; // stack pointer
uintptr_t fp; // frame pointer
uintptr_t cp; // call pointer
uintptr_t ip; // instr pointer
uint64_t steps; // 已执行指令数(供性能分析参考)
uint64_t ncalls; // 已执行 CALL/CALLI 次数(供性能分析参考)
int exit_code;
@@ -49,6 +75,14 @@ typedef struct spl_vm {
VEC(usize) breakpoints; /* ip 断点(执行到该指令前暂停,run_once 返回 2) */
VEC(char *) fn_breakpoints; /* 函数名断点(CALL/CALLI 目标函数入口暂停) */
spl_prog_t *prog;
/* 统一偏移地址空间:regions[1]=栈,regions[i>=2]=堆分配。 */
spl_vm_region_vec_t regions;
VEC(usize) gdata_off; /* prog->gdata[i] 在本 VM 空间内的偏移 */
spl_asp_t asp; /* 本 VM 的地址空间描述符(按值持有,避免共享静态) */
spl_vm_val_t stdio_off[3]; /* stdin/stdout/stderr 的 VM 句柄(懒建) */
spl_vm_val_t ret_val; /* 最近一次完成的调用返回值(64 位) */
spl_vm_foreign_fn foreign; /* 线 1 动态处理器(可为 NULL) */
void *foreign_ctx;
char error_msg[1024];
struct {
uintptr_t max_stack_depth;
@@ -68,6 +102,35 @@ void spl_vm_drop(spl_vm_t *vm);
int spl_vm_addr_valid(uintptr_t p, usize size);
/* 偏移地址空间:偏移 -> 宿主地址;越界/ null 返回 NULL。 */
void *spl_vm_xlate(spl_vm_t *vm, spl_vm_val_t off, usize size);
/* 宿主地址 -> 偏移;不属于本 VM 地址空间返回 0。 */
spl_vm_val_t spl_vm_to_off(spl_vm_t *vm, const void *ptr);
/* 本 VM 的地址空间描述符(供 runtime 解引用)。 */
spl_asp_t *spl_vm_asp(spl_vm_t *vm);
/* ---- 线 1:VM -> 外部函数 ---- */
/* 安装“外部函数”按名处理器(NCALL 的 native 无 impl_fn 时使用)。 */
void spl_vm_set_foreign(spl_vm_t *vm, spl_vm_foreign_fn fn, void *ctx);
/* ---- 线 2:外部 -> VM 函数 ---- */
/* 按 call->name 调用 VM 内函数(call->args/nargs 为实参),结果写入 call->ret。
* 可在 VM 运行中重入调用。返回 0 成功,-1 失败。 */
int spl_vm_invoke(spl_vm_t *vm, spl_vm_call_t *call);
/* 入口调用:调用方先按 ABI 压 2 个 pad 再压实参。 */
int spl_vm_call_entry(spl_vm_t *vm, const char *name, int nargs);
/* ---- 栈 / 结果 / 内存 访问(不暴露宿主指针) ---- */
spl_vm_val_t spl_vm_ret_val(spl_vm_t *vm);
usize spl_vm_sp(spl_vm_t *vm);
usize spl_vm_fp(spl_vm_t *vm);
spl_vm_val_t spl_vm_stack_get(spl_vm_t *vm, usize index);
int spl_vm_stack_set(spl_vm_t *vm, usize index, spl_vm_val_t val);
spl_vm_val_t spl_vm_mem_alloc(spl_vm_t *vm, usize size);
int spl_vm_mem_read(spl_vm_t *vm, spl_vm_val_t off, void *dst, usize n);
int spl_vm_mem_write(spl_vm_t *vm, spl_vm_val_t off, const void *src, usize n);
int spl_vm_load_prog(spl_vm_t *vm, spl_prog_t *prog);
int spl_vm_prepare(spl_vm_t *vm, const char *entry, int argc, const char **argv, const char **envp);
@@ -1,7 +1,7 @@
/* spl_vm_embed.h - 原生编译器内嵌 VM(comptime 执行)。
/* spl_vm_embed.h - 裸机内嵌 VM(装载/运行,不含任何内置 native/syscall)。
*
* 单 TU 合并式:定义 SPL_VM_EMBED_IMPLIMENTATION 后 include 本头,会把 stage0 的
* spl_mcode.c / spl_syscall.c / spl_vm.c 一并纳入当前翻译单元(不单独编译/链接)。
* spl_mcode.c / spl_vm.c 一并纳入当前翻译单元(不单独编译/链接)。
*/
#ifndef __SPL_VM_EMBED_H__
@@ -13,14 +13,17 @@ int vm_load_from_buffer(void *vm, const void *buf, unsigned long long len);
void vm_push(void *vm, unsigned long long val);
int vm_call(void *vm, const char *name, unsigned long long nargs);
int vm_run(void *vm);
unsigned long long vm_ret_val(void *vm);
unsigned long long vm_mem_alloc(void *vm, unsigned long long size);
int vm_mem_read(void *vm, unsigned long long off, void *dst, unsigned long long n);
int vm_mem_write(void *vm, unsigned long long off, const void *src, unsigned long long n);
#ifdef SPL_VM_EMBED_IMPLIMENTATION
#include "../../stage0/spl_mcode.h"
void spl_syscall_register(spl_prog_t *prog) { (void)prog; /* stub */ }
#include "../../stage0/spl_mcode.c"
#include "../../stage0/spl_vm.c"
/* 裸机内嵌 VM:只提供装载/运行 VM 的能力,不内置任何 native/syscall。
* 外部函数解析与注册属于配置端(调用方自行处理)。 */
#include "spl_mcode.c"
#include "spl_vm.c"
void *vm_new(void) {
spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t));
@@ -55,7 +58,6 @@ int vm_load_from_buffer(void *p, const void *buf, unsigned long long len) {
free(prog);
return -1;
}
spl_syscall_register(prog);
if (spl_vm_load_prog(vm, prog) != 0) {
spl_prog_drop(prog);
free(prog);
@@ -75,26 +77,10 @@ void vm_push(void *p, unsigned long long val) {
int vm_call(void *p, const char *name, unsigned long long nargs) {
spl_vm_t *vm = (spl_vm_t *)p;
spl_vm_func_t *func;
if (!vm || !name)
return -1;
func = spl_prog_get_func(vm->prog, name);
if (!func)
return -1;
if (vm->cp >= vm->config.max_call_depth)
return -1;
/* 入口调用:ip=-1 作 sentinel;实参由 vm_push 压栈。 */
vm->ip = (usize)-1;
vm->cp = 0;
vm->fp = 0;
vm->frames.data[0].saved_sp = vm->sp - (usize)nargs;
vm->frames.data[0].saved_fp = vm->fp;
vm->frames.data[0].saved_ip = vm->ip;
vm->frames.data[0].nargs = (spl_vm_val_t)nargs;
vm->cp = 1;
vm->ip = (usize)func->address;
vm->fp = vm->sp - (usize)nargs;
return 0;
/* 入口调用:调用方需先按 ABI 压 2 个 pad 再压实参。 */
return spl_vm_call_entry(vm, name, (int)nargs);
}
int vm_run(void *p) {
@@ -104,6 +90,27 @@ int vm_run(void *p) {
spl_vm_run_until(vm, 0);
return (int)vm->exit_code;
}
unsigned long long vm_ret_val(void *p) {
spl_vm_t *vm = (spl_vm_t *)p;
return vm ? (unsigned long long)vm->ret_val : 0;
}
unsigned long long vm_mem_alloc(void *p, unsigned long long size) {
spl_vm_t *vm = (spl_vm_t *)p;
return (unsigned long long)spl_vm_mem_alloc(vm, (usize)size);
}
int vm_mem_read(void *p, unsigned long long off, void *dst, unsigned long long n) {
spl_vm_t *vm = (spl_vm_t *)p;
return spl_vm_mem_read(vm, (spl_vm_val_t)off, dst, (usize)n);
}
int vm_mem_write(void *p, unsigned long long off, const void *src, unsigned long long n) {
spl_vm_t *vm = (spl_vm_t *)p;
return spl_vm_mem_write(vm, (spl_vm_val_t)off, src, (usize)n);
}
#endif /* SPL_VM_EMBED_IMPLIMENTATION */
#endif /* __SPL_VM_EMBED_H__ */
+140 -10
View File
@@ -6,6 +6,7 @@
#include "include/acutest.h"
#include "spl_mcode.h"
#include "spl_syscall.h"
#include "spl_vm.h"
#include <stdio.h>
@@ -159,7 +160,8 @@ static int run_with_natives(const spl_vm_ins_t *instns, int ninsns, spl_vm_nativ
* Native function for NCALL tests
* ================================================================ */
static spl_vm_val_t native_add_impl(int nargs, spl_vm_val_t *args) {
static spl_vm_val_t native_add_impl(spl_vm_t *vm, int nargs, spl_vm_val_t *args) {
(void)vm;
return (nargs >= 2) ? args[0] + args[1] : 0;
}
@@ -479,7 +481,8 @@ void test_call_add(void) {
spl_vm_ins_t add_insns[] = {ins(SPL_LADDR, SPL_VOID, 0), ins(SPL_LOAD, SPL_I64, 0),
ins(SPL_LADDR, SPL_VOID, 8), ins(SPL_LOAD, SPL_I64, 0),
ins(SPL_ADD, SPL_I64, 0), ins(SPL_RET, SPL_I64, 0)};
spl_vm_ins_t main_insns[] = {ins(SPL_PUSH, SPL_I32, 10), ins(SPL_PUSH, SPL_I32, 20),
spl_vm_ins_t main_insns[] = {ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_PUSH, SPL_VOID, 0),
ins(SPL_PUSH, SPL_I32, 10), ins(SPL_PUSH, SPL_I32, 20),
ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_CALL, SPL_VOID, 2),
ins(SPL_RET, SPL_I64, 0)};
@@ -586,11 +589,12 @@ void test_calli(void) {
spl_vm_ins_t add_insns[] = {ins(SPL_LADDR, SPL_VOID, 0), ins(SPL_LOAD, SPL_I64, 0),
ins(SPL_LADDR, SPL_VOID, 8), ins(SPL_LOAD, SPL_I64, 0),
ins(SPL_ADD, SPL_I64, 0), ins(SPL_RET, SPL_I64, 0)};
spl_vm_ins_t main_insns[] = {ins(SPL_PUSH, SPL_I32, 10), ins(SPL_PUSH, SPL_I32, 20),
spl_vm_ins_t main_insns[] = {ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_PUSH, SPL_VOID, 0),
ins(SPL_PUSH, SPL_I32, 10), ins(SPL_PUSH, SPL_I32, 20),
ins(SPL_PUSH, SPL_VOID, 2), ins(SPL_PUSH, SPL_VOID, 0),
ins(SPL_CALLI, SPL_VOID, 0), ins(SPL_RET, SPL_I64, 0)};
int ninsns_t = 6 + 6;
int ninsns_t = 6 + 8;
size_t nlen0 = strlen("add") + 1;
size_t npad0 = ((nlen0 + 7) / 8) * 8 - nlen0;
size_t nlen1 = strlen("main") + 1;
@@ -627,7 +631,7 @@ void test_calli(void) {
p += npad1;
LE64(p, 0);
LE64(p, 0);
LE64(p, 6);
LE64(p, 8);
LE64(p, 6);
for (int i = 0; i < 6; i++) {
@@ -637,7 +641,7 @@ void test_calli(void) {
*p++ = (unsigned char)(add_insns[i].type >> 8);
LE64(p, add_insns[i].imm);
}
for (int i = 0; i < 6; i++) {
for (int i = 0; i < 8; i++) {
*p++ = (unsigned char)(main_insns[i].opcode);
*p++ = (unsigned char)(main_insns[i].opcode >> 8);
*p++ = (unsigned char)(main_insns[i].type);
@@ -669,8 +673,9 @@ void test_calli(void) {
* ================================================================ */
void test_gaddr_ld32(void) {
/* Load program, add global data, GADDR + LD32 to read it back */
spl_vm_ins_t p[] = {ins(SPL_GADDR, SPL_VOID, 0), ins(SPL_LOAD, SPL_U32, 0),
/* Load program, add global data, GADDR + LD32 to read it back.
* gdata 索引 0 为哨兵;首次 add_data 得到索引 1。 */
spl_vm_ins_t p[] = {ins(SPL_GADDR, SPL_VOID, 1), ins(SPL_LOAD, SPL_U32, 0),
ins(SPL_RET, SPL_U32, 0)};
size_t len;
unsigned char *bin = build_binary("main", 0, p, 3, &len);
@@ -697,8 +702,8 @@ void test_gaddr_ld32(void) {
}
void test_gaddr_multi(void) {
/* Two global data entries: read second one via GADDR 1 */
spl_vm_ins_t p[] = {ins(SPL_GADDR, SPL_VOID, 1), ins(SPL_LOAD, SPL_U32, 0),
/* Two global data entries: read second one via GADDR 2 (0 为哨兵) */
spl_vm_ins_t p[] = {ins(SPL_GADDR, SPL_VOID, 2), ins(SPL_LOAD, SPL_U32, 0),
ins(SPL_RET, SPL_U32, 0)};
size_t len;
unsigned char *bin = build_binary("main", 0, p, 3, &len);
@@ -818,6 +823,127 @@ void test_empty(void) {
TEST_CHECK(spl_prog_load_from_file("nonexistent_file_xyz.bin", NULL) != 0);
}
/* ================================================================
* 动态回调 / 重入 / 栈访问 API
* ================================================================ */
static spl_vm_val_t foreign_add_cb(spl_vm_t *vm, const spl_vm_call_t *call, void *ctx) {
(void)vm;
(void)ctx;
if (!call || call->nargs < 2)
return 0;
return call->args[0] + call->args[1];
}
/* 线 1 动态:NCALL 的 native 无 impl_fn 时走 vm->foreign。 */
void test_foreign_fallback(void) {
spl_vm_ins_t p[] = {ins(SPL_PUSH, SPL_I32, 30), ins(SPL_PUSH, SPL_I32, 12),
ins(SPL_PUSH, SPL_VOID, 0), ins(SPL_NCALL, SPL_I32, 2),
ins(SPL_RET, SPL_I32, 0)};
size_t len;
unsigned char *bin = build_binary("main", 0, p, 5, &len);
spl_prog_t prog;
spl_vm_t vm;
spl_vm_native_t nat[] = {{"host_add", 0, NULL}};
int rc = -1;
spl_vm_init(&vm);
if (write_temp(bin, len) == 0 && spl_prog_load_from_file(TMPFILE, &prog) == 0) {
for (int i = 0; i < 1; i++)
spl_prog_add_native(&prog, &nat[i]);
if (spl_vm_load_prog(&vm, &prog) == 0) {
spl_vm_set_foreign(&vm, foreign_add_cb, NULL);
if (spl_vm_prepare(&vm, "main", 0, NULL, NULL) == 0) {
int ret = spl_vm_run_until(&vm, 0);
if (ret == 1)
rc = (int)vm.ret_val;
}
}
}
spl_vm_drop(&vm);
remove(TMPFILE);
free(bin);
TEST_CHECK(rc == 42);
}
/* 线 2:外部 -> VM 调用。 */
void test_invoke(void) {
spl_vm_ins_t add_insns[] = {ins(SPL_LADDR, SPL_VOID, 0), ins(SPL_LOAD, SPL_I64, 0),
ins(SPL_LADDR, SPL_VOID, 8), ins(SPL_LOAD, SPL_I64, 0),
ins(SPL_ADD, SPL_I64, 0), ins(SPL_RET, SPL_I64, 0)};
size_t len;
unsigned char *bin = build_binary("add", 2, add_insns, 6, &len);
spl_prog_t prog;
spl_vm_t vm;
spl_vm_val_t args[2];
spl_vm_call_t call;
int ok = 0;
spl_vm_init(&vm);
if (write_temp(bin, len) == 0 && spl_prog_load_from_file(TMPFILE, &prog) == 0) {
if (spl_vm_load_prog(&vm, &prog) == 0) {
args[0] = 40;
args[1] = 2;
call.name = "add";
call.args = args;
call.nargs = 2;
call.ret = 0;
ok = (spl_vm_invoke(&vm, &call) == 0) && (call.ret == 42);
}
}
spl_vm_drop(&vm);
remove(TMPFILE);
free(bin);
TEST_CHECK(ok);
}
/* 栈 / 结果访问 API 不依赖宿主指针。 */
void test_stack_api(void) {
spl_vm_t vm;
spl_vm_init(&vm);
TEST_CHECK(spl_vm_stack_set(&vm, 0, 123) == 0);
TEST_CHECK(spl_vm_stack_get(&vm, 0) == 123);
TEST_CHECK(spl_vm_sp(&vm) == 0);
TEST_CHECK(spl_vm_fp(&vm) == 0);
TEST_CHECK(spl_vm_stack_get(&vm, (usize)-1) == 0);
spl_vm_drop(&vm);
}
/* syscall 注册 + 内存 API:NCALL vm_alloc 得到 VM 偏移,并经 mem_read/write 往返。 */
void test_syscall_registration(void) {
spl_vm_ins_t p[] = {ins(SPL_PUSH, SPL_I64, 16), ins(SPL_PUSH, SPL_VOID, 0),
ins(SPL_NCALL, SPL_I64, 1), ins(SPL_RET, SPL_I64, 0)};
size_t len;
unsigned char *bin = build_binary("main", 0, p, 4, &len);
spl_prog_t prog;
spl_vm_t vm;
spl_vm_native_t nat[] = {{"vm_alloc", 0, NULL}};
spl_vm_val_t off = 0;
int ok = 0;
char w[4] = {1, 2, 3, 0};
char r[4] = {0};
spl_vm_init(&vm);
if (write_temp(bin, len) == 0 && spl_prog_load_from_file(TMPFILE, &prog) == 0) {
for (int i = 0; i < 1; i++)
spl_prog_add_native(&prog, &nat[i]);
spl_syscall_register(&prog);
if (spl_vm_load_prog(&vm, &prog) == 0 && spl_vm_prepare(&vm, "main", 0, NULL, NULL) == 0) {
if (spl_vm_run_until(&vm, 0) == 1) {
off = vm.ret_val;
if (off != 0 && spl_vm_mem_write(&vm, off, w, 4) == 0 &&
spl_vm_mem_read(&vm, off, r, 4) == 0 && memcmp(w, r, 4) == 0)
ok = 1;
}
}
}
spl_vm_drop(&vm);
remove(TMPFILE);
free(bin);
TEST_CHECK(off != 0);
TEST_CHECK(ok);
}
/* ================================================================
* Test list
* ================================================================ */
@@ -872,6 +998,10 @@ TEST_LIST = {
{"ld_st64", test_ld_st64},
{"many_ops", test_many_ops},
{"halt", test_halt},
{"foreign_fallback", test_foreign_fallback},
{"invoke", test_invoke},
{"stack_api", test_stack_api},
{"syscall_registration", test_syscall_registration},
{"bad_magic", test_bad_magic},
{"empty", test_empty},
{NULL, NULL},
+4
View File
@@ -1086,6 +1086,10 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
usize sret_off = 0;
usize j = 0;
/* ABI:实参下方预留 2 个空闲 slot(PAD0/PAD1)。 */
CG_PUSH(cg, SPL_U64, 0);
CG_PUSH(cg, SPL_U64, 0);
if (ret_is_sret) {
sret_off = vec_at(cg->frame.slots, ref).data_off;
CG_LADDR(cg, sret_off);
+13
View File
@@ -50,6 +50,7 @@ type Body = enum {
StatementBreak: struct { label: usize, expr: usize },
StatementContinue: struct { label: usize },
StatementDefer: struct { body: usize },
StatementErrdefer: struct { body: usize }, // errdefer:仅错误退出时执行
StatementComptime: struct { body: usize },
StatementDecl: struct { decl: usize },
StatementExpr: struct { expr: usize },
@@ -87,6 +88,8 @@ type Body = enum {
},
ExprAggregateLit: struct { name: ByteView, fields: Vec },
ExprComptimeCall: struct { name: ByteView, args: Vec },
ExprTry: struct { value: usize }, // `try expr`
ExprCatch: struct { value: usize, pattern: usize, handler: usize }, // `expr catch <pat> { }`
ExprBlock: struct { stmts: Vec, tail_expr: usize },
ExprIf: struct { cond: usize, then_block: usize, else_branch: usize },
ExprIfvar: struct { var_decl: usize, then_block: usize, else_branch: usize },
@@ -144,6 +147,7 @@ fn kind_name(body: Body): []u8 {
.StatementBreak(_) => { ret "statement_break"; },
.StatementContinue(_) => { ret "statement_continue"; },
.StatementDefer(_) => { ret "statement_defer"; },
.StatementErrdefer(_) => { ret "statement_errdefer"; },
.StatementComptime(_) => { ret "statement_comptime"; },
.ExprComptime(_) => { ret "expr_comptime"; },
.StatementDecl(_) => { ret "statement_decl"; },
@@ -171,6 +175,8 @@ fn kind_name(body: Body): []u8 {
.ExprArrayLit(_) => { ret "array_literal"; },
.ExprAggregateLit(_) => { ret "aggregate_literal"; },
.ExprComptimeCall(_) => { ret "comptime_call"; },
.ExprTry(_) => { ret "try_expr"; },
.ExprCatch(_) => { ret "catch_expr"; },
.ExprComptimeInit(_) => { ret "comptime_init"; },
.ExprBlock(_) => { ret "block"; },
.ExprIf(_) => { ret "if_expr"; },
@@ -466,6 +472,7 @@ fn dump_node(ast: *Ast, buf: *ByteBuffer, stack: *Vec, ref: usize, last: bool):
},
.StatementContinue(x) => { ok = dump_opt(ast, buf, stack, x.label, true); },
.StatementDefer(x) => { ok = dump_opt(ast, buf, stack, x.body, true); },
.StatementErrdefer(x) => { ok = dump_opt(ast, buf, stack, x.body, true); },
.StatementComptime(x) => { ok = dump_opt(ast, buf, stack, x.body, true); },
.ExprComptime(x) => { ok = dump_opt(ast, buf, stack, x.body, true); },
.StatementDecl(d) => { ok = dump_opt(ast, buf, stack, d.decl, true); },
@@ -519,6 +526,12 @@ fn dump_node(ast: *Ast, buf: *ByteBuffer, stack: *Vec, ref: usize, last: bool):
},
.ExprAggregateLit(a) => { ok = dump_list(ast, buf, stack, a.fields); },
.ExprComptimeCall(c) => { ok = dump_list(ast, buf, stack, c.args); },
.ExprTry(t2) => { ok = dump_opt(ast, buf, stack, t2.value, true); },
.ExprCatch(c2) => {
ok = dump_opt(ast, buf, stack, c2.value, false) &&
dump_opt(ast, buf, stack, c2.pattern, false) &&
dump_opt(ast, buf, stack, c2.handler, true);
},
.ExprComptimeInit(x) => { ok = dump_list(ast, buf, stack, x.fields); },
.ExprBlock(b) => {
ok = dump_list(ast, buf, stack, b.stmts) &&
+78
View File
@@ -44,6 +44,7 @@ sema: *Sema,
ir: *IrBuilder,
ast: *Ast,
def2ir_map: Map,
glob_gidx: Map, // def_id -> gidx+1(全局变量)
loop_stack: Vec, // LoopCtx
defer_stack: Vec, // ast node ref
cur_ret_lang: usize,
@@ -105,6 +106,62 @@ fn ir_map_put(self: *Ast2Ir, def_id: usize, val: usize) {
match Map.put(&self.def2ir_map, &def_id as *u8, &val as *u8) { .Ok => {}, .Err(e) => {} }
}
fn glob_get(self: *Ast2Ir, def_id: usize, out: *usize): bool {
match Map.get(&self.glob_gidx, &def_id as *u8, out as *u8) {
.Found => { ret true; },
.NotFound => { ret false; },
}
ret false;
}
fn glob_put(self: *Ast2Ir, def_id: usize, val: usize) {
match Map.put(&self.glob_gidx, &def_id as *u8, &val as *u8) { .Ok => {}, .Err(e) => {} }
}
// 顶层 var/const → 模块全局(alloc 于静态存储;引用是 *T 指针常量)。
fn emit_global_var(self: *Ast2Ir, d: *Node) {
if d == null || d.resolved_def_id == 0 { ret; }
var def_id = d.resolved_def_id;
var existing: usize = 0;
if glob_get(self, def_id, &existing) { ret; }
var lang = LangType.def_lang_id(&self.sema.types, def_id);
var ir = to_ir_type(self, lang);
if ir == 0 { ret; }
var init_ref: usize = 0;
match d.body {
.VarDecl(x) => { init_ref = x.init_expr; },
.ConstDecl(x) => { init_ref = x.init_expr; },
_ => {},
}
var zero = true;
var bytes = Vec.blank(1, 1);
if init_ref != 0 {
var inode = Ast.node(self.ast, init_ref);
if inode != null {
match inode.body {
.ExprIntLit(bi) => {
var v: u64 = 0;
match BigInt.to_u64(&v, bi.value) { .Ok => {}, .Err(e) => {} }
var bits = LangType.int_bits(&self.sema.types, ir);
var size = bits / 8;
if size != 0 {
zero = false;
var i: usize = 0;
while i < size {
var b = ((v >> (8 * i)) & 255) as u8;
match Vec.push(&bytes, &b as *u8) { .Ok => {}, .Err(e) => {} }
i = i + 1;
}
}
},
_ => {},
}
}
}
var gidx = IrBuilder.add_global(self.ir, ir, zero, bytes);
glob_put(self, def_id, gidx + 1);
}
fn kind_is(self: *Ast2Ir, lang_id: usize, want: LangKind): bool {
var e = ltn(self, lang_id);
if e == null { ret false; }
@@ -608,6 +665,13 @@ fn emit_lvalue(self: *Ast2Ir, ref: usize): usize {
.ExprIdent(x) => {
var d = defn(self, n.resolved_def_id);
if d != null && @enum2int(d.kind) == @enum2int(DefKind.Fn) { ret 0; }
var g: usize = 0;
if glob_get(self, n.resolved_def_id, &g) {
var lang = node_lang(n);
var ir = to_ir_type(self, lang);
var ptr_ir = TypeTable.make_ptr(&self.sema.types.ir, ir);
ret IrBuilder.type_const_global(self.ir, ptr_ir, g - 1);
}
var slot: usize = 0;
if !ir_map_get(self, n.resolved_def_id, &slot) { ret 0; }
ret slot;
@@ -935,6 +999,13 @@ fn emit_ident(self: *Ast2Ir, n: *Node): usize {
if !ir_map_get(self, n.resolved_def_id, &fn_ref) { ret 0; }
ret IrBuilder.type_const_fn(self.ir, node_ir(self, n), fn_ref);
}
var g: usize = 0;
if glob_get(self, n.resolved_def_id, &g) {
var ir = node_ir(self, n);
var ptr_ir = TypeTable.make_ptr(&self.sema.types.ir, ir);
var ptr = IrBuilder.type_const_global(self.ir, ptr_ir, g - 1);
ret IrBuilder.mem_load(self.ir, ir, ptr);
}
var slot: usize = 0;
if !ir_map_get(self, n.resolved_def_id, &slot) { ret 0; }
ret IrBuilder.mem_load(self.ir, node_ir(self, n), slot);
@@ -1961,6 +2032,8 @@ fn emit_container_reserve(self: *Ast2Ir, ref: usize) {
}
},
.TopLevelBlock(x) => { emit_container_reserve(self, dref); },
.VarDecl(_) => { emit_global_var(self, d); },
.ConstDecl(_) => { emit_global_var(self, d); },
_ => {},
}
}
@@ -1997,6 +2070,8 @@ fn emit_container_body(self: *Ast2Ir, ref: usize) {
}
},
.TopLevelBlock(x) => { emit_container_body(self, dref); },
.VarDecl(_) => {},
.ConstDecl(_) => {},
_ => {},
}
}
@@ -2070,6 +2145,8 @@ fn new(builder: *IrBuilder, sema: *Sema, diag: *Diag): Ast2Ir {
.ast = sema.ast,
.def2ir_map = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_kind_usize()),
.glob_gidx = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_kind_usize()),
.loop_stack = Vec.blank(@sizeof(LoopCtx), @alignof(LoopCtx)),
.defer_stack = Vec.blank(@sizeof(usize), @alignof(usize)),
.cur_ret_lang = 0,
@@ -2089,6 +2166,7 @@ fn drop(self: *Ast2Ir) {
Vec.drop(&self.loop_stack);
Vec.drop(&self.defer_stack);
Map.drop(&self.def2ir_map);
Map.drop(&self.glob_gidx);
var k: usize = 0;
while k < self.owned.len {
match Vec.get(&self.owned, k) {
+37 -1
View File
@@ -82,6 +82,14 @@ type ConstLit = enum {
Float: f64,
Char: u8,
Fn: usize,
Global: usize, // 全局变量下标(Ir.globals);值 = 指向该全局的 *T
}
// 模块级全局变量:编译期分配的静态存储,引用时是一个 *T 指针常量(同 LLVM GlobalVariable)。
type Global = struct {
tid: usize,
zero: bool, // true = 零初始化(BSS,不携带字节)
data: Vec, // u8 初始字节(zero=false 时使用)
}
type IrBody = enum {
@@ -128,6 +136,7 @@ type IrFunc = struct {
type Ir = @self;
funcs: Vec, // IrFunc
globals: Vec, // Global
// ---- 生命周期 ----
@@ -141,7 +150,8 @@ fn new_entry(): IrEntry {
}
fn new(): Ir {
var ir = Ir { .funcs = Vec.blank(@sizeof(IrFunc), @alignof(IrFunc)) };
var ir = Ir { .funcs = Vec.blank(@sizeof(IrFunc), @alignof(IrFunc)),
.globals = Vec.blank(@sizeof(Global), @alignof(Global)) };
var sentinel = IrFunc {
.name = ByteView.empty(),
.attrs = Vec.blank(@sizeof(usize), @alignof(usize)),
@@ -180,6 +190,25 @@ fn drop(self: *Ir) {
i = i + 1;
}
Vec.drop(&self.funcs);
var g: usize = 0;
while g < self.globals.len {
var ge = (self.globals.data as *Global) + g;
Vec.drop(&ge.data);
g = g + 1;
}
Vec.drop(&self.globals);
}
// 追加一个全局变量;返回其下标(gidx)。bytes 的所有权转移进表。
fn add_global(self: *Ir, tid: usize, zero: bool, bytes: Vec): usize {
var g = Global { .tid = tid, .zero = zero, .data = bytes };
match Vec.push(&self.globals, &g as *u8) { .Ok => {}, .Err(error) => { ret 0; } }
ret self.globals.len - 1;
}
fn global_at(self: *Ir, gidx: usize): *Global {
if gidx >= self.globals.len { ret null; }
ret (self.globals.data as *Global) + gidx;
}
fn alloc_fn(self: *Ir): usize {
@@ -394,6 +423,13 @@ fn dump_body(out: *ByteBuffer, ty: *TypeTable, e: *IrEntry): bool {
},
.Const(c) => {
if !dump_type(out, ty, c.tid) { ret false; }
match c.lit {
.Global(g) => {
if !out_str(out, " global#") { ret false; }
ret out_u(out, g);
},
_ => {},
}
var te = TypeTable.node(ty, c.tid);
var is_float = false;
var is_fn = false;
+57 -1
View File
@@ -18,7 +18,7 @@ type .{ .Layout } = @import("./layout.spl");
type AttrM = @import("./attr.spl");
type .{ .Attr } = @import("./attr.spl");
type IrM = @import("./ir.spl");
type .{ .Ir, .IrFunc, .IrEntry } = @import("./ir.spl");
type .{ .Ir, .IrFunc, .IrEntry, .Global } = @import("./ir.spl");
type Ir2C = @self;
@@ -570,6 +570,7 @@ fn emit_const(self: *Ir2C, ref: usize, n: *IrEntry) {
}
},
.Ptr(v) => { put(self, "(void*)"); put_u(self, v); },
.Global(g) => { put(self, "(void*)spl_g_"); put_u(self, g); },
.Float(v) => { put(self, "0.0"); },
.Fn(fid) => { put(self, "(void*)&"); c_fn_name(self, fid); },
}
@@ -1240,6 +1241,32 @@ fn find_main(self: *Ir2C): usize {
fn run(self: *Ir2C) {
put(self, "#include \"spl_rt.h\"\n");
// 模块级全局变量(Zero → BSS:无初始化式)。
var gi: usize = 0;
while gi < self.ir.globals.len {
var g = (self.ir.globals.data as *Global) + gi;
var sz = type_size(self, g.tid);
if sz == 0 { sz = 1; }
put(self, "static unsigned char spl_g_");
put_u(self, gi);
put(self, "[");
put_u(self, sz);
put(self, "]");
if !g.zero {
put(self, " = {");
var k: usize = 0;
while k < g.data.len {
if k > 0 { put(self, ", "); }
put_u(self, ((g.data.data as *u8) + k).* as usize);
k = k + 1;
}
if g.data.len == 0 { put(self, "0"); }
put(self, "}");
}
put(self, ";\n");
gi = gi + 1;
}
var i: usize = 1;
while i < self.ir.funcs.len {
var f = IrM.func(self.ir, i);
@@ -1256,6 +1283,7 @@ fn run(self: *Ir2C) {
}
i = i + 1;
}
emit_ct_table(self);
var m = find_main(self);
if m != 0 {
var f = IrM.func(self.ir, m);
@@ -1283,6 +1311,34 @@ fn run(self: *Ir2C) {
}
}
// compiler function(`ct_` 前缀)回调表:供 native 端 vm_set_foreign 按名分发。
fn emit_ct_table(self: *Ir2C) {
put(self, "static const struct { const char *name; void *fn; } spl_ct_tab[] = {\n");
var n: usize = 0;
var i: usize = 1;
while i < self.ir.funcs.len {
var f = IrM.func(self.ir, i);
if f != null && !fn_is_extern(self, f) &&
ByteView.starts_with(f.name, ByteView.from_slice("ct_")) {
put(self, " {\"");
put_bv(self, f.name);
put(self, "\", (void*)f");
put_u(self, i);
put(self, "},\n");
n = n + 1;
}
i = i + 1;
}
if n == 0 { put(self, " {0, 0},\n"); }
put(self, "};\n");
put(self, "void *spl_ct_lookup(const char *name) {\n");
put(self, " unsigned long i;\n");
put(self, " for (i = 0; i < sizeof(spl_ct_tab)/sizeof(spl_ct_tab[0]); i++)\n");
put(self, " if (spl_ct_tab[i].name && strcmp(spl_ct_tab[i].name, name) == 0) return spl_ct_tab[i].fn;\n");
put(self, " return 0;\n");
put(self, "}\n");
}
fn new(ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr, out: *ByteBuffer): Ir2C {
ret Ir2C {
.ir = ir,
+49 -1
View File
@@ -16,7 +16,7 @@ type .{ .Layout } = @import("./layout.spl");
type AttrM = @import("./attr.spl");
type .{ .Attr, .AttrArg } = @import("./attr.spl");
type IrM = @import("./ir.spl");
type .{ .Ir, .IrFunc, .IrEntry } = @import("./ir.spl");
type .{ .Ir, .IrFunc, .IrEntry, .Global } = @import("./ir.spl");
type Mcode = @import("./mcode.spl");
type .{ .Prog, .Op, .VmKind, .VmIns, .VmFunc } = @import("./mcode.spl");
type Mem = @import("sys/mem.spl");
@@ -28,6 +28,7 @@ ty: *TypeTable,
attr: *Attr,
layout: *Layout,
extern_native: Vec, // isize
global_gaddr: Vec, // usize:每个全局变量在 prog.gdata 的下标
prog: Prog,
// ---- 类型/布局查询 ----
@@ -589,6 +590,23 @@ fn cg_const(cg: *Cgen, ref: usize, n: *IrEntry) {
var te = TypeTable.node(ctx.ty, tid);
if te == null { ret; }
// 全局变量引用:Const{ lit = Global(gidx) } → GADDR(该全局的运行时地址)。
match n.body {
.Const(c) => {
match c.lit {
.Global(g) => {
var di: usize = 0;
if g < ctx.global_gaddr.len { di = (ctx.global_gaddr.data as *usize)[g]; }
emit(cg, .Gaddr, .Void, di);
cg_store_slot(cg, ref, .Ptr);
ret;
},
_ => {},
}
},
_ => {},
}
match te.node {
.Fn(f) => {
var cref = const_fn(n);
@@ -952,6 +970,9 @@ fn cg_control(cg: *Cgen, ref: usize, n: *IrEntry) {
cg_store_slot(cg, ref, rk);
}
} else {
/* ABI:实参下方预留 2 个空闲 slot(PAD0/PAD1)。 */
cg_push(cg, .U64, 0);
cg_push(cg, .U64, 0);
var ret_t = cl.tid;
var ret_is_sret = ir_is_aggregate(ctx, ret_t);
var sret_off: usize = 0;
@@ -1210,6 +1231,7 @@ fn init(ctx: *Ir2Vm, ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr) {
ctx.attr = attr;
ctx.layout = layout;
ctx.extern_native = Vec.blank(@sizeof(isize), @alignof(isize));
ctx.global_gaddr = Vec.blank(@sizeof(usize), @alignof(usize));
match Mcode.new() {
.Ok(v) => { ctx.prog = v; },
@@ -1220,6 +1242,7 @@ fn init(ctx: *Ir2Vm, ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr) {
fn drop(ctx: *Ir2Vm) {
Mcode.drop(&ctx.prog);
Vec.drop(&ctx.extern_native);
Vec.drop(&ctx.global_gaddr);
}
fn run_func(ctx: *Ir2Vm, ref: usize): i32 {
@@ -1250,6 +1273,22 @@ fn run(ctx: *Ir2Vm): i32 {
i = i + 1;
}
// 登记全局变量到 prog.gdata(Zero→零填/BSS,Bytes→拷贝),记下运行时下标。
var gi: usize = 0;
while gi < ctx.ir.globals.len {
var g = (ctx.ir.globals.data as *Global) + gi;
var gsize = ir_type_size(ctx, g.tid);
var didx: usize = 0;
if g.zero {
didx = Mcode.add_zero_data(&ctx.prog, gsize);
} else {
didx = Mcode.add_data(&ctx.prog, g.data.data as usize, gsize);
}
var dv = didx;
match Vec.push(&ctx.global_gaddr, &dv as *u8) { .Ok => {}, .Err(error) => {} }
gi = gi + 1;
}
// 哨兵:保证真实函数入口地址非零。
ignore_usize(Mcode.add_instr(&ctx.prog, .Halt, .Void, 0));
@@ -1327,6 +1366,15 @@ fn dump(ctx: *Ir2Vm, out: *ByteBuffer): bool {
ret Mcode.dump(&ctx.prog, out);
}
// 序列化到内存 ByteBuffer(不落盘),供内嵌 VM 直接加载。
fn encode(ctx: *Ir2Vm, out: *ByteBuffer): bool {
match Mcode.encode(&ctx.prog, out) {
.Ok => { ret true; },
.Err(error) => { ret false; },
}
ret false;
}
// 把翻译结果写成 .sir(二进制)。
fn store(ctx: *Ir2Vm, path: ByteView): bool {
match Mcode.store(&ctx.prog, path) {
+6
View File
@@ -285,6 +285,12 @@ fn type_const_float(self: *IrBuilder, tid: usize, val: f64): usize { ret const_n
fn type_const_char(self: *IrBuilder, tid: usize, val: u8): usize { ret const_node(self, tid, .Char(val)); }
fn type_const_fn(self: *IrBuilder, tid: usize, val: usize): usize { ret const_node(self, tid, .Fn(val)); }
fn type_const_bytes(self: *IrBuilder, tid: usize, data: usize): usize { ret const_node(self, tid, .Ptr(data)); }
fn type_const_global(self: *IrBuilder, tid: usize, gidx: usize): usize { ret const_node(self, tid, .Global(gidx)); }
// 追加模块级全局变量;返回 gidx。bytes 所有权转移进 Ir。
fn add_global(self: *IrBuilder, tid: usize, zero: bool, bytes: Vec): usize {
ret Ir.add_global(&self.ir, tid, zero, bytes);
}
// ---- type ops ----
+54 -25
View File
@@ -314,6 +314,26 @@ fn add_data(self: *Prog, ptr: usize, size: usize): usize {
ret self.gdata.len - 1;
}
// 追加一条 size 字节的零初始化全局数据(BSS 语义);返回其索引。
fn add_zero_data(self: *Prog, size: usize): usize {
var entry = ByteBuffer.new();
match ByteBuffer.reserve(&entry, size) {
.Ok => {},
.Err(error) => { ByteBuffer.drop(&entry); ret 0; },
}
if size != 0 {
entry.storage.len = size;
var p = entry.storage.data as *u8;
var i: usize = 0;
while i < size { p[i] = 0; i = i + 1; }
}
match Vec.push(&self.gdata, &entry as *u8) {
.Ok => {},
.Err(error) => { ByteBuffer.drop(&entry); ret 0; },
}
ret self.gdata.len - 1;
}
// 返回 name 对应的 native 索引;不存在则登记。name 为空指针时返回 -1。
fn get_or_add_native(self: *Prog, name: ByteView): isize {
if name.ptr == null { ret -1; }
@@ -545,10 +565,8 @@ fn put_name_field(out: *ByteBuffer, name: ByteView): bool {
ret put_zeros(out, align8(nlen) - nlen);
}
fn store(self: *Prog, path: ByteView): Status {
var out = ByteBuffer.new();
defer { ByteBuffer.drop(&out); }
// 把 prog 序列化为二进制写入 out(不落盘,供内嵌 VM 直接用)。
fn encode(self: *Prog, out: *ByteBuffer): Status {
// 精确预估输出大小并一次性预留,避免大文件逐字节增长导致的重复拷贝。
var total: usize = 48;
var fi: usize = 0;
@@ -581,11 +599,11 @@ fn store(self: *Prog, path: ByteView): Status {
if e != null { total = total + 8 + align8(e.storage.len); }
fi = fi + 1;
}
match ByteBuffer.reserve(&out, total) { .Ok => {}, .Err(error) => {} }
match ByteBuffer.reserve(out, total) { .Ok => {}, .Err(error) => {} }
if out.storage.cap < total || out.storage.data == null { ret .Err(make(.Io)); }
if !put_view(&out, ByteView.from_slice("SPLBIN")) { ret .Err(make(.Io)); }
if !put_zeros(&out, 2) { ret .Err(make(.Io)); }
if !put_view(out, ByteView.from_slice("SPLBIN")) { ret .Err(make(.Io)); }
if !put_zeros(out, 2) { ret .Err(make(.Io)); }
var nfuncs = self.funcs.len;
var ninsns = self.insns.len;
@@ -594,21 +612,21 @@ fn store(self: *Prog, path: ByteView): Status {
var ndata: usize = 0;
if self.gdata.len > 0 { ndata = self.gdata.len - 1; }
if !put_u64(&out, nfuncs) { ret .Err(make(.Io)); }
if !put_u64(&out, ninsns) { ret .Err(make(.Io)); }
if !put_u64(&out, nnatives) { ret .Err(make(.Io)); }
if !put_u64(&out, nstrs) { ret .Err(make(.Io)); }
if !put_u64(&out, ndata) { ret .Err(make(.Io)); }
if !put_u64(out, nfuncs) { ret .Err(make(.Io)); }
if !put_u64(out, ninsns) { ret .Err(make(.Io)); }
if !put_u64(out, nnatives) { ret .Err(make(.Io)); }
if !put_u64(out, nstrs) { ret .Err(make(.Io)); }
if !put_u64(out, ndata) { ret .Err(make(.Io)); }
var i: usize = 0;
while i < nfuncs {
var f = func_at(self, i);
if f == null { ret .Err(make(.Io)); }
if !put_name_field(&out, f.name) { ret .Err(make(.Io)); }
if !put_u64(&out, f.idx_of_strtab) { ret .Err(make(.Io)); }
if !put_u64(&out, f.nargs) { ret .Err(make(.Io)); }
if !put_u64(&out, f.ninsns) { ret .Err(make(.Io)); }
if !put_u64(&out, f.address) { ret .Err(make(.Io)); }
if !put_name_field(out, f.name) { ret .Err(make(.Io)); }
if !put_u64(out, f.idx_of_strtab) { ret .Err(make(.Io)); }
if !put_u64(out, f.nargs) { ret .Err(make(.Io)); }
if !put_u64(out, f.ninsns) { ret .Err(make(.Io)); }
if !put_u64(out, f.address) { ret .Err(make(.Io)); }
i = i + 1;
}
@@ -627,17 +645,17 @@ fn store(self: *Prog, path: ByteView): Status {
while i < nnatives {
var n = native_at(self, i);
if n == null { ret .Err(make(.Io)); }
if !put_name_field(&out, n.name) { ret .Err(make(.Io)); }
if !put_u64(&out, n.idx_of_strtab) { ret .Err(make(.Io)); }
if !put_name_field(out, n.name) { ret .Err(make(.Io)); }
if !put_u64(out, n.idx_of_strtab) { ret .Err(make(.Io)); }
i = i + 1;
}
i = 0;
while i < nstrs {
var s = str_at(self, i);
if !put_u64(&out, s.len) { ret .Err(make(.Io)); }
if !put_view(&out, s) { ret .Err(make(.Io)); }
if !put_zeros(&out, align8(s.len) - s.len) { ret .Err(make(.Io)); }
if !put_u64(out, s.len) { ret .Err(make(.Io)); }
if !put_view(out, s) { ret .Err(make(.Io)); }
if !put_zeros(out, align8(s.len) - s.len) { ret .Err(make(.Io)); }
i = i + 1;
}
@@ -646,11 +664,22 @@ fn store(self: *Prog, path: ByteView): Status {
var e = gdata_at(self, i);
if e == null { ret .Err(make(.Io)); }
var dsize = e.storage.len;
if !put_u64(&out, dsize) { ret .Err(make(.Io)); }
if !put_view(&out, ByteView.from_slice(ByteBuffer.as_slice(e.*))) { ret .Err(make(.Io)); }
if !put_zeros(&out, align8(dsize) - dsize) { ret .Err(make(.Io)); }
if !put_u64(out, dsize) { ret .Err(make(.Io)); }
if !put_view(out, ByteView.from_slice(ByteBuffer.as_slice(e.*))) { ret .Err(make(.Io)); }
if !put_zeros(out, align8(dsize) - dsize) { ret .Err(make(.Io)); }
i = i + 1;
}
ret .Ok;
}
fn store(self: *Prog, path: ByteView): Status {
var out = ByteBuffer.new();
defer { ByteBuffer.drop(&out); }
match encode(self, &out) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
var f = open_cstr(path, ByteView.from_slice("wb"));
if !File.valid(&f) { ret .Err(make(.Io)); }
+38 -1
View File
@@ -282,6 +282,7 @@ fn can_start_expr(kind: TokenKind): bool {
.For => { ret true; },
.Match => { ret true; },
.Comptime => { ret true; },
.Try => { ret true; },
_ => { ret false; },
}
},
@@ -321,6 +322,7 @@ fn can_start_statement(kind: TokenKind): bool {
.Break => { ret true; },
.Continue => { ret true; },
.Defer => { ret true; },
.Errdefer => { ret true; },
.Var => { ret true; },
.Const => { ret true; },
.Type => { ret true; },
@@ -1237,7 +1239,19 @@ fn parse_expr_prec(self: *Parser, min_prec: i32): usize {
}
fn parse_expr(self: *Parser): usize {
ret parse_expr_prec(self, 1);
var e = parse_expr_prec(self, 1);
// `expr catch <pattern> <block>`:catch 用解包语法绑定错误。
while !self.failed {
var t = peek(self);
if t == null { break; }
if !kind_is_keyword(t.kind, .Catch) { break; }
advance(self);
var pat = parse_pattern(self);
if pat == 0 { ret e; }
var handler = parse_block(self);
e = new_node(self, .ExprCatch(.{ .value = e, .pattern = pat, .handler = handler }), t);
}
ret e;
}
fn parse_cast(self: *Parser): usize {
@@ -1444,6 +1458,12 @@ fn parse_primary(self: *Parser): usize {
if @enum2int(k) == @enum2int(Keyword.Loop) { ret parse_loop_expr(self); }
if @enum2int(k) == @enum2int(Keyword.For) { ret parse_for_expr(self); }
if @enum2int(k) == @enum2int(Keyword.Match) { ret parse_match_expr(self); }
// `try <expr>`:错误上抛前缀。
if @enum2int(k) == @enum2int(Keyword.Try) {
advance(self);
var tv = parse_expr(self);
ret new_node(self, .ExprTry(.{ .value = tv }), t);
}
// `comptime <expr>`:编译期表达式(可调用普通函数、返回类型等)。
if @enum2int(k) == @enum2int(Keyword.Comptime) {
advance(self);
@@ -1958,6 +1978,22 @@ fn parse_defer_stmt(self: *Parser): usize {
ret new_node(self, .StatementDefer(.{ .body = body }), kw);
}
fn parse_errdefer_stmt(self: *Parser): usize {
var kw = peek(self);
if kw == null || !kind_is_keyword(kw.kind, .Errdefer) { ret 0; }
advance(self);
var body: usize = 0;
var t = peek(self);
if t != null && kind_is_punct(t.kind, .LBrace) { body = parse_block(self); }
else if t != null && can_start_statement(t.kind) { body = parse_statement(self); }
else {
body = parse_expr(self);
t = peek(self);
if t != null && kind_is_punct(t.kind, .Semicolon) { advance(self); }
}
ret new_node(self, .StatementErrdefer(.{ .body = body }), kw);
}
fn parse_comptime_stmt(self: *Parser): usize {
var kw = peek(self);
if kw == null || !kind_is_keyword(kw.kind, .Comptime) { ret 0; }
@@ -1979,6 +2015,7 @@ fn parse_statement(self: *Parser): usize {
if @enum2int(k) == @enum2int(Keyword.Break) { ret parse_break_stmt(self); }
if @enum2int(k) == @enum2int(Keyword.Continue) { ret parse_continue_stmt(self); }
if @enum2int(k) == @enum2int(Keyword.Defer) { ret parse_defer_stmt(self); }
if @enum2int(k) == @enum2int(Keyword.Errdefer) { ret parse_errdefer_stmt(self); }
if @enum2int(k) == @enum2int(Keyword.Comptime) { ret parse_comptime_stmt(self); }
if @enum2int(k) == @enum2int(Keyword.Var) ||
@enum2int(k) == @enum2int(Keyword.Const) ||
-637
View File
@@ -1,637 +0,0 @@
/* spl_rt.h - SPL native runtime (header-only, C89-friendly)
*
* 提供 ir2c 生成代码所需的所有 `#extern(vm)` 符号,以及 SPL 基础类型别名。
* 目标:生成代码可用 C89 语法通过(不依赖 stdint/stdbool)。
*/
#ifndef __SPL_RT_H__
#define __SPL_RT_H__
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* 语义清晰的 inline:C99 用 static inline,GNU 用 __inline__,C89 退化为 static */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define SPL_INLINE static inline
#elif defined(__GNUC__) || defined(__clang__)
#define SPL_INLINE static __inline__
#else
#define SPL_INLINE static
#endif
/* ---- SPL 基础类型别名 ---- */
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
#ifndef SPL_USIZE_TYPEDEF
#define SPL_USIZE_TYPEDEF
typedef u64 usize;
#endif
#ifndef SPL_ISIZE_TYPEDEF
#define SPL_ISIZE_TYPEDEF
typedef i64 isize;
#endif
/* 注:不定义 bool/true/false,避免与 C23 关键字冲突;生成代码用 u8 表示布尔。 */
/* ---- panic / trap ---- */
SPL_INLINE void spl_panic(const char *msg) {
fprintf(stderr, "%s\n", msg ? msg : "panic");
exit(1);
}
SPL_INLINE void spl_trap(void) { abort(); }
/* ---- mem ---- */
SPL_INLINE void *vm_alloc(u64 sz) {
if (sz == 0)
return NULL;
return malloc((size_t)sz);
}
SPL_INLINE void vm_free(void *p) {
if (p)
free(p);
}
SPL_INLINE void *vm_realloc(void *p, u64 sz) {
if (!p)
return vm_alloc(sz);
if (sz == 0) {
free(p);
return NULL;
}
return realloc(p, (size_t)sz);
}
SPL_INLINE void *vm_memcpy(void *dst, const void *src, u64 n) {
if (n)
memcpy(dst, src, (size_t)n);
return dst;
}
SPL_INLINE void *vm_memmove(void *dst, const void *src, u64 n) {
if (n)
memmove(dst, src, (size_t)n);
return dst;
}
SPL_INLINE i64 vm_memcmp(const void *a, const void *b, u64 n) {
if (n == 0)
return 0;
return (i64)memcmp(a, b, (size_t)n);
}
SPL_INLINE i32 vm_bytes_eq(const void *a, u64 alen, const void *b, u64 blen) {
if (alen != blen)
return 0;
if (alen == 0)
return 1;
if (!a || !b)
return 0;
return memcmp(a, b, (size_t)alen) == 0;
}
/* ---- Vec ---- */
typedef struct {
usize raw;
usize data;
usize len;
usize cap;
usize elem_size;
usize elem_align;
} spl_vec_t;
SPL_INLINE int spl_vec_is_valid(const spl_vec_t *v) {
usize a;
if (v->elem_size == 0)
return 0;
a = v->elem_align;
if (a == 0 || (a & (a - 1)) != 0)
return 0;
if (v->len > v->cap)
return 0;
if (v->cap == 0)
return v->raw == 0 && v->data == 0 && v->len == 0;
if (v->raw == 0 || v->data == 0)
return 0;
return (v->data & (a - 1)) == 0;
}
SPL_INLINE int spl_align_ok(usize a) { return a != 0 && (a & (a - 1)) == 0; }
SPL_INLINE void spl_grow(usize current, usize need, usize *out) {
usize cap = current < 8 ? 8 : current;
usize limit = ~(usize)0;
while (cap < need) {
if (cap > limit / 2) {
cap = need;
break;
}
cap = cap * 2;
}
*out = cap;
}
SPL_INLINE int spl_vec_allocate(spl_vec_t *out, usize capacity, usize elem_size, usize elem_align) {
usize bytes, mask, addr;
void *raw;
if (elem_size == 0)
return 1;
if (!spl_align_ok(elem_align))
return 4;
out->raw = 0;
out->data = 0;
out->len = 0;
out->cap = 0;
out->elem_size = elem_size;
out->elem_align = elem_align;
if (capacity == 0)
return 0;
if (capacity > ~(usize)0 / elem_size)
return 3;
bytes = capacity * elem_size;
mask = elem_align - 1;
if (bytes > ~(usize)0 - mask)
return 3;
raw = malloc(bytes + mask);
if (!raw)
return 3;
addr = (usize)raw;
if (addr > ~(usize)0 - mask) {
free(raw);
return 3;
}
out->raw = addr;
out->data = (addr + mask) & ~mask;
out->cap = capacity;
return 0;
}
SPL_INLINE int spl_vec_reserve_raw(spl_vec_t *v, usize need) {
usize new_cap = 0, used = 0, old;
spl_vec_t fresh;
int rc;
if (need <= v->cap)
return 0;
spl_grow(v->cap, need, &new_cap);
rc = spl_vec_allocate(&fresh, new_cap, v->elem_size, v->elem_align);
if (rc)
return rc;
if (v->len != 0) {
if (v->len > ~(usize)0 / v->elem_size) {
free((void *)fresh.raw);
return 3;
}
used = v->len * v->elem_size;
}
if (used)
memcpy((void *)fresh.data, (void *)v->data, used);
fresh.len = v->len;
old = v->raw;
*v = fresh;
if (old)
free((void *)old);
return 0;
}
SPL_INLINE void spl_vec_release(spl_vec_t *v) {
usize es = v->elem_size, ea = v->elem_align;
if (v->raw)
free((void *)v->raw);
v->raw = 0;
v->data = 0;
v->len = 0;
v->cap = 0;
v->elem_size = es;
v->elem_align = ea;
}
SPL_INLINE i32 vm_vec_valid(void *vv) {
const spl_vec_t *v = (const spl_vec_t *)vv;
return v ? spl_vec_is_valid(v) : 0;
}
SPL_INLINE i32 vm_vec_push_raw(void *vv, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !elem)
return 0;
if (v->len < v->cap) {
memcpy((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 1;
}
return 0;
}
SPL_INLINE i32 vm_vec_get(void *vv, u64 index, void **out) {
const spl_vec_t *v = (const spl_vec_t *)vv;
if (!v || !out)
return 1;
if (!spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
*out = (void *)(v->data + index * v->elem_size);
return 0;
}
SPL_INLINE i32 vm_vec_push(void *vv, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
int rc;
if (!v || !elem || !spl_vec_is_valid(v))
return 1;
if (v->len < v->cap) {
memcpy((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 0;
}
rc = spl_vec_reserve_raw(v, v->len + 1);
if (rc)
return rc;
memmove((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 0;
}
SPL_INLINE i32 vm_vec_allocate(void *out, u64 capacity, u64 elem_size, u64 elem_align) {
return spl_vec_allocate((spl_vec_t *)out, capacity, elem_size, elem_align);
}
SPL_INLINE i32 vm_vec_reserve_raw(void *vv, u64 need) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v)
return 1;
return spl_vec_reserve_raw(v, need);
}
SPL_INLINE i32 vm_vec_append(void *vv, const void *elems, u64 count) {
spl_vec_t *v = (spl_vec_t *)vv;
usize copy_bytes, new_len, used, source_offset = 0;
int source_inside = 0, rc;
if (!v || !spl_vec_is_valid(v))
return 1;
if (count == 0)
return 0;
if (!elems)
return 1;
if (count > ~(usize)0 / v->elem_size)
return 3;
copy_bytes = count * v->elem_size;
if (v->len > ~(usize)0 - count)
return 3;
new_len = v->len + count;
used = v->len * v->elem_size;
if (used) {
usize base = v->data;
usize source = (usize)elems;
if (source >= base && source - base < used) {
source_offset = source - base;
if (copy_bytes > used - source_offset)
return 2;
source_inside = 1;
}
}
rc = spl_vec_reserve_raw(v, new_len);
if (rc)
return rc;
if (source_inside)
elems = (const void *)(v->data + source_offset);
memmove((void *)(v->data + used), elems, copy_bytes);
v->len = new_len;
return 0;
}
SPL_INLINE i32 vm_vec_set(void *vv, u64 index, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !elem || !spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
memmove((void *)(v->data + index * v->elem_size), elem, v->elem_size);
return 0;
}
SPL_INLINE i32 vm_vec_pop(void *vv, void *out) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !out || !spl_vec_is_valid(v))
return 1;
if (v->len == 0)
return 2;
memmove(out, (void *)(v->data + (v->len - 1) * v->elem_size), v->elem_size);
v->len--;
return 0;
}
SPL_INLINE i32 vm_vec_clone(void *outp, const void *srcp) {
spl_vec_t *out = (spl_vec_t *)outp;
const spl_vec_t *src = (const spl_vec_t *)srcp;
spl_vec_t fresh;
usize bytes;
int rc;
if (!out || !src || !spl_vec_is_valid(out) || !spl_vec_is_valid(src))
return 1;
if (out->elem_size != src->elem_size || out->elem_align != src->elem_align)
return 1;
fresh.raw = 0;
fresh.data = 0;
fresh.len = 0;
fresh.cap = 0;
fresh.elem_size = src->elem_size;
fresh.elem_align = src->elem_align;
rc = spl_vec_reserve_raw(&fresh, src->len);
if (rc)
return rc;
bytes = src->len * src->elem_size;
if (bytes)
memcpy((void *)fresh.data, (void *)src->data, bytes);
fresh.len = src->len;
if (out->raw)
free((void *)out->raw);
*out = fresh;
return 0;
}
SPL_INLINE void vm_vec_drop(void *vv) {
spl_vec_t *v = (spl_vec_t *)vv;
if (v)
spl_vec_release(v);
}
/* ---- Map ---- */
typedef struct {
spl_vec_t keys;
spl_vec_t vals;
spl_vec_t states;
usize size;
usize key_size;
usize val_size;
usize hash_kind;
} spl_map_t;
SPL_INLINE usize spl_hash_usize_value(usize value) {
usize prime = 1099511628211ull;
usize h = value;
h = (h ^ (h >> 30)) * prime;
h = h ^ (h >> 27);
h = h * prime;
h = h ^ (h >> 31);
if (h == 0)
return prime;
return h;
}
SPL_INLINE usize spl_hash_bytes(const void *data, usize len) {
const unsigned char *p = (const unsigned char *)data;
usize h = 14695981039346656037ull;
usize prime = 1099511628211ull;
usize i;
for (i = 0; i < len; i++)
h = (h ^ (usize)p[i]) * prime;
return h;
}
SPL_INLINE usize spl_map_hash(const spl_map_t *m, const void *key) {
const usize *v;
if (m->hash_kind == 0)
return spl_hash_usize_value(*(const usize *)key);
if (m->hash_kind == 2)
return 3;
v = (const usize *)key;
return spl_hash_bytes((const void *)v[0], v[1]);
}
SPL_INLINE int spl_map_eq(const spl_map_t *m, const void *a, const void *b) {
const usize *x;
const usize *y;
if (m->hash_kind == 0 || m->hash_kind == 2)
return *(const usize *)a == *(const usize *)b;
x = (const usize *)a;
y = (const usize *)b;
if (x[1] != y[1])
return 0;
if (x[1] == 0)
return 1;
return memcmp((const void *)x[0], (const void *)y[0], x[1]) == 0;
}
SPL_INLINE int spl_map_valid(const spl_map_t *m) {
if (m->key_size == 0 || m->val_size == 0)
return 0;
if (m->keys.len != m->states.len || m->vals.len != m->states.len)
return 0;
if (m->size > m->states.len)
return 0;
return 1;
}
SPL_INLINE usize spl_map_find_slot(const spl_map_t *m, const void *key) {
usize mask, i, probes;
unsigned char *st;
if (m->states.cap == 0)
return ~(usize)0;
mask = m->states.cap - 1;
i = spl_map_hash(m, key) & mask;
st = (unsigned char *)m->states.data;
probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 1 && spl_map_eq(m, (const void *)(m->keys.data + i * m->key_size), key))
return i;
i = (i + 1) & mask;
probes++;
}
return ~(usize)0;
}
SPL_INLINE void spl_map_place(spl_map_t *m, const void *key, const void *val) {
usize mask, i, first_deleted, probes;
unsigned char *st;
mask = m->states.cap - 1;
i = spl_map_hash(m, key) & mask;
st = (unsigned char *)m->states.data;
first_deleted = ~(usize)0;
probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 2 && first_deleted == ~(usize)0)
first_deleted = i;
i = (i + 1) & mask;
probes++;
}
if (first_deleted != ~(usize)0)
i = first_deleted;
memcpy((void *)(m->keys.data + i * m->key_size), key, m->key_size);
memcpy((void *)(m->vals.data + i * m->val_size), val, m->val_size);
st[i] = 1;
m->size++;
}
SPL_INLINE int spl_map_reserve(spl_map_t *m, usize need) {
usize new_cap = 0, i;
spl_map_t fresh;
int rc;
if (!spl_map_valid(m))
return 1;
if (need <= m->states.cap)
return 0;
spl_grow(m->states.cap, need, &new_cap);
fresh = *m;
fresh.keys.raw = 0;
fresh.keys.data = 0;
fresh.keys.len = 0;
fresh.keys.cap = 0;
fresh.vals.raw = 0;
fresh.vals.data = 0;
fresh.vals.len = 0;
fresh.vals.cap = 0;
fresh.states.raw = 0;
fresh.states.data = 0;
fresh.states.len = 0;
fresh.states.cap = 0;
fresh.size = 0;
rc = spl_vec_reserve_raw(&fresh.keys, new_cap);
if (rc)
goto fail;
rc = spl_vec_reserve_raw(&fresh.vals, new_cap);
if (rc)
goto fail;
rc = spl_vec_reserve_raw(&fresh.states, new_cap);
if (rc)
goto fail;
fresh.keys.len = new_cap;
fresh.vals.len = new_cap;
fresh.states.len = new_cap;
memset((void *)fresh.states.data, 0, new_cap);
for (i = 0; i < m->states.len; i++) {
if (((unsigned char *)m->states.data)[i] == 1)
spl_map_place(&fresh, (const void *)(m->keys.data + i * m->key_size),
(const void *)(m->vals.data + i * m->val_size));
}
spl_vec_release(&m->keys);
spl_vec_release(&m->vals);
spl_vec_release(&m->states);
*m = fresh;
return 0;
fail:
spl_vec_release(&fresh.keys);
spl_vec_release(&fresh.vals);
spl_vec_release(&fresh.states);
return rc;
}
SPL_INLINE i32 vm_map_valid(void *mm) {
const spl_map_t *m = (const spl_map_t *)mm;
return m ? spl_map_valid(m) : 0;
}
SPL_INLINE i32 vm_map_reserve(void *mm, u64 need) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return 1;
return spl_map_reserve(m, need);
}
SPL_INLINE i32 vm_map_put(void *mm, const void *key, const void *val) {
spl_map_t *m = (spl_map_t *)mm;
usize existing;
if (!m || !key || !val || !spl_map_valid(m))
return 1;
existing = spl_map_find_slot(m, key);
if (existing != ~(usize)0) {
memcpy((void *)(m->vals.data + existing * m->val_size), val, m->val_size);
return 0;
}
if (m->states.cap == 0) {
int rc = spl_map_reserve(m, 8);
if (rc)
return rc;
} else {
usize next_size, scaled;
if (m->size > ~(usize)0 - 1)
return 3;
next_size = m->size + 1;
if (next_size > ~(usize)0 / 128)
return 3;
scaled = next_size * 128;
if (scaled / m->states.cap >= 70) {
int rc;
if (m->states.cap > ~(usize)0 / 2)
return 3;
rc = spl_map_reserve(m, m->states.cap * 2);
if (rc)
return rc;
}
}
spl_map_place(m, key, val);
return 0;
}
SPL_INLINE i32 vm_map_get(void *mm, const void *key, void *out) {
spl_map_t *m = (spl_map_t *)mm;
usize i;
if (!m || !key || !out || !spl_map_valid(m))
return 1;
i = spl_map_find_slot(m, key);
if (i == ~(usize)0)
return 1;
memcpy(out, (void *)(m->vals.data + i * m->val_size), m->val_size);
return 0;
}
SPL_INLINE i32 vm_map_del(void *mm, const void *key) {
spl_map_t *m = (spl_map_t *)mm;
usize i;
if (!m || !key || !spl_map_valid(m))
return 1;
i = spl_map_find_slot(m, key);
if (i == ~(usize)0)
return 1;
((unsigned char *)m->states.data)[i] = 2;
m->size--;
return 0;
}
SPL_INLINE void vm_map_clear(void *mm) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return;
if (m->states.data && m->states.len)
memset((void *)m->states.data, 0, m->states.len);
m->size = 0;
}
SPL_INLINE void vm_map_drop(void *mm) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return;
spl_vec_release(&m->keys);
spl_vec_release(&m->vals);
spl_vec_release(&m->states);
m->size = 0;
}
/* ---- file ---- */
SPL_INLINE void *vm_fopen(void *path, void *mode) {
return (void *)fopen((const char *)path, (const char *)mode);
}
SPL_INLINE i32 vm_fclose(void *f) { return f ? fclose((FILE *)f) : 0; }
SPL_INLINE u64 vm_fread(void *buf, u64 sz, u64 n, void *f) {
return f ? (u64)fread(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0;
}
SPL_INLINE u64 vm_fwrite(void *buf, u64 sz, u64 n, void *f) {
return f ? (u64)fwrite(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0;
}
SPL_INLINE u64 vm_fsize(void *f) {
long cur, end;
if (!f)
return 0;
cur = ftell((FILE *)f);
if (cur < 0)
return 0;
if (fseek((FILE *)f, 0, SEEK_END) != 0)
return 0;
end = ftell((FILE *)f);
fseek((FILE *)f, cur, SEEK_SET);
return end < 0 ? 0 : (u64)end;
}
SPL_INLINE void *vm_stdin(void) { return (void *)stdin; }
SPL_INLINE void *vm_stdout(void) { return (void *)stdout; }
SPL_INLINE void *vm_stderr(void) { return (void *)stderr; }
SPL_INLINE i32 vm_putchar(i32 c) { return fputc(c, stdout); }
SPL_INLINE i32 vm_getchar(void) { return fgetc(stdin); }
/* ---- misc ---- */
SPL_INLINE void vm_exit(i32 code) { exit(code); }
SPL_INLINE u64 vm_timestamp(u64 kind) {
time_t sec = time(NULL);
if (kind == 1)
return (u64)sec;
if (kind == 2)
return 0;
if (kind == 4)
return (u64)sec * 1000000000ull;
return 0;
}
/* ---- 内嵌 VM(comptime):实现在 spl_vm_embed.c,链接 stage0 VM ---- */
#define SPL_VM_EMBED_IMPLIMENTATION
#include "spl_vm_embed.h"
#endif /* __SPL_RT_H__ */