Merge branch 'fix_gc' into runtime_rework
This commit is contained in:
@@ -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); }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
281
source/quickjs.h
281
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. */
|
||||
|
||||
100
source/runtime.c
100
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;
|
||||
@@ -5063,7 +5055,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)) {
|
||||
@@ -5135,7 +5127,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;
|
||||
@@ -5323,7 +5315,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)) {
|
||||
@@ -6562,7 +6554,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;
|
||||
@@ -6596,7 +6588,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;
|
||||
@@ -6878,7 +6870,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;
|
||||
@@ -7016,7 +7008,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);
|
||||
@@ -7737,7 +7729,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;
|
||||
@@ -8397,7 +8389,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;
|
||||
@@ -8439,7 +8431,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;
|
||||
@@ -8761,7 +8753,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,
|
||||
@@ -9240,7 +9232,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);
|
||||
@@ -9288,7 +9280,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);
|
||||
@@ -9335,7 +9327,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);
|
||||
@@ -9415,7 +9407,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;
|
||||
@@ -9923,15 +9915,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;
|
||||
}
|
||||
@@ -9957,7 +9949,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); \
|
||||
@@ -10013,7 +10005,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);
|
||||
}
|
||||
@@ -10035,7 +10027,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;
|
||||
@@ -10079,7 +10071,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);
|
||||
}
|
||||
@@ -10094,7 +10086,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;
|
||||
@@ -10154,7 +10146,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)) {
|
||||
@@ -10248,7 +10240,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;
|
||||
@@ -10297,7 +10289,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;
|
||||
}
|
||||
@@ -10331,7 +10323,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);
|
||||
@@ -10349,7 +10341,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) {
|
||||
@@ -10720,7 +10712,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;
|
||||
|
||||
Reference in New Issue
Block a user