diff --git a/source/mach.c b/source/mach.c index be1d384d..ea57276e 100644 --- a/source/mach.c +++ b/source/mach.c @@ -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); } diff --git a/source/quickjs-internal.h b/source/quickjs-internal.h index 4ea2c645..2b6959de 100644 --- a/source/quickjs-internal.h +++ b/source/quickjs-internal.h @@ -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 { diff --git a/source/quickjs.h b/source/quickjs.h index 6df02771..191c3983 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -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. */ diff --git a/source/runtime.c b/source/runtime.c index cbb5b731..0b03f3cb 100644 --- a/source/runtime.c +++ b/source/runtime.c @@ -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;