Merge branch 'gen_dylib'

This commit is contained in:
2026-02-17 08:59:05 -06:00
23 changed files with 96093 additions and 87168 deletions

View File

@@ -85,6 +85,12 @@ static JSValue *mach_materialize_cpool(JSContext *ctx, MachCPoolEntry *entries,
/* ---- Link pass: resolve GETNAME to GETINTRINSIC or GETENV ---- */
static void mach_link_code(JSContext *ctx, JSCodeRegister *code, JSValue env) {
if (!JS_IsNull(env) && !JS_IsStone(env)) {
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);
env_ref.val = env;
@@ -809,7 +815,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
DT(MACH_ADD), DT(MACH_SUB),
DT(MACH_MUL), DT(MACH_DIV),
DT(MACH_MOD), DT(MACH_POW),
DT(MACH_NEG), DT(MACH_INC), DT(MACH_DEC),
DT(MACH_NEG),
DT(MACH_EQ), DT(MACH_NEQ),
DT(MACH_LT), DT(MACH_LE),
DT(MACH_GT), DT(MACH_GE),
@@ -859,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),
@@ -1218,38 +1224,6 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
VM_BREAK();
}
VM_CASE(MACH_INC): {
JSValue v = frame->slots[b];
if (JS_IsInt(v)) {
int32_t i = JS_VALUE_GET_INT(v);
if (i == INT32_MAX)
frame->slots[a] = JS_NewFloat64(ctx, (double)i + 1);
else
frame->slots[a] = JS_NewInt32(ctx, i + 1);
} else {
double d;
JS_ToFloat64(ctx, &d, v);
frame->slots[a] = JS_NewFloat64(ctx, d + 1);
}
VM_BREAK();
}
VM_CASE(MACH_DEC): {
JSValue v = frame->slots[b];
if (JS_IsInt(v)) {
int32_t i = JS_VALUE_GET_INT(v);
if (i == INT32_MIN)
frame->slots[a] = JS_NewFloat64(ctx, (double)i - 1);
else
frame->slots[a] = JS_NewInt32(ctx, i - 1);
} else {
double d;
JS_ToFloat64(ctx, &d, v);
frame->slots[a] = JS_NewFloat64(ctx, d - 1);
}
VM_BREAK();
}
VM_CASE(MACH_LNOT): {
int bval = JS_ToBool(ctx, frame->slots[b]);
frame->slots[a] = JS_NewBool(ctx, !bval);
@@ -2075,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];
@@ -2128,6 +2087,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
pc = code->disruption_pc;
ctx->disruption_reported = FALSE;
frame_ref.val = JS_MKPTR(frame); /* root handler frame for GC */
ctx->current_exception = JS_NULL;
break;
}
if (JS_IsNull(frame->caller)) {
@@ -2334,9 +2294,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; }
@@ -2906,12 +2863,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));
@@ -3341,8 +3292,6 @@ static void dump_register_code(JSContext *ctx, JSCodeRegister *code, int indent)
/* A, B: move, unary ops */
case MACH_MOVE:
case MACH_NEG:
case MACH_INC:
case MACH_DEC:
case MACH_LNOT:
case MACH_BNOT:
printf("r%d, r%d", a, b);

View File

