This commit is contained in:
2026-02-21 16:23:44 -06:00
parent 517bd64275
commit bbeb757e40
2 changed files with 444 additions and 1099 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -17,10 +17,6 @@ JSValue qbe_new_float64(JSContext *ctx, double d) {
return __JS_NewFloat64(ctx, d);
}
JSValue qbe_new_string(JSContext *ctx, const char *str) {
return JS_NewString(ctx, str);
}
/* Comparison op IDs (must match qbe.cm float_cmp_op_id values) */
enum {
QBE_CMP_EQ = 0,
@@ -31,128 +27,89 @@ enum {
QBE_CMP_GE = 5
};
/* ============================================================
Float binary arithmetic
============================================================ */
static inline JSValue qbe_float_binop(JSContext *ctx, JSValue a, JSValue b,
double (*op)(double, double)) {
double da, db;
JS_ToFloat64(ctx, &da, a);
JS_ToFloat64(ctx, &db, b);
double r = op(da, db);
if (!isfinite(r))
return JS_NULL;
return JS_NewFloat64(ctx, r);
}
static double op_add(double a, double b) { return a + b; }
static double op_sub(double a, double b) { return a - b; }
static double op_mul(double a, double b) { return a * b; }
JSValue qbe_float_add(JSContext *ctx, JSValue a, JSValue b) {
return qbe_float_binop(ctx, a, b, op_add);
}
/* Generic add: concat if both text, float add if both numeric, else type error */
JSValue cell_rt_add(JSContext *ctx, JSValue a, JSValue b) {
if (JS_IsText(a) && JS_IsText(b))
return JS_ConcatString(ctx, a, b);
if (JS_IsNumber(a) && JS_IsNumber(b))
return qbe_float_binop(ctx, a, b, op_add);
JS_RaiseDisrupt(ctx, "cannot add incompatible types");
return JS_NULL;
}
JSValue qbe_float_sub(JSContext *ctx, JSValue a, JSValue b) {
return qbe_float_binop(ctx, a, b, op_sub);
}
JSValue qbe_float_mul(JSContext *ctx, JSValue a, JSValue b) {
return qbe_float_binop(ctx, a, b, op_mul);
}
JSValue qbe_float_div(JSContext *ctx, JSValue a, JSValue b) {
double da, db;
JS_ToFloat64(ctx, &da, a);
JS_ToFloat64(ctx, &db, b);
if (db == 0.0)
return JS_NULL;
double r = da / db;
if (!isfinite(r))
return JS_NULL;
return JS_NewFloat64(ctx, r);
}
JSValue qbe_float_mod(JSContext *ctx, JSValue a, JSValue b) {
double da, db;
JS_ToFloat64(ctx, &da, a);
JS_ToFloat64(ctx, &db, b);
if (db == 0.0)
return JS_NULL;
double r = fmod(da, db);
if (!isfinite(r))
return JS_NULL;
return JS_NewFloat64(ctx, r);
}
JSValue qbe_float_pow(JSContext *ctx, JSValue a, JSValue b) {
double da, db;
JS_ToFloat64(ctx, &da, a);
JS_ToFloat64(ctx, &db, b);
double r = pow(da, db);
if (!isfinite(r) && isfinite(da) && isfinite(db))
return JS_NULL;
return JS_NewFloat64(ctx, r);
}
/* ============================================================
Float unary ops
============================================================ */
JSValue qbe_float_neg(JSContext *ctx, JSValue v) {
double d;
JS_ToFloat64(ctx, &d, v);
return JS_NewFloat64(ctx, -d);
}
JSValue qbe_float_inc(JSContext *ctx, JSValue v) {
double d;
JS_ToFloat64(ctx, &d, v);
return JS_NewFloat64(ctx, d + 1);
}
JSValue qbe_float_dec(JSContext *ctx, JSValue v) {
double d;
JS_ToFloat64(ctx, &d, v);
return JS_NewFloat64(ctx, d - 1);
}
/* ============================================================
Float comparison — returns 0 or 1 for QBE branching
============================================================ */
int qbe_float_cmp(JSContext *ctx, int op, JSValue a, JSValue b) {
double da, db;
JS_ToFloat64(ctx, &da, a);
JS_ToFloat64(ctx, &db, b);
switch (op) {
case QBE_CMP_EQ: return da == db;
case QBE_CMP_NE: return da != db;
case QBE_CMP_LT: return da < db;
case QBE_CMP_LE: return da <= db;
case QBE_CMP_GT: return da > db;
case QBE_CMP_GE: return da >= db;
default: return 0;
/* Generic comparison helper matching MACH eq/ne/lt/le/gt/ge semantics. */
JSValue cell_rt_cmp(JSContext *ctx, int op, JSValue a, JSValue b) {
if (JS_VALUE_IS_BOTH_INT(a, b)) {
int32_t ia = JS_VALUE_GET_INT(a);
int32_t ib = JS_VALUE_GET_INT(b);
switch (op) {
case QBE_CMP_EQ: return JS_NewBool(ctx, ia == ib);
case QBE_CMP_NE: return JS_NewBool(ctx, ia != ib);
case QBE_CMP_LT: return JS_NewBool(ctx, ia < ib);
case QBE_CMP_LE: return JS_NewBool(ctx, ia <= ib);
case QBE_CMP_GT: return JS_NewBool(ctx, ia > ib);
case QBE_CMP_GE: return JS_NewBool(ctx, ia >= ib);
default: return JS_NewBool(ctx, 0);
}
}
}
/* ============================================================
Boolean conversion wrapper
============================================================ */
/* Fast path: identity after chasing forward pointers (matches MACH). */
{
JSValue ca = JS_IsPtr(a) ? JS_MKPTR(chase(a)) : a;
JSValue cb = JS_IsPtr(b) ? JS_MKPTR(chase(b)) : b;
if (ca == cb) {
if (op == QBE_CMP_EQ || op == QBE_CMP_LE || op == QBE_CMP_GE)
return JS_TRUE;
if (op == QBE_CMP_NE)
return JS_FALSE;
}
}
int qbe_to_bool(JSContext *ctx, JSValue v) {
return JS_ToBool(ctx, v);
if (JS_IsNumber(a) && JS_IsNumber(b)) {
double da, db;
JS_ToFloat64(ctx, &da, a);
JS_ToFloat64(ctx, &db, b);
switch (op) {
case QBE_CMP_EQ: return JS_NewBool(ctx, da == db);
case QBE_CMP_NE: return JS_NewBool(ctx, da != db);
case QBE_CMP_LT: return JS_NewBool(ctx, da < db);
case QBE_CMP_LE: return JS_NewBool(ctx, da <= db);
case QBE_CMP_GT: return JS_NewBool(ctx, da > db);
case QBE_CMP_GE: return JS_NewBool(ctx, da >= db);
default: return JS_NewBool(ctx, 0);
}
}
if (mist_is_text(a) && mist_is_text(b)) {
int cmp = js_string_compare_value(ctx, a, b, FALSE);
switch (op) {
case QBE_CMP_EQ: return JS_NewBool(ctx, cmp == 0);
case QBE_CMP_NE: return JS_NewBool(ctx, cmp != 0);
case QBE_CMP_LT: return JS_NewBool(ctx, cmp < 0);
case QBE_CMP_LE: return JS_NewBool(ctx, cmp <= 0);
case QBE_CMP_GT: return JS_NewBool(ctx, cmp > 0);
case QBE_CMP_GE: return JS_NewBool(ctx, cmp >= 0);
default: return JS_NewBool(ctx, 0);
}
}
if (JS_IsNull(a) && JS_IsNull(b)) {
if (op == QBE_CMP_EQ || op == QBE_CMP_LE || op == QBE_CMP_GE)
return JS_TRUE;
return JS_FALSE;
}
if (JS_IsBool(a) && JS_IsBool(b)) {
int ba = JS_VALUE_GET_BOOL(a);
int bb = JS_VALUE_GET_BOOL(b);
switch (op) {
case QBE_CMP_EQ: return JS_NewBool(ctx, ba == bb);
case QBE_CMP_NE: return JS_NewBool(ctx, ba != bb);
case QBE_CMP_LT: return JS_NewBool(ctx, ba < bb);
case QBE_CMP_LE: return JS_NewBool(ctx, ba <= bb);
case QBE_CMP_GT: return JS_NewBool(ctx, ba > bb);
case QBE_CMP_GE: return JS_NewBool(ctx, ba >= bb);
default: return JS_NewBool(ctx, 0);
}
}
if (op == QBE_CMP_EQ)
return JS_NewBool(ctx, 0);
if (op == QBE_CMP_NE)
return JS_NewBool(ctx, 1);
JS_RaiseDisrupt(ctx, "cannot compare: operands must be same type");
return JS_EXCEPTION;
}
/* ============================================================
@@ -190,29 +147,37 @@ JSValue qbe_bitwise_xor(JSContext *ctx, JSValue a, JSValue b) {
return JS_NewInt32(ctx, ia ^ ib);
}
/* ============================================================
Shift ops on floats (convert to int32, shift, re-tag)
============================================================ */
/* Concat helper matching MACH_CONCAT semantics exactly. */
JSValue cell_rt_concat(JSContext *ctx, JSValue left, JSValue right, int self_assign) {
if (self_assign) {
/* Self-assign pattern: slot[a] = slot[a] + slot[c]. */
if (JS_IsPtr(left)) {
JSText *s = (JSText *)chase(left);
int slen = (int)s->length;
int rlen = js_string_value_len(right);
int cap = (int)objhdr_cap56(s->hdr);
if (objhdr_type(s->hdr) == OBJ_TEXT
&& !(s->hdr & OBJHDR_S_MASK)
&& slen + rlen <= cap) {
/* In-place append, no allocation. */
for (int i = 0; i < rlen; i++)
string_put(s, slen + i, js_string_value_get(right, i));
s->length = slen + rlen;
return left;
}
}
/* Allocate with growth factor, leave unstoned. */
JSValue res = JS_ConcatStringGrow(ctx, left, right);
if (JS_IsException(res))
return JS_EXCEPTION;
return res;
}
JSValue qbe_shift_shl(JSContext *ctx, JSValue a, JSValue b) {
int32_t ia, ib;
JS_ToInt32(ctx, &ia, a);
JS_ToInt32(ctx, &ib, b);
return JS_NewInt32(ctx, ia << (ib & 31));
}
JSValue qbe_shift_sar(JSContext *ctx, JSValue a, JSValue b) {
int32_t ia, ib;
JS_ToInt32(ctx, &ia, a);
JS_ToInt32(ctx, &ib, b);
return JS_NewInt32(ctx, ia >> (ib & 31));
}
JSValue qbe_shift_shr(JSContext *ctx, JSValue a, JSValue b) {
int32_t ia, ib;
JS_ToInt32(ctx, &ia, a);
JS_ToInt32(ctx, &ib, b);
return JS_NewInt32(ctx, (uint32_t)ia >> (ib & 31));
/* Different target: exact-fit stoned path. */
JSValue res = JS_ConcatString(ctx, left, right);
if (JS_IsException(res))
return JS_EXCEPTION;
return res;
}
/* ============================================================
@@ -381,13 +346,6 @@ static JSValue cell_rt_load_field_key(JSContext *ctx, JSValue obj, JSValue key)
return JS_GetProperty(ctx, obj, key);
}
JSValue cell_rt_load_field(JSContext *ctx, JSValue obj, const char *name) {
JSValue key = aot_key_from_cstr(ctx, name);
if (JS_IsException(key))
return JS_EXCEPTION;
return cell_rt_load_field_key(ctx, obj, key);
}
JSValue cell_rt_load_field_lit(JSContext *ctx, JSValue obj, int64_t lit_idx) {
JSValue key = aot_lit_from_index(ctx, lit_idx);
if (JS_IsException(key))
@@ -395,29 +353,12 @@ JSValue cell_rt_load_field_lit(JSContext *ctx, JSValue obj, int64_t lit_idx) {
return cell_rt_load_field_key(ctx, obj, key);
}
/* Like cell_rt_load_field but without the function guard.
Used by load_dynamic when the key happens to be a static string. */
JSValue cell_rt_load_prop_str(JSContext *ctx, JSValue obj, const char *name) {
JSValue key = aot_key_from_cstr(ctx, name);
if (JS_IsException(key))
return JS_EXCEPTION;
return JS_GetProperty(ctx, obj, key);
}
static int cell_rt_store_field_key(JSContext *ctx, JSValue val, JSValue obj,
JSValue key) {
int ret = JS_SetProperty(ctx, obj, key, val);
return (ret < 0 || JS_HasException(ctx)) ? 0 : 1;
}
int cell_rt_store_field(JSContext *ctx, JSValue val, JSValue obj,
const char *name) {
JSValue key = aot_key_from_cstr(ctx, name);
if (JS_IsException(key))
return 0;
return cell_rt_store_field_key(ctx, val, obj, key);
}
int cell_rt_store_field_lit(JSContext *ctx, JSValue val, JSValue obj,
int64_t lit_idx) {
JSValue key = aot_lit_from_index(ctx, lit_idx);
@@ -455,25 +396,6 @@ int cell_rt_store_dynamic(JSContext *ctx, JSValue val, JSValue obj,
}
}
JSValue cell_rt_load_index(JSContext *ctx, JSValue arr, JSValue idx) {
if (JS_IsInt(idx))
return JS_GetPropertyNumber(ctx, arr, (uint32_t)JS_VALUE_GET_INT(idx));
return JS_GetProperty(ctx, arr, idx);
}
int cell_rt_store_index(JSContext *ctx, JSValue val, JSValue arr,
JSValue idx) {
int ret = 0;
JSValue nr = JS_NULL;
if (JS_IsInt(idx))
nr = JS_SetPropertyNumber(ctx, arr, (uint32_t)JS_VALUE_GET_INT(idx), val);
else
ret = JS_SetProperty(ctx, arr, idx, val);
if (JS_IsInt(idx))
return JS_IsException(nr) ? 0 : 1;
return (ret < 0 || JS_HasException(ctx)) ? 0 : 1;
}
/* --- Intrinsic/global lookup --- */
void cell_rt_set_native_env(JSContext *ctx, JSValue env) {
@@ -895,6 +817,12 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
if (!JS_IsFunction(callee_fn_val)) {
JS_RaiseDisrupt(ctx, "not a function");
{
int ret_info = JS_VALUE_GET_INT(frame->address);
int ret_slot = ret_info & 0xFFFF;
if (ret_slot != 0xFFFF)
fp[ret_slot] = JS_EXCEPTION;
}
/* Resume caller with exception pending */
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(exc_fn))->u.native.fn_ptr;
@@ -905,6 +833,10 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
JSFunction *callee_fn = JS_VALUE_GET_FUNCTION(callee_fn_val);
if (!cell_check_call_arity(ctx, callee_fn, callee_argc)) {
int ret_info = JS_VALUE_GET_INT(frame->address);
int ret_slot = ret_info & 0xFFFF;
if (ret_slot != 0xFFFF)
fp[ret_slot] = JS_EXCEPTION;
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(exc_fn))->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, exc_fn);
@@ -1191,56 +1123,10 @@ JSValue cell_rt_frame(JSContext *ctx, JSValue fn, int64_t nargs) {
return JS_MKPTR(new_frame);
}
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;
}
/* cell_rt_invoke — still used for non-dispatch-loop paths (e.g. old code) */
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 c_argc = JS_VALUE_GET_INT(fr->address);
if (c_argc < 0) c_argc = 0;
JSValue fn_val = fr->function;
if (!JS_IsFunction(fn_val)) {
JS_RaiseDisrupt(ctx, "not a function");
return JS_EXCEPTION;
}
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
JSValue result;
if (!cell_check_call_arity(ctx, fn, c_argc))
return JS_EXCEPTION;
if (fn->kind == JS_FUNC_KIND_C) {
result = js_call_c_function(ctx, fn_val, fr->slots[0], c_argc, &fr->slots[1]);
} else if (fn->kind == JS_FUNC_KIND_NATIVE) {
result = cell_native_dispatch(ctx, fn_val, fr->slots[0], c_argc, &fr->slots[1]);
} else {
JSValue args[c_argc > 0 ? c_argc : 1];
for (int i = 0; i < c_argc; i++)
args[i] = fr->slots[i + 1];
result = JS_CallInternal(ctx, fn_val, fr->slots[0], c_argc, args, 0);
}
if (JS_IsException(result))
return JS_EXCEPTION;
if (JS_HasException(ctx))
JS_GetException(ctx);
return result;
}
JSValue cell_rt_goframe(JSContext *ctx, JSValue fn, int64_t nargs) {
return cell_rt_frame(ctx, fn, nargs);
}
JSValue cell_rt_goinvoke(JSContext *ctx, JSValue frame_val) {
return cell_rt_invoke(ctx, frame_val);
}
/* --- Array push/pop --- */
JSValue cell_rt_push(JSContext *ctx, JSValue arr, JSValue val) {
@@ -1268,13 +1154,6 @@ static JSValue cell_rt_delete_key(JSContext *ctx, JSValue obj, JSValue key) {
return JS_NewBool(ctx, ret >= 0);
}
JSValue cell_rt_delete_str(JSContext *ctx, JSValue obj, const char *name) {
JSValue key = aot_key_from_cstr(ctx, name);
if (JS_IsException(key))
return JS_EXCEPTION;
return cell_rt_delete_key(ctx, obj, key);
}
JSValue cell_rt_delete_lit(JSContext *ctx, JSValue obj, int64_t lit_idx) {
JSValue key = aot_lit_from_index(ctx, lit_idx);
if (JS_IsException(key))
@@ -1282,49 +1161,6 @@ JSValue cell_rt_delete_lit(JSContext *ctx, JSValue obj, int64_t lit_idx) {
return cell_rt_delete_key(ctx, obj, key);
}
/* --- Typeof --- */
JSValue cell_rt_typeof(JSContext *ctx, JSValue val) {
if (JS_IsNull(val)) return JS_NewString(ctx, "null");
if (JS_IsInt(val) || JS_IsNumber(val)) return JS_NewString(ctx, "number");
if (JS_IsBool(val)) return JS_NewString(ctx, "logical");
if (JS_IsText(val)) return JS_NewString(ctx, "text");
if (JS_IsFunction(val)) return JS_NewString(ctx, "function");
if (JS_IsArray(val)) return JS_NewString(ctx, "array");
if (JS_IsRecord(val)) return JS_NewString(ctx, "object");
return JS_NewString(ctx, "unknown");
}
/* --- Text comparison stubs (called from QBE type-dispatch branches) --- */
JSValue cell_rt_lt_text(JSContext *ctx, JSValue a, JSValue b) {
const char *sa = JS_ToCString(ctx, a);
const char *sb = JS_ToCString(ctx, b);
int r = (sa && sb) ? strcmp(sa, sb) < 0 : 0;
return JS_NewBool(ctx, r);
}
JSValue cell_rt_gt_text(JSContext *ctx, JSValue a, JSValue b) {
const char *sa = JS_ToCString(ctx, a);
const char *sb = JS_ToCString(ctx, b);
int r = (sa && sb) ? strcmp(sa, sb) > 0 : 0;
return JS_NewBool(ctx, r);
}
JSValue cell_rt_le_text(JSContext *ctx, JSValue a, JSValue b) {
const char *sa = JS_ToCString(ctx, a);
const char *sb = JS_ToCString(ctx, b);
int r = (sa && sb) ? strcmp(sa, sb) <= 0 : 0;
return JS_NewBool(ctx, r);
}
JSValue cell_rt_ge_text(JSContext *ctx, JSValue a, JSValue b) {
const char *sa = JS_ToCString(ctx, a);
const char *sb = JS_ToCString(ctx, b);
int r = (sa && sb) ? strcmp(sa, sb) >= 0 : 0;
return JS_NewBool(ctx, r);
}
static int cell_rt_tol_eq_inner(JSContext *ctx, JSValue a, JSValue b,
JSValue tol) {
if (JS_IsNumber(a) && JS_IsNumber(b) && JS_IsNumber(tol)) {
@@ -1358,6 +1194,108 @@ JSValue cell_rt_ne_tol(JSContext *ctx, JSValue a, JSValue b, JSValue tol) {
return JS_NewBool(ctx, !cell_rt_tol_eq_inner(ctx, a, b, tol));
}
/* --- Extended type checks and text stoning --- */
void cell_rt_stone_text(JSValue v) {
stone_mutable_text(v);
}
int cell_rt_is_blob(JSValue v) {
return mist_is_blob(v);
}
int cell_rt_is_data(JSValue v) {
return mist_is_gc_object(v) && !mist_is_array(v)
&& !mist_is_function(v) && !mist_is_blob(v);
}
int cell_rt_is_fit(JSValue v) {
if (JS_IsInt(v))
return 1;
if (JS_IsShortFloat(v)) {
double d = JS_VALUE_GET_FLOAT64(v);
return isfinite(d) && trunc(d) == d && fabs(d) <= 9007199254740992.0;
}
return 0;
}
int cell_rt_is_char(JSValue v) {
if (MIST_IsImmediateASCII(v))
return MIST_GetImmediateASCIILen(v) == 1;
if (mist_is_text(v))
return js_string_value_len(v) == 1;
return 0;
}
int cell_rt_is_digit(JSValue v) {
if (MIST_IsImmediateASCII(v) && MIST_GetImmediateASCIILen(v) == 1) {
int ch = MIST_GetImmediateASCIIChar(v, 0);
return ch >= '0' && ch <= '9';
}
if (mist_is_text(v) && js_string_value_len(v) == 1) {
uint32_t ch = js_string_value_get(v, 0);
return ch >= '0' && ch <= '9';
}
return 0;
}
int cell_rt_is_letter(JSValue v) {
if (MIST_IsImmediateASCII(v) && MIST_GetImmediateASCIILen(v) == 1) {
int ch = MIST_GetImmediateASCIIChar(v, 0);
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
if (mist_is_text(v) && js_string_value_len(v) == 1) {
uint32_t ch = js_string_value_get(v, 0);
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
return 0;
}
int cell_rt_is_lower(JSValue v) {
if (MIST_IsImmediateASCII(v) && MIST_GetImmediateASCIILen(v) == 1) {
int ch = MIST_GetImmediateASCIIChar(v, 0);
return ch >= 'a' && ch <= 'z';
}
if (mist_is_text(v) && js_string_value_len(v) == 1) {
uint32_t ch = js_string_value_get(v, 0);
return ch >= 'a' && ch <= 'z';
}
return 0;
}
int cell_rt_is_upper(JSValue v) {
if (MIST_IsImmediateASCII(v) && MIST_GetImmediateASCIILen(v) == 1) {
int ch = MIST_GetImmediateASCIIChar(v, 0);
return ch >= 'A' && ch <= 'Z';
}
if (mist_is_text(v) && js_string_value_len(v) == 1) {
uint32_t ch = js_string_value_get(v, 0);
return ch >= 'A' && ch <= 'Z';
}
return 0;
}
int cell_rt_is_ws(JSValue v) {
if (MIST_IsImmediateASCII(v) && MIST_GetImmediateASCIILen(v) == 1) {
int ch = MIST_GetImmediateASCIIChar(v, 0);
return ch == ' ' || ch == '\t' || ch == '\n'
|| ch == '\r' || ch == '\f' || ch == '\v';
}
if (mist_is_text(v) && js_string_value_len(v) == 1) {
uint32_t ch = js_string_value_get(v, 0);
return ch == ' ' || ch == '\t' || ch == '\n'
|| ch == '\r' || ch == '\f' || ch == '\v';
}
return 0;
}
int cell_rt_is_actor(JSContext *ctx, JSValue v) {
int result = 0;
if (mist_is_record(v) && !JS_IsNull(ctx->actor_sym))
result = JS_HasPropertyKey(ctx, v, ctx->actor_sym) > 0;
return result;
}
/* --- Type check: is_proxy (function with arity 2) --- */
int cell_rt_is_proxy(JSContext *ctx, JSValue v) {
@@ -1367,14 +1305,6 @@ int cell_rt_is_proxy(JSContext *ctx, JSValue v) {
return fn->length == 2;
}
/* --- Identity check (chases forwarding pointers) --- */
JSValue cell_rt_is_identical(JSContext *ctx, JSValue a, JSValue b) {
if (JS_IsPtr(a)) a = JS_MKPTR(chase(a));
if (JS_IsPtr(b)) b = JS_MKPTR(chase(b));
return JS_NewBool(ctx, a == b);
}
/* --- Short-circuit and/or (non-allocating) --- */
JSValue cell_rt_and(JSContext *ctx, JSValue left, JSValue right) {