Merge branch 'fix_gc' into mcode_streamline

This commit is contained in:
2026-02-12 19:15:13 -06:00
4 changed files with 349 additions and 204 deletions

View File

@@ -547,7 +547,7 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
}
/* String concat for ADD */
if (op == MACH_ADD && JS_IsText(a) && JS_IsText(b))
if (op == MACH_ADD && mist_is_text(a) && mist_is_text(b))
return JS_ConcatString(ctx, a, b);
/* Comparison ops allow mixed types — return false for mismatches */
@@ -576,7 +576,7 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
}
}
/* String comparisons */
if (JS_IsText(a) && JS_IsText(b)) {
if (mist_is_text(a) && mist_is_text(b)) {
int cmp = js_string_compare_value(ctx, a, b, FALSE);
switch (op) {
case MACH_EQ: return JS_NewBool(ctx, cmp == 0);
@@ -696,7 +696,7 @@ void __asan_on_error(void) {
fprintf(stderr, "\n=== ASAN error: VM stack trace ===\n");
int is_first = 1;
while (frame) {
if (!JS_IsFunction(frame->function)) break;
if (!mist_is_function(frame->function)) break;
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
const char *func_name = NULL;
const char *file = NULL;
@@ -882,7 +882,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JS_ToFloat64(ctx, &dt, tol);
BOOL eq = fabs(da - db) <= dt;
frame->slots[a] = JS_NewBool(ctx, is_eq_op ? eq : !eq);
} else if (JS_IsText(left) && JS_IsText(right) && JS_VALUE_GET_TAG(tol) == JS_TAG_BOOL && JS_VALUE_GET_BOOL(tol)) {
} else if (mist_is_text(left) && mist_is_text(right) && JS_VALUE_GET_TAG(tol) == JS_TAG_BOOL && JS_VALUE_GET_BOOL(tol)) {
BOOL eq = js_string_compare_value_nocase(ctx, left, right) == 0;
frame->slots[a] = JS_NewBool(ctx, is_eq_op ? eq : !eq);
} else {
@@ -960,7 +960,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JSValue obj = frame->slots[b];
JSValue key = code->cpool[c];
/* Non-proxy functions (arity != 2) can't have properties read */
if (JS_IsFunction(obj)) {
if (mist_is_function(obj)) {
JSFunction *fn_chk = JS_VALUE_GET_FUNCTION(obj);
if (fn_chk->length != 2) {
JS_ThrowTypeError(ctx, "cannot read property of non-proxy function");
@@ -1009,10 +1009,10 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
if (JS_IsInt(idx)) {
JSValue r = JS_SetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(idx), val);
ret = JS_IsException(r) ? -1 : 0;
} else if (JS_IsArray(obj)) {
} else if (mist_is_array(obj)) {
JS_ThrowTypeError(ctx, "array index must be a number");
ret = -1;
} else if (JS_IsRecord(obj) && !JS_IsText(idx) && !JS_IsRecord(idx)) {
} else if (mist_is_record(obj) && !mist_is_text(idx) && !mist_is_record(idx)) {
JS_ThrowTypeError(ctx, "object key must be a string or object");
ret = -1;
} else {
@@ -1219,7 +1219,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
/* push R(B) onto array R(A) */
JSValue arr = frame->slots[a];
JSValue val = frame->slots[b];
if (!JS_IsArray(arr)) {
if (!mist_is_array(arr)) {
JS_ThrowTypeError(ctx, "cannot push to non-array");
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto disrupt;
@@ -1238,7 +1238,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
case MACH_POP: {
/* R(A) = pop last element from array R(B) */
JSValue arr = frame->slots[b];
if (!JS_IsArray(arr)) {
if (!mist_is_array(arr)) {
JS_ThrowTypeError(ctx, "cannot pop from non-array");
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto disrupt;
@@ -1482,7 +1482,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
frame->slots[a] = JS_NewBool(ctx, JS_IsNumber(frame->slots[b]));
break;
case MACH_IS_TEXT:
frame->slots[a] = JS_NewBool(ctx, JS_IsText(frame->slots[b]));
frame->slots[a] = JS_NewBool(ctx, mist_is_text(frame->slots[b]));
break;
case MACH_IS_BOOL:
frame->slots[a] = JS_NewBool(ctx, JS_IsBool(frame->slots[b]));
@@ -1491,49 +1491,42 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
frame->slots[a] = JS_NewBool(ctx, JS_IsNull(frame->slots[b]));
break;
case MACH_IS_ARRAY:
frame->slots[a] = JS_NewBool(ctx, JS_IsArray(frame->slots[b]));
frame->slots[a] = JS_NewBool(ctx, mist_is_array(frame->slots[b]));
break;
case MACH_IS_FUNC:
frame->slots[a] = JS_NewBool(ctx, JS_IsFunction(frame->slots[b]));
frame->slots[a] = JS_NewBool(ctx, mist_is_function(frame->slots[b]));
break;
case MACH_IS_RECORD:
frame->slots[a] = JS_NewBool(ctx, JS_IsRecord(frame->slots[b]));
frame->slots[a] = JS_NewBool(ctx, mist_is_record(frame->slots[b]));
break;
case MACH_IS_STONE:
frame->slots[a] = JS_NewBool(ctx, JS_IsStone(frame->slots[b]));
frame->slots[a] = JS_NewBool(ctx, mist_is_stone(frame->slots[b]));
break;
case MACH_LENGTH: {
JSValue res = JS_CellLength(ctx, frame->slots[b]);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
frame->slots[a] = res;
JSValue v = frame->slots[b];
if (mist_is_array(v)) {
JSArray *arr = JS_VALUE_GET_ARRAY(v);
frame->slots[a] = JS_NewInt32(ctx, (int32_t)arr->len);
} else if (MIST_IsImmediateASCII(v)) {
frame->slots[a] = JS_NewInt32(ctx, MIST_GetImmediateASCIILen(v));
} else {
/* fallback to C for text/blob/function (still a GC safepoint) */
JSValue res = JS_CellLength(ctx, v);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
frame->slots[a] = res;
}
break;
}
case MACH_IS_PROXY: {
JSValue v = frame->slots[b];
int is_proxy = 0;
if (JS_IsFunction(v)) {
if (mist_is_function(v)) {
JSFunction *fn = JS_VALUE_GET_FUNCTION(v);
is_proxy = (fn->length == 2);
}
frame->slots[a] = JS_NewBool(ctx, is_proxy);
break;
}
case MACH_TYPEOF: {
JSValue val = frame->slots[b];
const char *tname = "unknown";
if (JS_IsNull(val)) tname = "null";
else if (JS_IsInt(val) || JS_IsNumber(val)) tname = "number";
else if (JS_IsBool(val)) tname = "logical";
else if (JS_IsText(val)) tname = "text";
else if (JS_IsFunction(val)) tname = "function";
else if (JS_IsArray(val)) tname = "array";
else if (JS_IsRecord(val)) tname = "object";
JSValue res = JS_NewString(ctx, tname);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
frame->slots[a] = res;
break;
}
/* Logical */
case MACH_NOT: {
int bval = JS_ToBool(ctx, frame->slots[b]);
@@ -1580,7 +1573,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
case MACH_LOAD_FIELD: {
JSValue obj = frame->slots[b];
JSValue key = code->cpool[c];
if (JS_IsFunction(obj)) {
if (mist_is_function(obj)) {
JS_ThrowTypeError(ctx, "cannot read property of function");
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto disrupt;
@@ -1648,10 +1641,10 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
if (JS_IsInt(key)) {
JSValue r = JS_SetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(key), val);
ret = JS_IsException(r) ? -1 : 0;
} else if (JS_IsArray(obj)) {
} else if (mist_is_array(obj)) {
JS_ThrowTypeError(ctx, "array index must be a number");
ret = -1;
} else if (JS_IsBool(key) || JS_IsNull(key) || JS_IsArray(key) || JS_IsFunction(key)) {
} else if (JS_IsBool(key) || JS_IsNull(key) || mist_is_array(key) || mist_is_function(key)) {
JS_ThrowTypeError(ctx, "object key must be text");
ret = -1;
} else {
@@ -1676,7 +1669,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
case MACH_GOFRAME: {
/* A=frame_slot, B=func_reg, C=argc */
JSValue func_val = frame->slots[b];
if (!JS_IsFunction(func_val)) {
if (!mist_is_function(func_val)) {
JS_ThrowTypeError(ctx, "not a function");
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto disrupt;
@@ -1840,7 +1833,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JSFrameRegister *trace_frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
int first = 1;
while (trace_frame) {
if (!JS_IsFunction(trace_frame->function)) break;
if (!mist_is_function(trace_frame->function)) break;
JSFunction *trace_fn = JS_VALUE_GET_FUNCTION(trace_frame->function);
if (trace_fn->kind == JS_FUNC_KIND_REGISTER && trace_fn->u.reg.code) {
JSCodeRegister *tc = trace_fn->u.reg.code;
@@ -2449,7 +2442,6 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
else if (strcmp(op, "is_stone") == 0) { AB2(MACH_IS_STONE); }
else if (strcmp(op, "length") == 0) { AB2(MACH_LENGTH); }
else if (strcmp(op, "is_proxy") == 0) { AB2(MACH_IS_PROXY); }
else if (strcmp(op, "typeof") == 0) { AB2(MACH_TYPEOF); }
/* Logical */
else if (strcmp(op, "not") == 0) { AB2(MACH_NOT); }
else if (strcmp(op, "and") == 0) { ABC3(MACH_AND); }

View File

@@ -399,6 +399,72 @@ typedef struct { uint16_t line; uint16_t col; } MachLineEntry;
#define MACH_GET_sBx(i) ((int16_t)((i) >> 16))
#define MACH_GET_sJ(i) ((int32_t)((i) & 0xFFFFFF00) >> 8)
/* ============================================================
GC Safepoint Classification for the MACH VM Dispatch Loop
============================================================
Every opcode falls into one of three categories:
[P] Pure inline — never calls C, never allocates. No GC possible.
No frame re-derivation needed after execution.
[N] Non-allocating C call — calls a C function that is guaranteed
to never allocate (e.g. JS_ToBool, js_string_compare_value).
No frame re-derivation needed.
[G] GC safepoint — calls C that may allocate, triggering GC.
After the call, all heap pointers (including `frame`) MUST be
re-derived via: frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
The 18 C entry points that can allocate (GC safepoints):
1. JS_GetProperty — key interning for string keys >7 chars
2. JS_SetProperty — rec_resize when record grows
3. JS_GetPropertyNumber — text substring extraction
4. JS_SetPropertyNumber — array grow
5. JS_NewObject — allocates record
6. JS_NewArray / JS_NewArrayLen — allocates array
7. js_new_register_function — allocates function object (closure)
8. alloc_frame_register — allocates frame via js_mallocz
9. js_call_c_function — arbitrary C code
10. JS_CallInternal — arbitrary bytecode
11. JS_Call — arbitrary call
12. JS_ConcatString — allocates new string
13. JS_ArrayPush — array grow
14. JS_ArrayPop — reads, but frame refresh needed
15. JS_DeleteProperty — mutates record
16. JS_HasProperty — complex traversal
17. js_regexp_constructor — allocates regex
18. reg_vm_binop — polymorphic dispatch (legacy opcodes)
Opcode-level classification:
[P] LOADK, LOADI, LOADNULL, LOADTRUE, LOADFALSE, MOVE, NOP
[P] ADD_INT..MOD_INT, NEG_INT, ADD_FLOAT..MOD_FLOAT, NEG_FLOAT
[P] EQ_INT..GE_INT, EQ_FLOAT..GE_FLOAT, EQ_BOOL, NE_BOOL
[P] IS_IDENTICAL, IS_INT, IS_NUM, IS_TEXT, IS_BOOL, IS_NULL
[P] IS_ARRAY, IS_FUNC, IS_RECORD, IS_STONE, IS_PROXY
[P] NOT, AND, OR, BITNOT, BITAND, BITOR, BITXOR
[P] JMP, JMPTRUE, JMPFALSE, JMPNULL, JMPNOTNULL
[P] RETURN, RETNIL, SETARG, GETUP, SETUP, DISRUPT, THROW
[P] LENGTH (array + imm-ASCII fast path only; text/blob fallback is [G])
[N] EQ_TEXT..GE_TEXT (js_string_compare_value — no allocation)
[N] LNOT (JS_ToBool — no allocation)
[G] ADD..USHR, NEG, INC, DEC, EQ..GE (legacy: reg_vm_binop)
[G] EQ_TOL, NEQ_TOL (tolerance comparison, may fall back)
[G] CONCAT (JS_ConcatString)
[G] GETFIELD, SETFIELD, GETINDEX, SETINDEX (property access)
[G] LOAD_FIELD, STORE_FIELD, LOAD_INDEX, STORE_INDEX
[G] LOAD_DYNAMIC, STORE_DYNAMIC
[G] GETNAME, GETINTRINSIC, GETENV, SET_VAR
[G] NEWOBJECT, NEWRECORD, NEWARRAY (object/array creation)
[G] CLOSURE (js_new_register_function)
[G] FRAME, GOFRAME (alloc_frame_register)
[G] INVOKE, GOINVOKE (function calls)
[G] PUSH (JS_ArrayPush), POP (JS_ArrayPop)
[G] DELETE, DELETEINDEX (JS_DeleteProperty)
[G] HASPROP, IN (JS_HasProperty)
[G] REGEXP (js_regexp_constructor)
============================================================ */
typedef enum MachOpcode {
/* === Legacy opcodes (used by existing .mach files) === */
@@ -544,7 +610,6 @@ typedef enum MachOpcode {
MACH_IS_TEXT, /* R(A) = is_text(R(B)) */
MACH_IS_BOOL, /* R(A) = is_bool(R(B)) */
MACH_IS_NULL, /* R(A) = is_null(R(B)) */
MACH_TYPEOF, /* R(A) = typeof(R(B)) */
/* Logical (mcode-style) */
MACH_NOT, /* R(A) = !R(B) — boolean not (AB) */
@@ -697,7 +762,6 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
[MACH_IS_TEXT] = "is_text",
[MACH_IS_BOOL] = "is_bool",
[MACH_IS_NULL] = "is_null",
[MACH_TYPEOF] = "typeof",
[MACH_NOT] = "not",
[MACH_AND] = "and",
[MACH_OR] = "or",
@@ -799,6 +863,38 @@ static inline objhdr_t *chase(JSValue v) {
return oh;
}
/* Inline type checks — use these in the VM dispatch loop to avoid
function call overhead. The public API (JS_IsArray etc. in quickjs.h)
remains non-inline for external callers; those wrappers live in runtime.c. */
static inline JS_BOOL mist_is_gc_object(JSValue v) {
return JS_IsPtr(v);
}
static inline JS_BOOL mist_is_array(JSValue v) {
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_ARRAY;
}
static inline JS_BOOL mist_is_record(JSValue v) {
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_RECORD;
}
static inline JS_BOOL mist_is_function(JSValue v) {
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_FUNCTION;
}
static inline JS_BOOL mist_is_text(JSValue v) {
return MIST_IsImmediateASCII(v)
|| (mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_TEXT);
}
static inline JS_BOOL mist_is_blob(JSValue v) {
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_BLOB;
}
static inline JS_BOOL mist_is_stone(JSValue v) {
return !mist_is_gc_object(v) || objhdr_s(*chase(v));
}
/* Intrinsic array type - tagged as JS_TAG_PTR with mist_hdr type OBJ_ARRAY */
typedef struct JSArray {

View File

@@ -298,25 +298,34 @@ typedef JSValue JSCFunctionData (JSContext *ctx, JSValue this_val,
int argc, JSValue *argv, int magic,
JSValue *data);
JSValue JS_Stone (JSContext *ctx, JSValue this_val);
/* ============================================================
1. Runtime / Context Lifecycle
============================================================ */
JSRuntime *JS_NewRuntime (void);
/* info lifetime must exceed that of rt */
void JS_SetMemoryLimit (JSRuntime *rt, size_t limit);
/* use 0 to disable maximum stack size check */
void JS_SetMaxStackSize (JSContext *ctx, size_t stack_size);
void JS_FreeRuntime (JSRuntime *rt);
void JS_SetMemoryLimit (JSRuntime *rt, size_t limit);
JSContext *JS_NewContext (JSRuntime *rt);
JSContext *JS_NewContextWithHeapSize (JSRuntime *rt, size_t heap_size);
void JS_FreeContext (JSContext *s);
void *JS_GetContextOpaque (JSContext *ctx);
void JS_SetContextOpaque (JSContext *ctx, void *opaque);
JSRuntime *JS_GetRuntime (JSContext *ctx);
void JS_SetClassProto (JSContext *ctx, JSClassID class_id, JSValue obj);
JSValue JS_GetClassProto (JSContext *ctx, JSClassID class_id);
/* use 0 to disable maximum stack size check */
void JS_SetMaxStackSize (JSContext *ctx, size_t stack_size);
/* should be called when changing thread to update the stack top value
used to check stack overflow. */
void JS_UpdateStackTop (JSContext *ctx);
JSContext *JS_NewContextWithHeapSize (JSRuntime *rt, size_t heap_size);
/* return != 0 if the JS code needs to be interrupted */
typedef int JSInterruptHandler (JSRuntime *rt, void *opaque);
void JS_SetInterruptHandler (JSContext *ctx, JSInterruptHandler *cb,
void *opaque);
JS_BOOL JS_IsLiveObject (JSRuntime *rt, JSValue obj);
/* Class system */
typedef void JSClassFinalizer (JSRuntime *rt, JSValue val);
typedef JSValue JSClassCall (JSContext *ctx, JSValue func_obj,
JSValue this_val, int argc,
@@ -329,6 +338,7 @@ typedef struct JSClassDef {
} JSClassDef;
#define JS_INVALID_CLASS_ID 0
extern JSClassID js_class_id_alloc;
JSClassID JS_NewClassID (JSClassID *pclass_id);
/* Returns the class ID if `v` is an object, otherwise returns
* JS_INVALID_CLASS_ID. */
@@ -336,22 +346,12 @@ JSClassID JS_GetClassID (JSValue v);
int JS_NewClass (JSContext *ctx, JSClassID class_id,
const JSClassDef *class_def);
int JS_IsRegisteredClass (JSContext *ctx, JSClassID class_id);
extern JSClassID js_class_id_alloc;
void JS_SetClassProto (JSContext *ctx, JSClassID class_id, JSValue obj);
JSValue JS_GetClassProto (JSContext *ctx, JSClassID class_id);
/* ============================================================
Copying GC - No Reference Counting Needed
============================================================
With a copying GC, reference counting is not needed since all live
objects are discovered by tracing from roots. These macros make
existing DupValue/FreeValue calls into no-ops.
2. Value Creation and Type Checks
============================================================ */
#define JS_DupValue(ctx, v) (v)
#define JS_FreeValue(ctx, v) ((void)0)
#define JS_DupValueRT(rt, v) (v)
#define JS_FreeValueRT(rt, v) ((void)0)
/* value handling */
static inline JSValue
JS_NewBool (JSContext *ctx, JS_BOOL val) {
@@ -403,6 +403,7 @@ JS_NewFloat64 (JSContext *ctx, double d) {
return __JS_NewFloat64 (ctx, d);
}
/* Inline type checks (immediate tags) */
static inline JS_BOOL JS_IsNumber (JSValue v) {
int tag = JS_VALUE_GET_TAG (v);
return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64 (tag);
@@ -420,7 +421,7 @@ static inline JS_BOOL JS_IsException (JSValue v) {
return (JS_VALUE_GET_TAG (v) == JS_TAG_EXCEPTION);
}
/* Immediate String Helpers */
/* Immediate ASCII string helpers */
#define MIST_ASCII_MAX_LEN 7
static inline JS_BOOL
@@ -448,6 +449,8 @@ static inline JSValue MIST_TryNewImmediateASCII (const char *str, size_t len) {
return v;
}
/* Heap object type checks (non-inline — see mist_is_* in quickjs-internal.h
for inline versions used by the VM dispatch loop) */
JS_BOOL JS_IsArray(JSValue v);
JS_BOOL JS_IsRecord(JSValue v);
#define JS_IsObject JS_IsRecord
@@ -456,9 +459,90 @@ JS_BOOL JS_IsBlob(JSValue v);
JS_BOOL JS_IsText(JSValue v);
JS_BOOL JS_IsStone(JSValue v);
// Fundamental
/* ============================================================
3. GC References
============================================================
With a copying GC, reference counting is not needed since all live
objects are discovered by tracing from roots. These macros make
existing DupValue/FreeValue calls into no-ops.
============================================================ */
#define JS_DupValue(ctx, v) (v)
#define JS_FreeValue(ctx, v) ((void)0)
#define JS_DupValueRT(rt, v) (v)
#define JS_FreeValueRT(rt, v) ((void)0)
/* ============================================================
4. Property Access
============================================================ */
JSValue JS_GetProperty (JSContext *ctx, JSValue this_obj, JSValue prop);
int JS_SetProperty (JSContext *ctx, JSValue this_obj, JSValue prop, JSValue val);
JSValue JS_GetPropertyStr (JSContext *ctx, JSValue this_obj, const char *prop);
int JS_SetPropertyStr (JSContext *ctx, JSValue this_obj, const char *prop, JSValue val);
JSValue JS_GetPropertyNumber (JSContext *ctx, JSValue this_obj, int idx);
JSValue JS_SetPropertyNumber (JSContext *ctx, JSValue obj, int idx, JSValue val);
JSValue JS_GetPrototype (JSContext *ctx, JSValue val);
JSValue JS_GetOwnPropertyNames (JSContext *ctx, JSValue obj);
int JS_GetLength (JSContext *ctx, JSValue obj, int64_t *pres);
void JS_SetOpaque (JSValue obj, void *opaque);
void *JS_GetOpaque (JSValue obj, JSClassID class_id);
void *JS_GetOpaque2 (JSContext *ctx, JSValue obj, JSClassID class_id);
void *JS_GetAnyOpaque (JSValue obj, JSClassID *class_id);
/* ============================================================
5. Object / Array / String Creation
============================================================ */
JSValue JS_NewObjectProtoClass (JSContext *ctx, JSValue proto, JSClassID class_id);
JSValue JS_NewObjectClass (JSContext *ctx, int class_id);
JSValue JS_NewObjectProto (JSContext *ctx, JSValue proto);
JSValue JS_NewObject (JSContext *ctx);
JSValue JS_NewArray (JSContext *ctx);
JSValue JS_NewArrayLen (JSContext *ctx, uint32_t len);
JSValue JS_NewArrayFrom (JSContext *ctx, int count, JSValue *values);
int JS_ArrayPush (JSContext *ctx, JSValue *arr_ptr, JSValue val);
JSValue JS_ArrayPop (JSContext *ctx, JSValue obj);
JSValue JS_NewStringLen (JSContext *ctx, const char *str1, size_t len1);
static inline JSValue JS_NewString (JSContext *ctx, const char *str) {
return JS_NewStringLen (ctx, str, strlen (str));
}
/* ============================================================
6. Type Conversion
============================================================ */
int JS_ToBool (JSContext *ctx, JSValue val); /* return -1 for JS_EXCEPTION */
int JS_ToInt32 (JSContext *ctx, int32_t *pres, JSValue val);
static inline int JS_ToUint32 (JSContext *ctx, uint32_t *pres, JSValue val) {
return JS_ToInt32 (ctx, (int32_t *)pres, val);
}
int JS_ToInt64 (JSContext *ctx, int64_t *pres, JSValue val);
int JS_ToFloat64 (JSContext *ctx, double *pres, JSValue val);
JSValue JS_ToString (JSContext *ctx, JSValue val);
JSValue JS_ToPropertyKey (JSContext *ctx, JSValue val);
const char *JS_ToCStringLen2 (JSContext *ctx, size_t *plen, JSValue val1, JS_BOOL cesu8);
static inline const char * JS_ToCStringLen (JSContext *ctx, size_t *plen, JSValue val1) {
return JS_ToCStringLen2 (ctx, plen, val1, 0);
}
static inline const char * JS_ToCString (JSContext *ctx, JSValue val1) {
return JS_ToCStringLen2 (ctx, NULL, val1, 0);
}
void JS_FreeCString (JSContext *ctx, const char *ptr);
JS_BOOL JS_StrictEq (JSContext *ctx, JSValue op1, JSValue op2);
/* ============================================================
7. Error Handling
============================================================ */
JSValue JS_Throw (JSContext *ctx, JSValue obj);
JSValue JS_GetException (JSContext *ctx);
JS_BOOL JS_HasException (JSContext *ctx);
@@ -474,44 +558,28 @@ JSValue __js_printf_like (2, 3)
JS_ThrowInternalError (JSContext *ctx, const char *fmt, ...);
JSValue JS_ThrowOutOfMemory (JSContext *ctx);
// TODO: rename this to just "eq"
JS_BOOL JS_StrictEq (JSContext *ctx, JSValue op1, JSValue op2);
/* ============================================================
8. Function Creation and Invocation
============================================================ */
int JS_ToBool (JSContext *ctx, JSValue val); /* return -1 for JS_EXCEPTION */
int JS_ToInt32 (JSContext *ctx, int32_t *pres, JSValue val);
static inline int JS_ToUint32 (JSContext *ctx, uint32_t *pres, JSValue val) {
return JS_ToInt32 (ctx, (int32_t *)pres, val);
}
int JS_ToInt64 (JSContext *ctx, int64_t *pres, JSValue val);
int JS_ToFloat64 (JSContext *ctx, double *pres, JSValue val);
/* return an exception if 'val' is a Number */
JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv);
JSValue JS_Stone (JSContext *ctx, JSValue this_val);
JSValue JS_NewStringLen (JSContext *ctx, const char *str1, size_t len1);
static inline JSValue JS_NewString (JSContext *ctx, const char *str) {
return JS_NewStringLen (ctx, str, strlen (str));
}
JSValue JS_ToString (JSContext *ctx, JSValue val);
const char *JS_ToCStringLen2 (JSContext *ctx, size_t *plen, JSValue val1, JS_BOOL cesu8);
static inline const char * JS_ToCStringLen (JSContext *ctx, size_t *plen, JSValue val1) {
return JS_ToCStringLen2 (ctx, plen, val1, 0);
}
static inline const char * JS_ToCString (JSContext *ctx, JSValue val1) {
return JS_ToCStringLen2 (ctx, NULL, val1, 0);
}
void JS_FreeCString (JSContext *ctx, const char *ptr);
/* JSON */
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
JSValue JS_ParseJSON (JSContext *ctx, const char *buf, size_t buf_len,
const char *filename);
#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */
JSValue JS_ParseJSON2 (JSContext *ctx, const char *buf, size_t buf_len,
const char *filename, int flags);
JSValue JS_JSONStringify (JSContext *ctx, JSValue obj,
JSValue replacer, JSValue space0);
JSValue JS_NewObjectProtoClass (JSContext *ctx, JSValue proto, JSClassID class_id);
JSValue JS_NewObjectClass (JSContext *ctx, int class_id);
JSValue JS_NewObjectProto (JSContext *ctx, JSValue proto);
JSValue JS_NewObject (JSContext *ctx);
/* ============================================================
9. Intrinsic Wrappers (JS_Cell* / JS_Array*)
============================================================ */
JSValue JS_NewArray (JSContext *ctx);
JSValue JS_NewArrayLen (JSContext *ctx, uint32_t len);
int JS_ArrayPush (JSContext *ctx, JSValue *arr_ptr, JSValue val);
JSValue JS_ArrayPop (JSContext *ctx, JSValue obj);
/* Intrinsic array operations - signatures match internal functions */
/* Intrinsic array operations */
JSValue JS_Array (JSContext *ctx, JSValue arg0, JSValue arg1, JSValue arg2, JSValue arg3);
JSValue JS_ArrayFilter (JSContext *ctx, JSValue arr, JSValue fn);
JSValue JS_ArraySort (JSContext *ctx, JSValue arr, JSValue selector);
@@ -519,9 +587,7 @@ JSValue JS_ArrayFind (JSContext *ctx, JSValue arr, JSValue target_or_fn, JSValue
JSValue JS_ArrFor (JSContext *ctx, JSValue arr, JSValue fn, JSValue reverse, JSValue exit_val);
JSValue JS_ArrayReduce (JSContext *ctx, JSValue arr, JSValue fn, JSValue initial, JSValue reverse);
/* Cell intrinsic functions - C API wrappers */
/* Core functions */
/* Core cell functions */
JSValue JS_CellStone (JSContext *ctx, JSValue val);
JSValue JS_CellLength (JSContext *ctx, JSValue val);
JSValue JS_CellReverse (JSContext *ctx, JSValue val);
@@ -534,7 +600,7 @@ JSValue JS_CellModulo (JSContext *ctx, JSValue a, JSValue b);
JSValue JS_CellNeg (JSContext *ctx, JSValue val);
JSValue JS_CellNot (JSContext *ctx, JSValue val);
/* Text functions */
/* Text cell functions */
JSValue JS_CellText (JSContext *ctx, JSValue val);
JSValue JS_CellLower (JSContext *ctx, JSValue text);
JSValue JS_CellUpper (JSContext *ctx, JSValue text);
@@ -545,7 +611,7 @@ JSValue JS_CellSearch (JSContext *ctx, JSValue text, JSValue pattern, JSValue fr
JSValue JS_CellExtract (JSContext *ctx, JSValue text, JSValue from, JSValue to);
JSValue JS_CellCharacter (JSContext *ctx, JSValue codepoint);
/* Number functions */
/* Number cell functions */
JSValue JS_CellNumber (JSContext *ctx, JSValue val);
JSValue JS_CellAbs (JSContext *ctx, JSValue num);
JSValue JS_CellSign (JSContext *ctx, JSValue num);
@@ -559,56 +625,20 @@ JSValue JS_CellMin (JSContext *ctx, JSValue a, JSValue b);
JSValue JS_CellMax (JSContext *ctx, JSValue a, JSValue b);
JSValue JS_CellRemainder (JSContext *ctx, JSValue a, JSValue b);
/* Object functions */
/* Object cell functions */
JSValue JS_CellObject (JSContext *ctx, JSValue proto, JSValue props);
/* Format function */
/* Format */
JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue transformer);
/* Helper functions */
JSValue JS_NewArrayFrom (JSContext *ctx, int count, JSValue *values);
/* Output helpers */
void JS_PrintText (JSContext *ctx, JSValue val);
void JS_PrintTextLn (JSContext *ctx, JSValue val);
void JS_PrintFormatted (JSContext *ctx, const char *fmt, int count, JSValue *values);
JSValue JS_GetProperty (JSContext *ctx, JSValue this_obj, JSValue prop);
int JS_SetProperty (JSContext *ctx, JSValue this_obj, JSValue prop, JSValue val);
// For records
JSValue JS_GetPropertyStr (JSContext *ctx, JSValue this_obj, const char *prop);
int JS_SetPropertyStr (JSContext *ctx, JSValue this_obj, const char *prop, JSValue val);
// Must be an array
JSValue JS_GetPropertyNumber (JSContext *ctx, JSValue this_obj, int idx);
JSValue JS_SetPropertyNumber (JSContext *ctx, JSValue obj, int idx, JSValue val);
JSValue JS_GetPrototype (JSContext *ctx, JSValue val);
/* Get property keys as array of text */
JSValue JS_GetOwnPropertyNames (JSContext *ctx, JSValue obj);
JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv);
void JS_SetOpaque (JSValue obj, void *opaque);
void *JS_GetOpaque (JSValue obj, JSClassID class_id);
void *JS_GetOpaque2 (JSContext *ctx, JSValue obj, JSClassID class_id);
void *JS_GetAnyOpaque (JSValue obj, JSClassID *class_id);
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
JSValue JS_ParseJSON (JSContext *ctx, const char *buf, size_t buf_len,
const char *filename);
#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */
JSValue JS_ParseJSON2 (JSContext *ctx, const char *buf, size_t buf_len,
const char *filename, int flags);
JSValue JS_JSONStringify (JSContext *ctx, JSValue obj,
JSValue replacer, JSValue space0);
/* return != 0 if the JS code needs to be interrupted */
typedef int JSInterruptHandler (JSRuntime *rt, void *opaque);
void JS_SetInterruptHandler (JSContext *ctx, JSInterruptHandler *cb,
void *opaque);
/* C function definition */
/* ============================================================
10. C Function Definition
============================================================ */
typedef enum JSCFunctionEnum {
JS_CFUNC_generic,
JS_CFUNC_generic_magic,
@@ -868,7 +898,27 @@ typedef struct JSCFunctionListEntry {
int JS_SetPropertyFunctionList (JSContext *ctx, JSValue obj,
const JSCFunctionListEntry *tab, int len);
/* debug value output */
/* ============================================================
11. Debug / Dump Utilities
============================================================ */
typedef struct JSMemoryUsage {
int64_t malloc_size, malloc_limit, memory_used_size;
int64_t malloc_count;
int64_t memory_used_count;
int64_t str_count, str_size;
int64_t obj_count, obj_size;
int64_t prop_count, prop_size;
int64_t shape_count, shape_size;
int64_t js_func_count, js_func_size, js_func_code_size;
int64_t js_func_pc2line_count, js_func_pc2line_size;
int64_t c_func_count, array_count;
int64_t fast_array_count, fast_array_elements;
int64_t binary_object_count, binary_object_size;
} JSMemoryUsage;
void JS_ComputeMemoryUsage (JSRuntime *rt, JSMemoryUsage *s);
void JS_DumpMemoryUsage (FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
typedef struct {
JS_BOOL show_hidden : 8; /* only show enumerable properties */
@@ -913,7 +963,20 @@ typedef void (*js_hook) (JSContext *, int type, js_debug *dbg, void *user);
#define JS_HOOK_GC 8
void js_debug_sethook (JSContext *ctx, js_hook, int type, void *user);
/* Memory allocation functions (bump allocator) */
uint32_t js_debugger_stack_depth (JSContext *ctx);
JSValue js_debugger_backtrace_fns (JSContext *ctx);
JSValue js_debugger_closure_variables (JSContext *ctx, JSValue fn);
JSValue js_debugger_local_variables (JSContext *ctx, int stack_index);
void js_debugger_set_closure_variable (JSContext *js, JSValue fn,
JSValue var_name, JSValue val);
JSValue js_debugger_build_backtrace (JSContext *ctx);
JSValue js_debugger_fn_info (JSContext *ctx, JSValue fn);
JSValue js_debugger_fn_bytecode (JSContext *js, JSValue fn);
void *js_debugger_val_address (JSContext *js, JSValue val);
/* ============================================================
12. Memory Allocation
============================================================ */
void *js_malloc (JSContext *ctx, size_t size);
void *js_mallocz (JSContext *ctx, size_t size);
void *js_realloc (JSContext *ctx, void *ptr, size_t size);
@@ -925,9 +988,11 @@ void *js_malloc_rt (size_t size);
void *js_mallocz_rt (size_t size);
void js_free_rt (void *ptr);
struct cJSON;
/* ============================================================
13. Compilation and Bytecode
============================================================ */
/* Compiled bytecode (context-free, serializable) */
struct cJSON;
typedef struct MachCode MachCode;
/* Free a compiled MachCode tree. */

View File

@@ -36,36 +36,28 @@ static inline JS_BOOL JS_IsInteger (JSValue v) {
return d == (double)(int64_t)d;
}
static inline JS_BOOL JS_IsGCObject (JSValue v) {
return JS_IsPtr (v);
}
JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
/* === Function definitions from header region (non-inline) === */
/* === Public API wrappers (non-inline, for quickjs.h declarations) ===
These delegate to the static inline versions in quickjs-internal.h. */
JS_BOOL JS_IsStone(JSValue v) {
return !JS_IsGCObject(v) || objhdr_s(*chase(v));
JS_BOOL JS_IsStone(JSValue v) { return mist_is_stone(v); }
JS_BOOL JS_IsArray(JSValue v) { return mist_is_array(v); }
JS_BOOL JS_IsRecord(JSValue v) { return mist_is_record(v); }
JS_BOOL JS_IsFunction(JSValue v) { return mist_is_function(v); }
JS_BOOL JS_IsBlob(JSValue v) { return mist_is_blob(v); }
JS_BOOL JS_IsText(JSValue v) { return mist_is_text(v); }
JS_BOOL JS_IsCode(JSValue v) {
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_CODE;
}
JS_BOOL JS_IsArray(JSValue v) {
return JS_IsGCObject(v) && objhdr_type(*chase(v)) == OBJ_ARRAY;
JS_BOOL JS_IsForwarded(JSValue v) {
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_FORWARD;
}
JS_BOOL JS_IsRecord (JSValue v) {
return JS_IsGCObject(v) && objhdr_type(*chase(v)) == OBJ_RECORD;
}
JS_BOOL JS_IsFunction (JSValue v) {
return JS_IsGCObject(v) && objhdr_type(*chase(v)) == OBJ_FUNCTION;
}
JS_BOOL JS_IsBlob (JSValue v) {
return JS_IsGCObject(v) && objhdr_type(*chase(v)) == OBJ_BLOB;
}
JS_BOOL JS_IsText(JSValue v) {
return MIST_IsImmediateASCII(v) || (JS_IsGCObject(v) && objhdr_type(*chase(v)) == OBJ_TEXT);
JS_BOOL JS_IsFrame(JSValue v) {
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_FRAME;
}
uint64_t get_text_hash (JSText *text) {
@@ -4521,7 +4513,7 @@ static JSRegExp *js_get_regexp (JSContext *ctx, JSValue obj, BOOL throw_error) {
static int js_is_regexp (JSContext *ctx, JSValue obj) {
JSValue m;
if (!JS_IsGCObject (obj)) return FALSE;
if (!mist_is_gc_object (obj)) return FALSE;
m = JS_GetPropertyStr (ctx, obj, "Symbol.match");
if (JS_IsException (m)) return -1;
if (!JS_IsNull (m)) return JS_ToBool (ctx, m);
@@ -4664,7 +4656,7 @@ fail:
JSValue js_regexp_toString (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
JSValue pattern, flags;
if (!JS_IsGCObject (this_val)) return JS_ThrowTypeErrorNotAnObject (ctx);
if (!mist_is_gc_object (this_val)) return JS_ThrowTypeErrorNotAnObject (ctx);
JSText *b = pretext_init (ctx, 0);
if (!b) return JS_EXCEPTION;
@@ -5062,7 +5054,7 @@ static JSValue js_json_check (JSContext *ctx, JSONStringifyContext *jsc, JSValue
/* check for object.toJSON method */
/* ECMA specifies this is done only for Object and BigInt */
if (JS_IsGCObject (val)) {
if (mist_is_gc_object (val)) {
JSValue f = JS_GetProperty (ctx, val, JS_KEY_toJSON);
if (JS_IsException (f)) goto exception;
if (JS_IsFunction (f)) {
@@ -5134,7 +5126,7 @@ static int js_json_to_str (JSContext *ctx, JSONStringifyContext *jsc, JSValue ho
goto concat_value;
}
if (JS_IsGCObject (
if (mist_is_gc_object (
val_ref.val)) { /* includes arrays (OBJ_ARRAY) since they have JS_TAG_PTR */
v = js_array_includes (ctx, jsc->stack, 1, &val_ref.val);
if (JS_IsException (v)) goto exception;
@@ -5322,7 +5314,7 @@ JSValue JS_JSONStringify (JSContext *ctx, JSValue obj, JSValue replacer, JSValue
JSValue present;
v = JS_GetPropertyNumber (ctx, replacer, i);
if (JS_IsException (v)) goto exception;
if (JS_IsGCObject (v)) {
if (mist_is_gc_object (v)) {
/* Objects are not valid property list items */
continue;
} else if (JS_IsNumber (v)) {
@@ -6561,7 +6553,7 @@ static JSValue make_replacement (JSContext *ctx, int argc, JSValue *argv, int fo
}
static int JS_IsRegExp (JSContext *ctx, JSValue v) {
if (!JS_IsGCObject (v)) return 0;
if (!mist_is_gc_object (v)) return 0;
JSValue exec = JS_GetPropertyStr (ctx, v, "exec");
if (JS_IsException (exec)) return -1;
@@ -6595,7 +6587,7 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
{
if (JS_IsText (argv[1])) {
target_is_regex = 0;
} else if (JS_IsGCObject (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
} else if (mist_is_gc_object (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
target_is_regex = 1;
} else {
return JS_NULL;
@@ -6877,7 +6869,7 @@ static JSValue js_cell_text_search (JSContext *ctx, JSValue this_val, int argc,
int target_is_regex = 0;
if (JS_IsText (argv[1])) {
target_is_regex = 0;
} else if (JS_IsGCObject (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
} else if (mist_is_gc_object (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
target_is_regex = 1;
} else {
return JS_NULL;
@@ -7015,7 +7007,7 @@ static JSValue js_cell_text_extract (JSContext *ctx, JSValue this_val, int argc,
if (from > to) return JS_NULL;
/* RegExp path: convert new exec result record -> classic array */
if (JS_IsGCObject (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
if (mist_is_gc_object (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
/* Root rx, str, out across allocating calls */
JSGCRef rx_ref, str_ref, out_ref;
JS_PushGCRef (ctx, &rx_ref);
@@ -7736,7 +7728,7 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
return result;
}
if (JS_IsGCObject (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
if (mist_is_gc_object (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
/* Split by regex (manual "global" iteration; ignore g flag semantics) */
/* Root rx, result, arg across allocating calls */
JSGCRef rx_ref, res_ref, arg_ref;
@@ -8396,7 +8388,7 @@ static JSValue js_cell_object (JSContext *ctx, JSValue this_val, int argc, JSVal
JSValue arg = argv[0];
/* object(object) - shallow mutable copy */
if (JS_IsGCObject (arg) && !JS_IsArray (arg) && !JS_IsFunction (arg)) {
if (mist_is_gc_object (arg) && !JS_IsArray (arg) && !JS_IsFunction (arg)) {
if (argc < 2 || JS_IsNull (argv[1])) {
/* Shallow copy - root arg, result, keys across allocating calls */
JSGCRef arg_ref, res_ref, keys_ref;
@@ -8438,7 +8430,7 @@ static JSValue js_cell_object (JSContext *ctx, JSValue this_val, int argc, JSVal
#undef OBJ_COPY_CLEANUP
/* object(object, another_object) - combine */
if (JS_IsGCObject (argv[1]) && !JS_IsArray (argv[1])) {
if (mist_is_gc_object (argv[1]) && !JS_IsArray (argv[1])) {
JSGCRef arg_ref, arg2_ref, res_ref, keys_ref;
JS_PushGCRef (ctx, &arg_ref);
arg_ref.val = arg;
@@ -8760,7 +8752,7 @@ static JSValue js_blob_constructor (JSContext *ctx, JSValue this_val, int argc,
}
}
/* blob(blob, from, to) - copy from another blob */
else if (argc >= 1 && JS_IsGCObject (argv[0]) && !JS_IsText (argv[0])) {
else if (argc >= 1 && mist_is_gc_object (argv[0]) && !JS_IsText (argv[0])) {
blob *src = js_get_blob (ctx, argv[0]);
if (!src)
return JS_ThrowTypeError (ctx,
@@ -9239,7 +9231,7 @@ static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue
if (!mc)
return JS_ThrowSyntaxError (ctx, "mach_load: failed to deserialize bytecode");
JSValue env = (argc >= 2 && JS_IsGCObject (argv[1])) ? argv[1] : JS_NULL;
JSValue env = (argc >= 2 && mist_is_gc_object (argv[1])) ? argv[1] : JS_NULL;
JSGCRef env_ref;
JS_PushGCRef (ctx, &env_ref);
@@ -9287,7 +9279,7 @@ static JSValue js_mach_eval_mcode (JSContext *ctx, JSValue this_val, int argc, J
return JS_ThrowInternalError (ctx, "mach_eval_mcode: compilation failed");
}
JSValue env = (argc >= 3 && JS_IsGCObject (argv[2])) ? argv[2] : JS_NULL;
JSValue env = (argc >= 3 && mist_is_gc_object (argv[2])) ? argv[2] : JS_NULL;
JSGCRef env_ref;
JS_PushGCRef (ctx, &env_ref);
@@ -9334,7 +9326,7 @@ static JSValue js_mach_dump_mcode (JSContext *ctx, JSValue this_val, int argc, J
return JS_ThrowInternalError (ctx, "mach_dump_mcode: compilation failed");
}
JSValue env = (argc >= 3 && JS_IsGCObject (argv[2])) ? argv[2] : JS_NULL;
JSValue env = (argc >= 3 && mist_is_gc_object (argv[2])) ? argv[2] : JS_NULL;
JSGCRef env_ref;
JS_PushGCRef (ctx, &env_ref);
@@ -9414,7 +9406,7 @@ static JSValue js_cell_stone (JSContext *ctx, JSValue this_val, int argc, JSValu
return obj;
}
if (JS_IsGCObject (obj)) {
if (mist_is_gc_object (obj)) {
JSRecord *rec = JS_VALUE_GET_RECORD (obj);
obj_set_stone (rec);
return obj;
@@ -9922,15 +9914,15 @@ static JSValue js_cell_proto (JSContext *ctx, JSValue this_val, int argc, JSValu
return JS_ThrowTypeError (ctx, "arrays do not have prototypes");
}
if (!JS_IsGCObject (obj)) return JS_NULL;
if (!mist_is_gc_object (obj)) return JS_NULL;
JSValue proto = JS_GetPrototype (ctx, obj);
if (JS_IsException (proto)) return JS_NULL;
/* If prototype is Object.prototype, return null */
if (JS_IsGCObject (proto)) {
if (mist_is_gc_object (proto)) {
JSValue obj_proto = ctx->class_proto[JS_CLASS_OBJECT];
if (JS_IsGCObject (obj_proto)
if (mist_is_gc_object (obj_proto)
&& JS_VALUE_GET_OBJ (proto) == JS_VALUE_GET_OBJ (obj_proto)) {
return JS_NULL;
}
@@ -9956,7 +9948,7 @@ static JSValue js_cell_meme (JSContext *ctx, JSValue this_val, int argc, JSValue
/* Helper function to apply a single mixin */
#define APPLY_MIXIN(mix_val) \
do { \
if (!JS_IsGCObject (mix_val) || JS_IsNull (mix_val) || JS_IsArray (mix_val)) \
if (!mist_is_gc_object (mix_val) || JS_IsNull (mix_val) || JS_IsArray (mix_val)) \
break; \
JSGCRef _mix_ref; \
JS_PushGCRef (ctx, &_mix_ref); \
@@ -10012,7 +10004,7 @@ static JSValue js_cell_meme (JSContext *ctx, JSValue this_val, int argc, JSValue
APPLY_MIXIN (mix);
}
JS_PopGCRef (ctx, &mixins_ref);
} else if (JS_IsGCObject (mixins) && !JS_IsNull (mixins)) {
} else if (mist_is_gc_object (mixins) && !JS_IsNull (mixins)) {
/* Single mixin object */
APPLY_MIXIN (mixins);
}
@@ -10034,7 +10026,7 @@ static JSValue js_cell_splat (JSContext *ctx, JSValue this_val, int argc, JSValu
if (argc < 1) return JS_NULL;
JSValue obj = argv[0];
if (!JS_IsGCObject (obj) || JS_IsNull (obj)) return JS_NULL;
if (!mist_is_gc_object (obj) || JS_IsNull (obj)) return JS_NULL;
/* Root obj, result, current, keys across allocating calls */
JSGCRef obj_ref, res_ref, cur_ref, keys_ref;
@@ -10078,7 +10070,7 @@ static JSValue js_cell_splat (JSContext *ctx, JSValue this_val, int argc, JSValu
return JS_EXCEPTION;
}
int tag = JS_VALUE_GET_TAG (val);
if (JS_IsGCObject (val) || JS_IsNumber (val) || tag == JS_TAG_STRING
if (mist_is_gc_object (val) || JS_IsNumber (val) || tag == JS_TAG_STRING
|| tag == JS_TAG_STRING_IMM || tag == JS_TAG_BOOL) {
JS_SetProperty (ctx, res_ref.val, key, val);
}
@@ -10093,7 +10085,7 @@ static JSValue js_cell_splat (JSContext *ctx, JSValue this_val, int argc, JSValu
if (JS_IsFunction (to_data)) {
JSValue args[1] = { res_ref.val };
JSValue extra = JS_Call (ctx, to_data, obj_ref.val, 1, args);
if (!JS_IsException (extra) && JS_IsGCObject (extra)) {
if (!JS_IsException (extra) && mist_is_gc_object (extra)) {
keys_ref.val = JS_GetOwnPropertyNames (ctx, extra);
if (!JS_IsException (keys_ref.val)) {
uint32_t len;
@@ -10153,7 +10145,7 @@ static JSValue js_cell_length (JSContext *ctx, JSValue this_val, int argc, JSVal
}
/* Objects with length property */
if (JS_IsGCObject (val)) {
if (mist_is_gc_object (val)) {
JSValue len = JS_GetPropertyStr (ctx, val, "length");
if (!JS_IsException (len) && !JS_IsNull (len)) {
if (JS_IsFunction (len)) {
@@ -10247,7 +10239,7 @@ static JSValue js_cell_is_blob (JSContext *ctx, JSValue this_val, int argc, JSVa
static JSValue js_cell_is_data (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 1) return JS_FALSE;
JSValue val = argv[0];
if (!JS_IsGCObject (val)) return JS_FALSE;
if (!mist_is_gc_object (val)) return JS_FALSE;
if (JS_IsArray (val)) return JS_FALSE;
if (JS_IsFunction (val)) return JS_FALSE;
if (js_get_blob (ctx, val)) return JS_FALSE;
@@ -10296,7 +10288,7 @@ static JSValue js_cell_is_number (JSContext *ctx, JSValue this_val, int argc, JS
static JSValue js_cell_is_object (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 1) return JS_FALSE;
JSValue val = argv[0];
if (!JS_IsGCObject (val)) return JS_FALSE;
if (!mist_is_gc_object (val)) return JS_FALSE;
if (JS_IsArray (val)) return JS_FALSE;
return JS_TRUE;
}
@@ -10330,7 +10322,7 @@ static JSValue js_cell_is_proto (JSContext *ctx, JSValue this_val, int argc, JSV
JSValue val = argv[0];
JSValue master = argv[1];
if (!JS_IsGCObject (val) || JS_IsNull (master)) return JS_FALSE;
if (!mist_is_gc_object (val) || JS_IsNull (master)) return JS_FALSE;
/* Walk prototype chain */
JSValue proto = JS_GetPrototype (ctx, val);
@@ -10348,7 +10340,7 @@ static JSValue js_cell_is_proto (JSContext *ctx, JSValue this_val, int argc, JSV
}
}
/* Also check if proto == master directly */
if (JS_IsGCObject (master)) {
if (mist_is_gc_object (master)) {
JSRecord *p1 = JS_VALUE_GET_OBJ (proto);
JSRecord *p2 = JS_VALUE_GET_OBJ (master);
if (p1 == p2) {
@@ -10719,7 +10711,7 @@ static int nota_stack_has (NotaEncodeContext *enc, JSValueConst val) {
int len = nota_get_arr_len (ctx, enc->visitedStack_ref->val);
for (int i = 0; i < len; i++) {
JSValue elem = JS_GetPropertyNumber (ctx, enc->visitedStack_ref->val, i);
if (JS_IsGCObject (elem) && JS_IsGCObject (val)) {
if (mist_is_gc_object (elem) && mist_is_gc_object (val)) {
if (JS_StrictEq (ctx, elem, val)) {
JS_FreeValue (ctx, elem);
return 1;