@@ -260,23 +260,70 @@ void cell_rt_store_index(JSContext *ctx, JSValue val, JSValue arr,
/* --- Intrinsic/global lookup --- */
/* Native module environment — set before executing a native module's cell_main.
Contains runtime functions (starts_with, ends_with, etc.) and use(). */
static JSGCRef g_native_env_ref;
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: ERROR env not stone\n");
abort();
}
if (g_has_native_env)
JS_DeleteGCRef(ctx, &g_native_env_ref);
if (!JS_IsNull(env)) {
JS_AddGCRef(ctx, &g_native_env_ref);
g_native_env_ref.val = env;
g_has_native_env = 1;
} else {
g_has_native_env = 0;
}
}
JSValue cell_rt_get_intrinsic(JSContext *ctx, const char *name) {
return JS_GetPropertyStr(ctx, ctx->global_obj, name);
/* Check native env first (runtime-provided functions like log) */
if (g_has_native_env) {
JSValue v = JS_GetPropertyStr(ctx, g_native_env_ref.val, name);
if (!JS_IsNull(v))
return v;
}
/* Linear scan of global object — avoids hash mismatch issues with
stoned records whose keys may be in cold storage */
JSValue gobj = ctx->global_obj;
if (JS_IsRecord(gobj)) {
JSRecord *rec = (JSRecord *)chase(gobj);
uint64_t mask = objhdr_cap56(rec->mist_hdr);
for (uint64_t i = 1; i <= mask; i++) {
if (js_key_equal_str(rec->slots[i].key, name))
return rec->slots[i].val;
}
}
JS_ThrowReferenceError(ctx, "'%s' is not defined", name);
return JS_EXCEPTION;
}
/* --- Closure access ---
Slot 511 in each frame stores a pointer to the enclosing frame.
Walking depth levels up the chain gives the target frame. */
Slot 511 in each frame stores the magic ID (registry index) of the
function that owns this frame. cell_rt_get/put_closure re-derive
the enclosing frame from the function's GC ref at call time, so
pointers stay valid even if GC moves frames. */
#define QBE_FRAME_OUTER_SLOT 511
static JSValue *derive_outer_fp(int magic);
JSValue cell_rt_get_closure(JSContext *ctx, void *fp, int64_t depth,
int64_t slot) {
JSValue *frame = (JSValue *)fp;
for (int64_t d = 0; d < depth; d++) {
void *outer = (void *)(uintptr_t)frame[QBE_FRAME_OUTER_SLOT];
if (!outer) return JS_NULL;
frame = (JSValue *)outer;
/* fp[511] stores the magic ID (registry index) of the function
that owns this frame. derive_outer_fp re-derives the enclosing
frame from the function's GC ref, so it's always current even
if GC moved the frame. */
int magic = (int)(int64_t)frame[QBE_FRAME_OUTER_SLOT];
frame = derive_outer_fp(magic);
if (!frame) return JS_NULL;
}
return frame[slot];
}
@@ -285,13 +332,74 @@ void cell_rt_put_closure(JSContext *ctx, void *fp, JSValue val, int64_t depth,
int64_t slot) {
JSValue *frame = (JSValue *)fp;
for (int64_t d = 0; d < depth; d++) {
void *outer = (void *)(uintptr_t)frame[QBE_FRAME_OUTER_SLOT];
if (!outer) return;
frame = (JSValue *)outer;
int magic = (int)(int64_t)frame[QBE_FRAME_OUTER_SLOT];
frame = derive_outer_fp(magic);
if (!frame) return;
}
frame[slot] = val;
}
/* --- GC-managed AOT frame stack ---
Each AOT function call pushes a GC ref so the GC can find and
update frame pointers when it moves objects. cell_rt_refresh_fp
re-derives the slot pointer after any GC-triggering call. */
#define MAX_AOT_DEPTH 256
static JSGCRef g_aot_gc_refs[MAX_AOT_DEPTH];
static int g_aot_depth = 0;
JSValue *cell_rt_enter_frame(JSContext *ctx, int64_t nr_slots) {
if (g_aot_depth >= MAX_AOT_DEPTH)
return NULL;
JSFrameRegister *frame = alloc_frame_register(ctx, (int)nr_slots);
if (!frame) return NULL;
JSGCRef *ref = &g_aot_gc_refs[g_aot_depth];
JS_AddGCRef(ctx, ref);
ref->val = JS_MKPTR(frame);
g_aot_depth++;
return (JSValue *)frame->slots;
}
JSValue *cell_rt_refresh_fp(JSContext *ctx) {
(void)ctx;
if (g_aot_depth <= 0) {
fprintf(stderr, "[BUG] cell_rt_refresh_fp: g_aot_depth=%d\n", g_aot_depth);
abort();
}
JSValue val = g_aot_gc_refs[g_aot_depth - 1].val;
JSFrameRegister *frame = (JSFrameRegister *)JS_VALUE_GET_PTR(val);
if (!frame) {
fprintf(stderr, "[BUG] cell_rt_refresh_fp: frame is NULL at depth=%d val=%lld\n",
g_aot_depth, (long long)val);
abort();
}
return (JSValue *)frame->slots;
}
/* Combined refresh + exception check in a single call.
Returns the refreshed fp, or NULL if there is a pending exception.
This avoids QBE register-allocation issues from two consecutive calls. */
JSValue *cell_rt_refresh_fp_checked(JSContext *ctx) {
if (JS_HasException(ctx))
return NULL;
if (g_aot_depth <= 0) {
fprintf(stderr, "[BUG] cell_rt_refresh_fp_checked: g_aot_depth=%d\n", g_aot_depth);
abort();
}
JSValue val = g_aot_gc_refs[g_aot_depth - 1].val;
JSFrameRegister *frame = (JSFrameRegister *)JS_VALUE_GET_PTR(val);
if (!frame) {
fprintf(stderr, "[BUG] cell_rt_refresh_fp_checked: frame is NULL\n");
abort();
}
return (JSValue *)frame->slots;
}
void cell_rt_leave_frame(JSContext *ctx) {
g_aot_depth--;
JS_DeleteGCRef(ctx, &g_aot_gc_refs[g_aot_depth]);
}
/* --- Function creation and calling --- */
typedef JSValue (*cell_compiled_fn)(JSContext *ctx, void *fp);
@@ -305,7 +413,8 @@ typedef JSValue (*cell_compiled_fn)(JSContext *ctx, void *fp);
static struct {
void *dl_handle;
int fn_idx;
void *outer_fp;
JSGCRef frame_ref; /* independent GC ref for enclosing frame */
int has_frame_ref;
} g_native_fn_registry[MAX_NATIVE_FN];
static int g_native_fn_count = 0;
@@ -313,6 +422,16 @@ static int g_native_fn_count = 0;
/* Set before executing a native module's cell_main */
static void *g_current_dl_handle = NULL;
/* Derive the outer frame's slots pointer from the closure's own GC ref.
Each closure keeps an independent GC ref so the enclosing frame
survives even after cell_rt_leave_frame pops the stack ref. */
static JSValue *derive_outer_fp(int magic) {
if (!g_native_fn_registry[magic].has_frame_ref) return NULL;
JSFrameRegister *frame = (JSFrameRegister *)JS_VALUE_GET_PTR(
g_native_fn_registry[magic].frame_ref.val);
return (JSValue *)frame->slots;
}
static JSValue cell_fn_trampoline(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv, int magic) {
if (magic < 0 || magic >= g_native_fn_count)
@@ -328,27 +447,44 @@ static JSValue cell_fn_trampoline(JSContext *ctx, JSValue this_val,
if (!fn)
return JS_ThrowTypeError(ctx, "native function %s not found in dylib", name);
/* Allocate frame: slot 0 = this, slots 1..argc = args */
JSValue frame[512];
memset(frame, 0, sizeof(frame));
frame[0] = this_val;
/* Allocate GC-managed frame: slot 0 = this, slots 1..argc = args */
JSValue *fp = cell_rt_enter_frame(ctx, 512);
if (!fp) return JS_EXCEPTION;
fp[0] = this_val;
for (int i = 0; i < argc && i < 510; i++)
frame[1 + i] = argv[i];
fp[1 + i] = argv[i];
/* Link to outer frame for closure access */
frame[QBE_FRAME_OUTER_SLOT] = (JSValue)(uintptr_t)g_native_fn_registry[magic].outer_fp;
/* Store the magic ID (registry index) so cell_rt_get/put_closure
can re-derive the enclosing frame from the GC ref at call time,
surviving GC moves */
fp[QBE_FRAME_OUTER_SLOT] = (JSValue)(int64_t)magic;
return fn(ctx, frame);
JSValue result = fn(ctx, fp);
cell_rt_leave_frame(ctx);
if (result == JS_EXCEPTION)
return JS_EXCEPTION;
return result;
}
JSValue cell_rt_make_function(JSContext *ctx, int64_t fn_idx, void *outer_fp) {
(void)outer_fp;
if (g_native_fn_count >= MAX_NATIVE_FN)
return JS_ThrowTypeError(ctx, "too many native functions (max %d)", MAX_NATIVE_FN);
int global_id = g_native_fn_count++;
g_native_fn_registry[global_id].dl_handle = g_current_dl_handle;
g_native_fn_registry[global_id].fn_idx = (int)fn_idx;
g_native_fn_registry[global_id].outer_fp = outer_fp;
/* Create independent GC ref so the enclosing frame survives
even after cell_rt_leave_frame pops the stack ref */
if (g_aot_depth > 0) {
JSGCRef *ref = &g_native_fn_registry[global_id].frame_ref;
JS_AddGCRef(ctx, ref);
ref->val = g_aot_gc_refs[g_aot_depth - 1].val;
g_native_fn_registry[global_id].has_frame_ref = 1;
} else {
g_native_fn_registry[global_id].has_frame_ref = 0;
}
return JS_NewCFunction2(ctx, (JSCFunction *)cell_fn_trampoline, "native_fn",
255, JS_CFUNC_generic_magic, global_id);
@@ -369,11 +505,13 @@ JSValue cell_rt_frame(JSContext *ctx, JSValue fn, int64_t nargs) {
}
void cell_rt_setarg(JSValue frame_val, int64_t idx, JSValue val) {
if (frame_val == JS_EXCEPTION || frame_val == JS_NULL) return;
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val);
fr->slots[idx] = val;
}
JSValue cell_rt_invoke(JSContext *ctx, JSValue frame_val) {
if (frame_val == JS_EXCEPTION) return JS_EXCEPTION;
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val);
int nr_slots = (int)objhdr_cap56(fr->header);
int c_argc = (nr_slots >= 2) ? nr_slots - 2 : 0;
@@ -474,18 +612,56 @@ int cell_rt_is_proxy(JSContext *ctx, JSValue v) {
return fn->length == 2;
}
/* --- Short-circuit and/or (non-allocating) --- */
JSValue cell_rt_and(JSContext *ctx, JSValue left, JSValue right) {
return JS_ToBool(ctx, left) ? right : left;
}
JSValue cell_rt_or(JSContext *ctx, JSValue left, JSValue right) {
return JS_ToBool(ctx, left) ? left : right;
}
/* --- Exception checking ---
After potentially-throwing runtime calls, QBE-generated code needs to
check for pending exceptions and branch to the disruption handler. */
void cell_rt_clear_exception(JSContext *ctx) {
if (JS_HasException(ctx))
JS_GetException(ctx);
}
/* --- Disruption --- */
void cell_rt_disrupt(JSContext *ctx) {
JS_ThrowTypeError(ctx, "type error in native code");
}
/* --- in: key in obj --- */
JSValue cell_rt_in(JSContext *ctx, JSValue key, JSValue obj) {
int has = JS_HasProperty(ctx, obj, key);
return JS_NewBool(ctx, has > 0);
}
/* --- regexp: create regex from pattern and flags --- */
JSValue cell_rt_regexp(JSContext *ctx, const char *pattern, const char *flags) {
JSValue argv[2];
argv[0] = JS_NewString(ctx, pattern);
argv[1] = JS_NewString(ctx, flags);
JSValue re = js_regexp_constructor(ctx, JS_NULL, 2, argv);
if (JS_IsException(re))
return JS_EXCEPTION;
return re;
}
/* --- Module entry point ---
Loads a native .cm module from a dylib handle.
Looks up cell_main, builds a heap-allocated frame, sets
g_current_dl_handle so closures register in the right module. */
JSValue cell_rt_native_module_load(JSContext *ctx, void *dl_handle) {
JSValue cell_rt_native_module_load(JSContext *ctx, void *dl_handle, JSValue env) {
cell_compiled_fn fn = (cell_compiled_fn)dlsym(dl_handle, "cell_main");
if (!fn)
return JS_ThrowTypeError(ctx, "cell_main not found in native module dylib");
@@ -495,22 +671,31 @@ JSValue cell_rt_native_module_load(JSContext *ctx, void *dl_handle) {
void *prev_handle = g_current_dl_handle;
g_current_dl_handle = dl_handle;
/* Heap-allocate so closures created in cell_main can reference
this frame after the module entry returns. */
JSValue *frame = calloc(512, sizeof(JSValue));
if (!frame) {
/* Make env available for cell_rt_get_intrinsic lookups */
cell_rt_set_native_env(ctx, env);
/* GC-managed frame for module execution */
JSValue *fp = cell_rt_enter_frame(ctx, 512);
if (!fp) {
g_current_dl_handle = prev_handle;
return JS_ThrowTypeError(ctx, "frame allocation failed");
}
JSValue result = fn(ctx, frame);
/* Clear any stale exception left by a previous interpreted run */
if (JS_HasException(ctx))
JS_GetException(ctx);
JSValue result = fn(ctx, fp);
cell_rt_leave_frame(ctx); /* safe — closures have independent GC refs */
g_current_dl_handle = prev_handle;
if (result == JS_EXCEPTION)
return JS_EXCEPTION;
return result;
}
/* Load a native module from a dylib handle, trying a named symbol first.
Falls back to cell_main if the named symbol is not found. */
JSValue cell_rt_native_module_load_named(JSContext *ctx, void *dl_handle, const char *sym_name) {
JSValue cell_rt_native_module_load_named(JSContext *ctx, void *dl_handle, const char *sym_name, JSValue env) {
cell_compiled_fn fn = NULL;
if (sym_name)
fn = (cell_compiled_fn)dlsym(dl_handle, sym_name);
@@ -522,19 +707,25 @@ JSValue cell_rt_native_module_load_named(JSContext *ctx, void *dl_handle, const
void *prev_handle = g_current_dl_handle;
g_current_dl_handle = dl_handle;
JSValue *frame = calloc(512, sizeof(JSValue));
if (!frame) {
/* Make env available for cell_rt_get_intrinsic lookups */
cell_rt_set_native_env(ctx, env);
JSValue *fp = cell_rt_enter_frame(ctx, 512);
if (!fp) {
g_current_dl_handle = prev_handle;
return JS_ThrowTypeError(ctx, "frame allocation failed");
}
JSValue result = fn(ctx, frame);
JSValue result = fn(ctx, fp);
cell_rt_leave_frame(ctx); /* safe — closures have independent GC refs */
g_current_dl_handle = prev_handle;
if (result == JS_EXCEPTION)
return JS_EXCEPTION;
return result;
}
/* Backward-compat: uses RTLD_DEFAULT (works when dylib opened with RTLD_GLOBAL) */
JSValue cell_rt_module_entry(JSContext *ctx) {
void *handle = dlopen(NULL, RTLD_LAZY);
return cell_rt_native_module_load(ctx, handle);
return cell_rt_native_module_load(ctx, handle, JS_NULL);
}

View File

@@ -495,8 +495,8 @@ typedef enum MachOpcode {
MACH_MOD, /* R(A) = R(B) % R(C) */
MACH_POW, /* R(A) = R(B) ** R(C) */
MACH_NEG, /* R(A) = -R(B) */
MACH_INC, /* R(A) = R(B) + 1 */
MACH_DEC, /* R(A) = R(B) - 1 */
MACH__DEAD_INC, /* reserved — was MACH_INC, never emitted */
MACH__DEAD_DEC, /* reserved — was MACH_DEC, never emitted */
/* Generic comparison (ABC) — used by legacy .mach */
MACH_EQ, /* R(A) = (R(B) == R(C)) */
@@ -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) */
@@ -671,8 +668,8 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
[MACH_MOD] = "mod",
[MACH_POW] = "pow",
[MACH_NEG] = "neg",
[MACH_INC] = "inc",
[MACH_DEC] = "dec",
[MACH__DEAD_INC] = "dead_inc",
[MACH__DEAD_DEC] = "dead_dec",
[MACH_EQ] = "eq",
[MACH_NEQ] = "neq",
[MACH_LT] = "lt",
@@ -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;
}
@@ -3046,7 +3076,7 @@ JSValue JS_ThrowError2 (JSContext *ctx, JSErrorEnum error_num, const char *fmt,
if (add_backtrace) {
print_backtrace (ctx, NULL, 0, 0);
}
return JS_Throw (ctx, JS_NULL);
return JS_Throw (ctx, JS_TRUE);
}
static JSValue JS_ThrowError (JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap) {