fix intrinsics and env

This commit is contained in:
2026-02-16 23:05:00 -06:00
parent 63955e45ff
commit c9dad91ea1
13 changed files with 94696 additions and 86771 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -229,7 +229,6 @@ Function calls are decomposed into three instructions:
| Instruction | Operands | Description |
|-------------|----------|-------------|
| `access` | `dest, name` | Load variable (intrinsic or module environment) |
| `set_var` | `name, src` | Set top-level variable by name |
| `get` | `dest, level, slot` | Get closure variable from parent scope |
| `put` | `level, slot, src` | Set closure variable in parent scope |

View File

@@ -22,33 +22,6 @@ function use_embed(name) {
return load_internal("js_core_" + name + "_use")
}
// These duplicate C builtins from runtime.c, but are needed because the GC can
// lose properties on the global object after compaction. The runtime_env provides
// a stable way for modules to access them via env_record linking.
function logical(val1) {
if (val1 == 0 || val1 == false || val1 == "false" || val1 == null)
return false;
if (val1 == 1 || val1 == true || val1 == "true")
return true;
return null;
}
function some(arr, pred) {
return find(arr, pred) != null
}
function every(arr, pred) {
return find(arr, x => not(pred(x))) == null
}
function starts_with(str, prefix) {
return search(str, prefix) == 0
}
function ends_with(str, suffix) {
return search(str, suffix, -length(suffix)) != null
}
var fd = use_embed('internal_fd')
var js = use_embed('js')
var crypto = use_embed('crypto')
@@ -87,7 +60,7 @@ function boot_load(name) {
}
mcode_blob = fd.slurp(mcode_path)
mach_blob = mach_compile_mcode_bin(name, text(mcode_blob))
return mach_load(mach_blob, {use: use_embed})
return mach_load(mach_blob, stone({use: use_embed}))
}
// Load a pipeline module from cache; on miss compile from source via boot chain
@@ -451,14 +424,6 @@ var parallel = pronto.parallel
var race = pronto.race
var sequence = pronto.sequence
// Fill runtime_env — includes duplicates of C builtins because the GC can
// lose global object properties after compaction. Modules resolve these via
// env_record, not the global.
runtime_env.logical = logical
runtime_env.some = some
runtime_env.every = every
runtime_env.starts_with = starts_with
runtime_env.ends_with = ends_with
runtime_env.actor = actor
runtime_env.is_actor = is_actor
runtime_env.log = log

View File

