Merge branch 'fix_gc' into runtime_rework

This commit is contained in:
2026-02-12 18:57:44 -06:00
4 changed files with 349 additions and 204 deletions

View File

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