stage2 提供c后端 提交stage1的测试
This commit is contained in:
1 parent
846f441e3a
commit
51d408d524
82 files changed
+6872
-65
No files matched your search
@@ -0,0 +1,629 @@
|
||||
/* 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;
|
||||
typedef u64 usize;
|
||||
typedef i64 isize;
|
||||
/* 注:不定义 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__ */
|
||||
@@ -0,0 +1,109 @@
|
||||
/* spl_vm_embed.h - 原生编译器内嵌 VM(comptime 执行)。
|
||||
*
|
||||
* 单 TU 合并式:定义 SPL_VM_EMBED_IMPLIMENTATION 后 include 本头,会把 stage0 的
|
||||
* spl_mcode.c / spl_syscall.c / spl_vm.c 一并纳入当前翻译单元(不单独编译/链接)。
|
||||
*/
|
||||
|
||||
#ifndef __SPL_VM_EMBED_H__
|
||||
#define __SPL_VM_EMBED_H__
|
||||
|
||||
void *vm_new(void);
|
||||
void vm_drop(void *vm);
|
||||
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);
|
||||
|
||||
#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"
|
||||
|
||||
void *vm_new(void) {
|
||||
spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t));
|
||||
if (!vm)
|
||||
return 0;
|
||||
spl_vm_init(vm);
|
||||
return vm;
|
||||
}
|
||||
|
||||
void vm_drop(void *p) {
|
||||
spl_vm_t *vm = (spl_vm_t *)p;
|
||||
if (!vm)
|
||||
return;
|
||||
if (vm->prog) {
|
||||
spl_prog_drop(vm->prog);
|
||||
free(vm->prog);
|
||||
vm->prog = 0;
|
||||
}
|
||||
spl_vm_drop(vm);
|
||||
free(vm);
|
||||
}
|
||||
|
||||
int vm_load_from_buffer(void *p, const void *buf, unsigned long long len) {
|
||||
spl_vm_t *vm = (spl_vm_t *)p;
|
||||
spl_prog_t *prog;
|
||||
if (!vm || !buf)
|
||||
return -1;
|
||||
prog = (spl_prog_t *)malloc(sizeof(spl_prog_t));
|
||||
if (!prog)
|
||||
return -1;
|
||||
if (spl_prog_load_from_buffer((const char *)buf, (usize)len, prog) != 0) {
|
||||
free(prog);
|
||||
return -1;
|
||||
}
|
||||
spl_syscall_register(prog);
|
||||
if (spl_vm_load_prog(vm, prog) != 0) {
|
||||
spl_prog_drop(prog);
|
||||
free(prog);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vm_push(void *p, unsigned long long val) {
|
||||
spl_vm_t *vm = (spl_vm_t *)p;
|
||||
if (!vm)
|
||||
return;
|
||||
if (vm->sp >= vm->config.max_stack_depth)
|
||||
return;
|
||||
vm->stacks.data[vm->sp++] = (spl_vm_val_t)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;
|
||||
}
|
||||
|
||||
int vm_run(void *p) {
|
||||
spl_vm_t *vm = (spl_vm_t *)p;
|
||||
if (!vm)
|
||||
return -1;
|
||||
spl_vm_run_until(vm, 0);
|
||||
return (int)vm->exit_code;
|
||||
}
|
||||
#endif /* SPL_VM_EMBED_IMPLIMENTATION */
|
||||
|
||||
#endif /* __SPL_VM_EMBED_H__ */
|
||||
+1
-1
@@ -5,7 +5,7 @@ type spl_vm_val_t = u64; // usize
|
||||
#extern(vm) fn vm_drop(vm: *any): void;
|
||||
|
||||
#extern(vm) fn vm_load(vm: *any, fpath: *u8): void;
|
||||
#extern(vm) fn vm_load_from_buffer(vm: *any, buffer: []u8): void;
|
||||
#extern(vm) fn vm_load_from_buffer(vm: *any, buf: *any, len: usize): i32;
|
||||
|
||||
#extern(vm) fn vm_push(vm: *any, val: spl_vm_val_t): void;
|
||||
// TODO
|
||||
|
||||
Reference in new issue
Block a user