@@ -1384,8 +1384,6 @@ var mcode = function(ast) {
pstate = parent_states[length(parent_states) - 1 - _lv]
pslot = find_var_in_saved(pstate, name)
emit_3("put", dest, pslot, level)
} else {
add_instr(["set_var", name, dest])
}
return dest
} else if (left_kind == ".") {
@@ -1486,9 +1484,6 @@ var mcode = function(ast) {
return val_slot
}
val_slot = gen_expr(right, -1)
if (level == -1) {
add_instr(["set_var", name, val_slot])
}
} else {
val_slot = gen_expr(right, -1)
if (level > 0) {

View File

@@ -976,17 +976,6 @@ var qbe_emit = function(ir, qbe, export_name) {
continue
}
// --- set_var [G] ---
if (op == "set_var") {
// IR: ["set_var", name_string, value_slot]
v = s_read(a2)
sl = intern_str(a1)
emit(` call $cell_rt_set_var(l %ctx, l ${v}, l ${sl})`)
refresh_fp()
continue
}
// --- in [G] ---
if (op == "in") {

View File

@@ -86,9 +86,10 @@ static JSValue *mach_materialize_cpool(JSContext *ctx, MachCPoolEntry *entries,
static void mach_link_code(JSContext *ctx, JSCodeRegister *code, JSValue env) {
if (!JS_IsNull(env) && !JS_IsStone(env)) {
fprintf(stderr, "mach_link_code: WARNING env not stone (code=%s file=%s)\n",
fprintf(stderr, "mach_link_code: ERROR env not stone (code=%s file=%s)\n",
code->name_cstr ? code->name_cstr : "<unknown>",
code->filename_cstr ? code->filename_cstr : "<unknown>");
abort();
}
JSGCRef env_ref;
JS_PushGCRef(ctx, &env_ref);
@@ -864,7 +865,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
DT(MACH_GOINVOKE),
DT(MACH_JMPNOTNULL),
DT(MACH_DISRUPT),
DT(MACH_SET_VAR), DT(MACH_IN),
DT(MACH_IN),
DT(MACH_IS_ARRAY), DT(MACH_IS_FUNC),
DT(MACH_IS_RECORD), DT(MACH_IS_STONE),
DT(MACH_LENGTH), DT(MACH_IS_PROXY),
@@ -2048,21 +2049,6 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
VM_CASE(MACH_DISRUPT):
goto disrupt;
/* Variable storage: env/global[K(Bx)] = R(A) */
VM_CASE(MACH_SET_VAR): {
int bx = MACH_GET_Bx(instr);
JSValue key = code->cpool[bx];
JSValue val = frame->slots[a];
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.reg.env_record;
if (!JS_IsNull(cur_env)) {
JS_SetProperty(ctx, cur_env, key, val);
} else {
JS_SetProperty(ctx, ctx->global_obj, key, val);
}
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
VM_BREAK();
}
/* Has-property check (mcode name) */
VM_CASE(MACH_IN): {
JSValue key = frame->slots[b];
@@ -2301,9 +2287,6 @@ static int mcode_reg_items(cJSON *it, cJSON **out) {
/* goinvoke: [1]=frame only (no result) */
if (!strcmp(op, "goinvoke")) { ADD(1); return c; }
/* set_var: [1]=name(string), [2]=val */
if (!strcmp(op, "set_var")) { ADD(2); return c; }
/* setarg: [1]=call, [2]=arg_idx(const), [3]=val */
if (!strcmp(op, "setarg")) { ADD(1); ADD(3); return c; }
@@ -2873,12 +2856,6 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
else if (strcmp(op, "disrupt") == 0) {
EM(MACH_ABC(MACH_DISRUPT, 0, 0, 0));
}
/* Variable storage */
else if (strcmp(op, "set_var") == 0) {
const char *vname = cJSON_GetArrayItem(it, 1)->valuestring;
int val_reg = A2;
EM(MACH_ABx(MACH_SET_VAR, val_reg, ml_cpool_str(&s, vname)));
}
/* Misc */
else if (strcmp(op, "in") == 0) {
EM(MACH_ABC(MACH_IN, A1, A2, A3));

View File

@@ -267,7 +267,8 @@ static int g_has_native_env = 0;
void cell_rt_set_native_env(JSContext *ctx, JSValue env) {
if (!JS_IsNull(env) && !JS_IsStone(env)) {
fprintf(stderr, "cell_rt_set_native_env: WARNING env not stone\n");
fprintf(stderr, "cell_rt_set_native_env: ERROR env not stone\n");
abort();
}
if (g_has_native_env)
JS_DeleteGCRef(ctx, &g_native_env_ref);
@@ -585,13 +586,6 @@ void cell_rt_disrupt(JSContext *ctx) {
JS_ThrowTypeError(ctx, "type error in native code");
}
/* --- set_var: set a variable in env_record or global --- */
void cell_rt_set_var(JSContext *ctx, JSValue val, const char *name) {
JSValue key = JS_NewString(ctx, name);
JS_SetProperty(ctx, ctx->global_obj, key, val);
}
/* --- in: key in obj --- */
JSValue cell_rt_in(JSContext *ctx, JSValue key, JSValue obj) {

View File

@@ -639,9 +639,6 @@ typedef enum MachOpcode {
/* Error handling */
MACH_DISRUPT, /* trigger disruption (A only) */
/* Variable storage */
MACH_SET_VAR, /* env/global[K(Bx)] = R(A) — store to var (ABx) */
/* Misc */
MACH_IN, /* R(A) = (R(B) in R(C)) — has property (ABC) */
@@ -764,7 +761,6 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
[MACH_GOINVOKE] = "goinvoke",
[MACH_JMPNOTNULL] = "jmpnotnull",
[MACH_DISRUPT] = "disrupt",
[MACH_SET_VAR] = "set_var",
[MACH_IN] = "in",
/* Extended type checks */
[MACH_IS_ARRAY] = "is_array",

View File

@@ -1688,6 +1688,34 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
scan += obj_size;
}
#ifdef VALIDATE_GC
{
JSRecord *grec = JS_VALUE_GET_RECORD(ctx->global_obj);
uint32_t mask = (uint32_t)objhdr_cap56(grec->mist_hdr);
for (uint32_t i = 1; i <= mask; i++) {
JSValue k = grec->slots[i].key;
if (!rec_key_is_empty(k) && !rec_key_is_tomb(k)) {
if (!JS_IsPtr(k)) {
fprintf(stderr, "VALIDATE_GC: global slot[%u] key is not a pointer (tag=0x%llx)\n",
i, (unsigned long long)k);
} else {
void *kp = JS_VALUE_GET_PTR(k);
if (!ptr_in_range(kp, to_base, to_free) && !is_ct_ptr(ctx, kp)) {
fprintf(stderr, "VALIDATE_GC: global slot[%u] key=%p outside valid ranges\n", i, kp);
}
}
JSValue v = grec->slots[i].val;
if (JS_IsPtr(v)) {
void *vp = JS_VALUE_GET_PTR(v);
if (!ptr_in_range(vp, to_base, to_free) && !is_ct_ptr(ctx, vp)) {
fprintf(stderr, "VALIDATE_GC: global slot[%u] val=%p outside valid ranges\n", i, vp);
}
}
}
}
}
#endif
/* Return old block (in poison mode, just poison it and leak) */
heap_block_free (rt, from_base, old_heap_size);
@@ -1960,6 +1988,7 @@ JSContext *JS_NewContext (JSRuntime *rt) {
if (!ctx) return NULL;
JS_AddIntrinsicBaseObjects (ctx);
JS_AddIntrinsicRegExp (ctx);
obj_set_stone (JS_VALUE_GET_RECORD (ctx->global_obj));
return ctx;
}
@@ -1967,7 +1996,8 @@ JSContext *JS_NewContextWithHeapSize (JSRuntime *rt, size_t heap_size) {
JSContext *ctx = JS_NewContextRawWithHeapSize (rt, heap_size);
if (!ctx) return NULL;
JS_AddIntrinsicBaseObjects (ctx);
JS_AddIntrinsicRegExp (ctx);
JS_AddIntrinsicRegExp (ctx);
obj_set_stone (JS_VALUE_GET_RECORD (ctx->global_obj));
return ctx;
}