From c5536697fff54d71ed3497d0e650b99ac16b1c7c Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 23 Feb 2026 16:54:19 -0600 Subject: [PATCH] merge cell --- Makefile | 4 +- archive/miniz.c | 3 +- debug/js.c | 1 + source/cell.c | 2 +- source/cell.h | 962 ++++++++++++++++++++++++++++++++- source/cell_internal.h | 6 + source/quickjs-atom.h | 265 --------- source/quickjs-internal.h | 163 +++++- source/quickjs.h | 1075 ------------------------------------- source/suite.c | 4 +- 10 files changed, 1111 insertions(+), 1374 deletions(-) delete mode 100644 source/quickjs-atom.h delete mode 100644 source/quickjs.h diff --git a/Makefile b/Makefile index 6a1bbdbe..790de8fd 100755 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ $(BUILD_DBG)/build.ninja: install: all $(CELL_SHOP) cp cell $(INSTALL_BIN)/cell cp libcell_runtime.dylib $(INSTALL_LIB)/ - cp source/cell.h source/quickjs.h source/wota.h $(INSTALL_INC)/ + cp source/cell.h $(INSTALL_INC)/ rm -rf $(CELL_SHOP)/packages/core ln -s $(CURDIR) $(CELL_SHOP)/packages/core @echo "Installed cell to $(INSTALL_BIN) and $(INSTALL_LIB)" @@ -32,7 +32,7 @@ install: all $(CELL_SHOP) install_debug: debug $(CELL_SHOP) cp cell $(INSTALL_BIN)/cell cp libcell_runtime.dylib $(INSTALL_LIB)/ - cp source/cell.h source/quickjs.h source/wota.h $(INSTALL_INC)/ + cp source/cell.h $(INSTALL_INC)/ rm -rf $(CELL_SHOP)/packages/core ln -s $(CURDIR) $(CELL_SHOP)/packages/core @echo "Installed cell (debug+asan) to $(INSTALL_BIN) and $(INSTALL_LIB)" diff --git a/archive/miniz.c b/archive/miniz.c index 1f5295df..d08500a1 100644 --- a/archive/miniz.c +++ b/archive/miniz.c @@ -1,6 +1,5 @@ -#include "quickjs.h" -#include "miniz.h" #include "cell.h" +#include "miniz.h" static JSClassID js_reader_class_id; static JSClassID js_writer_class_id; diff --git a/debug/js.c b/debug/js.c index f67bffb7..3acec8e5 100644 --- a/debug/js.c +++ b/debug/js.c @@ -1,4 +1,5 @@ #include "cell.h" +#include "quickjs-internal.h" JSC_CCALL(os_mem_limit, JS_SetMemoryLimit(JS_GetRuntime(js), js2number(js,argv[0]))) JSC_CCALL(os_max_stacksize, JS_SetMaxStackSize(js, js2number(js,argv[0]))) diff --git a/source/cell.c b/source/cell.c index a5283855..9c84cc85 100644 --- a/source/cell.c +++ b/source/cell.c @@ -8,8 +8,8 @@ #include "stb_ds.h" #include "cell.h" +#include "quickjs-internal.h" #include "cell_internal.h" -#include "cJSON.h" #define BOOTSTRAP_MCODE "boot/bootstrap.cm.mcode" #define ENGINE_SRC "internal/engine.cm" diff --git a/source/cell.h b/source/cell.h index cb76bfac..cf317c77 100644 --- a/source/cell.h +++ b/source/cell.h @@ -1,39 +1,883 @@ +/* + * cell.h — Consolidated public C API for ƿit modules + * + * QuickJS Javascript Engine + * Copyright (c) 2017-2021 Fabrice Bellard + * Copyright (c) 2017-2021 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ #ifndef CELL_H #define CELL_H -#include "quickjs.h" -#include "blob.h" +#include +#include +#include #ifdef __cplusplus extern "C" { #endif -// blob fns -JSValue js_core_blob_use(JSContext *js); -JSValue js_new_blob_alloc(JSContext *js, size_t bytes, void **out); -void js_blob_stone(JSValue blob, size_t actual_bytes); -JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t bytes); -void *js_get_blob_data(JSContext *js, size_t *size, JSValue v); // bytes -void *js_get_blob_data_bits(JSContext *js, size_t *bits, JSValue v); // bits -int js_is_blob(JSContext *js, JSValue v); +#if defined(__GNUC__) || defined(__clang__) +#define __js_printf_like(f, a) __attribute__ ((format (printf, f, a))) +#else +#define __js_printf_like(a, b) +#endif -double cell_random(); -uint64_t cell_random_fit(); +/* ============================================================ + JSValue — 64-bit tagged value + ============================================================ */ -int JS_ArrayLength(JSContext *js, JSValue a); - -int js2bool(JSContext *js, JSValue v); -JSValue bool2js(JSContext *js, int b); -double js2number(JSContext *js, JSValue v); -JSValue number2js(JSContext *js, double g); +typedef uint64_t JSValue; +typedef JSValue JSValueConst; -JSValue wota2value(JSContext *js, void *v); -void *value2wota(JSContext *js, JSValue v, JSValue replacer, size_t *bytes); +#define JS_BOOL int -JSValue nota2value(JSContext *js, void *nota); -void *value2nota(JSContext *js, JSValue v); +typedef struct JSRuntime JSRuntime; // the entire VM +typedef struct JSContext JSContext; // Each actor +typedef struct JSClass JSClass; +typedef uint32_t JSClassID; -JSValue js_core_json_use(JSContext *js); +/* Forward declaration - JSGCRef moved after JSValue definition */ +struct JSGCRef; + +/* ============================================================ + Mist Value Encoding (LSB-based type discrimination) + ============================================================ + + 64-bit builds: + LSB = 0 → 31-bit signed integer (value >> 1) + LSB = 001 → 61-bit pointer (aligned, clear low 3 bits) + LSB = 101 → Short float (61-bit, 3 fewer exponent bits than double) + LSB = 11 → Special tag (next 3 bits = subtype, 5 bits total) + + 32-bit builds: + LSB = 0 → 31-bit signed integer + LSB = 01 → 30-bit pointer + LSB = 11 → Special tag (next 3 bits = subtype) + + ============================================================ */ + +/* LSB-based tags */ +enum { + /* Primary tags (low bits) */ + JS_TAG_INT = 0, /* LSB = 0 */ + JS_TAG_PTR = 1, /* LSB = 01 */ + JS_TAG_SHORT_FLOAT = 5, /* LSB = 101 */ + JS_TAG_SPECIAL = 3, /* LSB = 11 */ + + /* Special subtypes (5 bits: xxxx11) */ + JS_TAG_BOOL = 0x03, /* 00011 */ + JS_TAG_NULL = 0x07, /* 00111 */ + JS_TAG_EXCEPTION = 0x0F, /* 01111 */ + JS_TAG_STRING_IMM = 0x0B, /* 01011 - immediate ASCII (up to 7 chars) */ +}; + +/* Compatibility tag aliases for external code */ +#define JS_TAG_STRING JS_TAG_STRING_IMM /* Alias: text/string type */ +#define JS_TAG_FLOAT64 JS_TAG_SHORT_FLOAT /* Alias: floats use short float encoding */ + +#define JS_EMPTY_TEXT ((JSValue)JS_TAG_STRING_IMM) + +/* ============================================================ + GC Rooting Structures + ============================================================ */ + +/* JSGCRef - for rooting values during GC */ +typedef struct JSGCRef { + JSValue val; + struct JSGCRef *prev; +} JSGCRef; + +/* JSLocalRef - GC updates C locals through pointers (OCaml-style) */ +typedef struct JSLocalRef { + JSValue *ptr; + struct JSLocalRef *prev; +} JSLocalRef; + +/* stack of JSGCRef */ +JSValue *JS_PushGCRef(JSContext *ctx, JSGCRef *ref); +JSValue JS_PopGCRef(JSContext *ctx, JSGCRef *ref); + +/* JS_FRAME/JS_ROOT/JS_LOCAL helpers (for use from cell.h macros) */ +JSGCRef *JS_GetGCFrame(JSContext *ctx); +JSLocalRef *JS_GetLocalFrame(JSContext *ctx); +void JS_PushLocalRef(JSContext *ctx, JSLocalRef *ref); +void JS_RestoreFrame(JSContext *ctx, JSGCRef *gc_frame, JSLocalRef *local_frame); + +#define JS_PUSH_VALUE(ctx, v) do { JS_PushGCRef(ctx, &v ## _ref); v ## _ref.val = v; } while (0) +#define JS_POP_VALUE(ctx, v) v = JS_PopGCRef(ctx, &v ## _ref) + +/* list of JSGCRef (they can be removed in any order, slower) */ +JSValue *JS_AddGCRef(JSContext *ctx, JSGCRef *ref); +void JS_DeleteGCRef(JSContext *ctx, JSGCRef *ref); + +/* ============================================================ + Value Extraction + ============================================================ */ + +/* Get primary tag (low 2-3 bits) */ +static inline int +JS_VALUE_GET_TAG (JSValue v) { + if ((v & 1) == 0) return JS_TAG_INT; + if ((v & 7) == JS_TAG_SHORT_FLOAT) return JS_TAG_SHORT_FLOAT; + if ((v & 3) == JS_TAG_PTR) return JS_TAG_PTR; + return (int)(v & 0x1F); /* special tag */ +} + +#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG (v) + +/* Extract 31-bit signed int (when LSB=0) */ +#define JS_VALUE_GET_INT(v) ((int32_t)((int64_t)(v) >> 1)) + +/* Extract bool value from special tag */ +#define JS_VALUE_GET_BOOL(v) ((int)((v) >> 5) & 1) + +/* Extract special tag payload (bits 5+) */ +#define JS_VALUE_GET_SPECIAL_PAYLOAD(v) ((int32_t)((v) >> 5)) + +/* ============================================================ + Value Creation + ============================================================ */ + +#define JS_MKVAL(tag, val) _JS_MkVal (tag, val) +static inline JSValue _JS_MkVal (int tag, int32_t val) { + if (tag == JS_TAG_INT) { return ((JSValue)(uint32_t)val << 1); } + /* Special tags encode payload in upper bits */ + return ((JSValue)tag) | ((JSValue)(uint32_t)val << 5); +} + +/* ============================================================ + Short Float (64-bit only) + Range: ~+-3.4e38 (8-bit exponent vs double's 11-bit) + Out of range → JS_NULL + ============================================================ */ + +static inline JSValue +__JS_NewFloat64 (JSContext *ctx, double d) { + union { + double d; + uint64_t u; + } u; + u.d = d; + + uint64_t sign = u.u >> 63; + int exp = (u.u >> 52) & 0x7FF; + uint64_t mantissa = u.u & ((1ULL << 52) - 1); + + /* Zero → short float zero (always +0, no -0) */ + if (exp == 0 && mantissa == 0) { return JS_TAG_SHORT_FLOAT; } + + /* NaN/Inf → NULL */ + if (exp == 0x7FF) { return JS_MKVAL (JS_TAG_NULL, 0); } + + /* Subnormals → zero */ + if (exp == 0) { return (sign << 63) | JS_TAG_SHORT_FLOAT; } + + /* Convert exponent: double bias 1023 → short bias 127 */ + int short_exp = exp - 1023 + 127; + if (short_exp < 1 || short_exp > 254) { + return JS_MKVAL (JS_TAG_NULL, 0); /* out of range */ + } + + /* Prefer integer if exact */ + if (d >= INT32_MIN && d <= INT32_MAX) { + int32_t i = (int32_t)d; + if ((double)i == d) { return JS_MKVAL (JS_TAG_INT, i); } + } + + /* Encode: [sign:1][exp:8][mantissa:52][tag:3] */ + return (sign << 63) | ((uint64_t)short_exp << 55) | (mantissa << 3) + | JS_TAG_SHORT_FLOAT; +} + +static inline double JS_VALUE_GET_FLOAT64 (JSValue v) { + if ((v & 7) != JS_TAG_SHORT_FLOAT) return 0.0; + + uint64_t sign = v >> 63; + uint64_t short_exp = (v >> 55) & 0xFF; + uint64_t mantissa = (v >> 3) & ((1ULL << 52) - 1); + + if (short_exp == 0) return 0.0; /* Always +0, no -0 */ + + uint64_t exp = short_exp - 127 + 1023; + union { + double d; + uint64_t u; + } u; + u.u = (sign << 63) | (exp << 52) | mantissa; + return u.d; +} + +#define JS_TAG_IS_FLOAT64(tag) ((tag) == JS_TAG_SHORT_FLOAT) +#define JS_NAN JS_MKVAL (JS_TAG_NULL, 0) + +/* ============================================================ + Type Checks + ============================================================ */ + +static inline JS_BOOL JS_IsInt (JSValue v) { return (v & 1) == 0; } +static inline JS_BOOL JS_IsPtr (JSValue v) { return (v & 7) == JS_TAG_PTR; } +static inline JS_BOOL JS_IsSpecial (JSValue v) { return (v & 3) == JS_TAG_SPECIAL; } + +static inline JS_BOOL +JS_IsShortFloat (JSValue v) { + return (v & 7) == JS_TAG_SHORT_FLOAT; +} + +#define JS_VALUE_IS_BOTH_INT(v1, v2) (((v1) & 1) == 0 && ((v2) & 1) == 0) +#define JS_VALUE_IS_BOTH_FLOAT(v1, v2) \ + (JS_IsShortFloat (v1) && JS_IsShortFloat (v2)) + +/* ============================================================ + Special Constants + ============================================================ */ + +#define JS_NULL ((JSValue)JS_TAG_NULL) +#define JS_FALSE ((JSValue)JS_TAG_BOOL) +#define JS_TRUE ((JSValue)(JS_TAG_BOOL | (1 << 5))) +#define JS_EXCEPTION ((JSValue)JS_TAG_EXCEPTION) + +/* Immediate ASCII string helpers */ +#define MIST_ASCII_MAX_LEN 7 + +static inline JS_BOOL +MIST_IsImmediateASCII (JSValue v) { + return (v & 0x1F) == JS_TAG_STRING_IMM; +} + +static inline int +MIST_GetImmediateASCIILen (JSValue v) { + return (int)((v >> 5) & 0x7); +} + +static inline int MIST_GetImmediateASCIIChar (JSValue v, int idx) { + return (int)((v >> (8 + idx * 8)) & 0xFF); +} + +static inline JSValue MIST_TryNewImmediateASCII (const char *str, size_t len) { + if (len > MIST_ASCII_MAX_LEN) return JS_NULL; + JSValue v = (JSValue)JS_TAG_STRING_IMM | ((JSValue)len << 5); + for (size_t i = 0; i < len; i++) { + uint8_t c = (uint8_t)str[i]; + if (c >= 0x80) return JS_NULL; + v |= (JSValue)c << (8 + i * 8); + } + 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 +JS_BOOL JS_IsFunction(JSValue v); +JS_BOOL JS_IsBlob(JSValue v); +JS_BOOL JS_IsText(JSValue v); +JS_BOOL JS_IsStone(JSValue v); + +/* ============================================================ + GC References — no-ops with copying GC + ============================================================ */ +#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) + +/* ============================================================ + C Function Typedefs + ============================================================ */ + +typedef JSValue JSCFunction (JSContext *ctx, JSValue this_val, int argc, + JSValue *argv); +typedef JSValue JSCFunctionMagic (JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic); +typedef JSValue JSCFunctionData (JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic, + JSValue *data); + +/* ============================================================ + Class System + ============================================================ */ + +typedef void JSClassFinalizer (JSRuntime *rt, JSValue val); +typedef JSValue JSClassCall (JSContext *ctx, JSValue func_obj, + JSValue this_val, int argc, + JSValue *argv, int flags); + +typedef struct JSClassDef { + const char *class_name; + JSClassFinalizer *finalizer; + JSClassCall *call; +} 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. */ +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); +void JS_SetClassProto (JSContext *ctx, JSClassID class_id, JSValue obj); +JSValue JS_GetClassProto (JSContext *ctx, JSClassID class_id); + +/* ============================================================ + Value Creation + ============================================================ */ + +static inline JSValue +JS_NewBool (JSContext *ctx, JS_BOOL val) { + return JS_MKVAL (JS_TAG_BOOL, (val != 0)); +} + +static inline JSValue +JS_NewInt32 (JSContext *ctx, int32_t val) { + return JS_MKVAL (JS_TAG_INT, val); +} + +static inline JSValue +JS_NewInt64 (JSContext *ctx, int64_t val) { + JSValue v; + if (val == (int32_t)val) { + v = JS_NewInt32 (ctx, val); + } else { + v = __JS_NewFloat64 (ctx, val); + } + return v; +} + +static inline JSValue +JS_NewUint32 (JSContext *ctx, uint32_t val) { + JSValue v; + if (val <= 0x7fffffff) { + v = JS_NewInt32 (ctx, val); + } else { + v = __JS_NewFloat64 (ctx, val); + } + return v; +} + +static inline JSValue +JS_NewFloat64 (JSContext *ctx, double d) { + int32_t val; + union { + double d; + uint64_t u; + } u, t; + if (d >= INT32_MIN && d <= INT32_MAX) { + u.d = d; + val = (int32_t)d; + t.d = val; + /* -0 cannot be represented as integer, so we compare the bit + representation */ + if (u.u == t.u) return JS_MKVAL (JS_TAG_INT, val); + } + 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); +} + +JSValue wota2value(JSContext *js, void *data); + +static inline JS_BOOL JS_IsBool (JSValue v) { + return JS_VALUE_GET_TAG (v) == JS_TAG_BOOL; +} + +static inline JS_BOOL JS_IsNull (JSValue v) { + return JS_VALUE_GET_TAG (v) == JS_TAG_NULL; +} + +static inline JS_BOOL JS_IsException (JSValue v) { + return (JS_VALUE_GET_TAG (v) == JS_TAG_EXCEPTION); +} + +/* ============================================================ + 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); + +/* ============================================================ + 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_NewObjectCap (JSContext *ctx, uint32_t n); + +JSValue JS_NewArray (JSContext *ctx); +JSValue JS_NewArrayLen (JSContext *ctx, uint32_t len); +JSValue JS_NewArrayCap (JSContext *ctx, uint32_t cap); +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)); +} + +/* ============================================================ + 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); + +/* ============================================================ + Error Handling + ============================================================ */ + +JSValue JS_GetException (JSContext *ctx); +JS_BOOL JS_HasException (JSContext *ctx); + +/* Set the disruption flag. No logging. */ +JSValue JS_Disrupt (JSContext *ctx); + +/* Log a message to a named channel. Routes through the ƿit log callback + if one has been set, otherwise falls back to fprintf(stderr). */ +void __js_printf_like (3, 4) + JS_Log (JSContext *ctx, const char *channel, const char *fmt, ...); + +/* Log to "error" channel + raise disruption. The common case. */ +JSValue __js_printf_like (2, 3) + JS_RaiseDisrupt (JSContext *ctx, const char *fmt, ...); + +/* Log to "memory" channel + disrupt. Skips JS callback (can't allocate). */ +JSValue JS_RaiseOOM (JSContext *ctx); +#define JS_ThrowOutOfMemory JS_RaiseOOM +#define JS_ThrowReferenceError JS_RaiseDisrupt +#define JS_ThrowTypeError JS_RaiseDisrupt +#define JS_ThrowInternalError JS_RaiseDisrupt +#define JS_ThrowRangeError JS_RaiseDisrupt + +/* ============================================================ + Function Invocation + ============================================================ */ + +JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv); +JSValue JS_Stone (JSContext *ctx, JSValue this_val); + +/* 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, + JS_BOOL compact_arrays); + +/* ============================================================ + Intrinsic Wrappers (JS_Cell* / JS_Array*) + ============================================================ */ + +/* 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); +JSValue JS_ArrayFind (JSContext *ctx, JSValue arr, JSValue target_or_fn, JSValue reverse, JSValue from); +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); + +/* Core cell functions */ +JSValue JS_CellStone (JSContext *ctx, JSValue val); +JSValue JS_CellLength (JSContext *ctx, JSValue val); +JSValue JS_CellReverse (JSContext *ctx, JSValue val); +JSValue JS_CellProto (JSContext *ctx, JSValue obj); +JSValue JS_CellSplat (JSContext *ctx, JSValue val); +JSValue JS_CellMeme (JSContext *ctx, JSValue obj, JSValue deep); +JSValue JS_CellApply (JSContext *ctx, JSValue fn, JSValue args); +JSValue JS_CellCall (JSContext *ctx, JSValue fn, JSValue this_val, JSValue args); +JSValue JS_CellModulo (JSContext *ctx, JSValue a, JSValue b); +JSValue JS_CellNeg (JSContext *ctx, JSValue val); +JSValue JS_CellNot (JSContext *ctx, JSValue val); + +/* Text cell functions */ +JSValue JS_CellText (JSContext *ctx, JSValue val); +JSValue JS_CellLower (JSContext *ctx, JSValue text); +JSValue JS_CellUpper (JSContext *ctx, JSValue text); +JSValue JS_CellTrim (JSContext *ctx, JSValue text, JSValue chars); +JSValue JS_CellCodepoint (JSContext *ctx, JSValue text, JSValue idx); +JSValue JS_CellReplace (JSContext *ctx, JSValue text, JSValue pattern, JSValue replacement); +JSValue JS_CellSearch (JSContext *ctx, JSValue text, JSValue pattern, JSValue from); +JSValue JS_CellExtract (JSContext *ctx, JSValue text, JSValue from, JSValue to); +JSValue JS_CellCharacter (JSContext *ctx, JSValue codepoint); + +/* Number cell functions */ +JSValue JS_CellNumber (JSContext *ctx, JSValue val); +JSValue JS_CellAbs (JSContext *ctx, JSValue num); +JSValue JS_CellSign (JSContext *ctx, JSValue num); +JSValue JS_CellFloor (JSContext *ctx, JSValue num); +JSValue JS_CellCeiling (JSContext *ctx, JSValue num); +JSValue JS_CellRound (JSContext *ctx, JSValue num); +JSValue JS_CellTrunc (JSContext *ctx, JSValue num); +JSValue JS_CellWhole (JSContext *ctx, JSValue num); +JSValue JS_CellFraction (JSContext *ctx, JSValue num); +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 cell functions */ +JSValue JS_CellObject (JSContext *ctx, JSValue proto, JSValue props); + +/* Format */ +JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue transformer); + +/* 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); + +/* ============================================================ + C Function Definition + ============================================================ */ +typedef enum JSCFunctionEnum { + JS_CFUNC_generic, + JS_CFUNC_generic_magic, + JS_CFUNC_f_f, + JS_CFUNC_f_f_f, + /* Fixed-arity fast paths - no argc/argv overhead */ + JS_CFUNC_0, /* JSValue f(ctx, this_val) */ + JS_CFUNC_1, /* JSValue f(ctx, this_val, arg0) */ + JS_CFUNC_2, /* JSValue f(ctx, this_val, arg0, arg1) */ + JS_CFUNC_3, /* JSValue f(ctx, this_val, arg0, arg1, arg2) */ + JS_CFUNC_4, + /* Pure functions (no this_val) - for global utility functions */ + JS_CFUNC_PURE, /* JSValue f(ctx, argc, argv) - generic pure */ + JS_CFUNC_PURE_0, /* JSValue f(ctx) */ + JS_CFUNC_PURE_1, /* JSValue f(ctx, arg0) */ + JS_CFUNC_PURE_2, /* JSValue f(ctx, arg0, arg1) */ + JS_CFUNC_PURE_3, /* JSValue f(ctx, arg0, arg1, arg2) */ + JS_CFUNC_PURE_4 /* JSValue f(ctx, arg0, arg1, arg2, arg3) */ +} JSCFunctionEnum; + +/* Fixed-arity C function types for fast paths */ +typedef JSValue JSCFunction0 (JSContext *ctx, JSValue this_val); +typedef JSValue JSCFunction1 (JSContext *ctx, JSValue this_val, + JSValue arg0); +typedef JSValue JSCFunction2 (JSContext *ctx, JSValue this_val, + JSValue arg0, JSValue arg1); +typedef JSValue JSCFunction3 (JSContext *ctx, JSValue this_val, + JSValue arg0, JSValue arg1, + JSValue arg2); +typedef JSValue JSCFunction4 (JSContext *ctx, JSValue this_val, + JSValue arg0, JSValue arg1, + JSValue arg2, JSValue arg3); + +/* Pure function types (no this_val) */ +typedef JSValue JSCFunctionPure (JSContext *ctx, int argc, JSValue *argv); +typedef JSValue JSCFunctionPure0 (JSContext *ctx); +typedef JSValue JSCFunctionPure1 (JSContext *ctx, JSValue arg0); +typedef JSValue JSCFunctionPure2 (JSContext *ctx, JSValue arg0, JSValue arg1); +typedef JSValue JSCFunctionPure3 (JSContext *ctx, JSValue arg0, JSValue arg1, + JSValue arg2); +typedef JSValue JSCFunctionPure4 (JSContext *ctx, JSValue arg0, JSValue arg1, + JSValue arg2, JSValue arg3); + +typedef union JSCFunctionType { + JSCFunction *generic; + JSValue (*generic_magic) (JSContext *ctx, JSValue this_val, int argc, + JSValue *argv, int magic); + double (*f_f) (double); + double (*f_f_f) (double, double); + /* Fixed-arity fast paths */ + JSCFunction0 *f0; + JSCFunction1 *f1; + JSCFunction2 *f2; + JSCFunction3 *f3; + JSCFunction4 *f4; + /* Pure function pointers */ + JSCFunctionPure *pure; + JSCFunctionPure0 *pure0; + JSCFunctionPure1 *pure1; + JSCFunctionPure2 *pure2; + JSCFunctionPure3 *pure3; + JSCFunctionPure4 *pure4; +} JSCFunctionType; + +JSValue JS_NewCFunction2 (JSContext *ctx, JSCFunction *func, const char *name, + int length, JSCFunctionEnum cproto, int magic); + +static inline JSValue JS_NewCFunction (JSContext *ctx, JSCFunction *func, const char *name, int length) { + return JS_NewCFunction2 (ctx, func, name, length, JS_CFUNC_generic, 0); +} + +static inline JSValue JS_NewCFunctionMagic (JSContext *ctx, JSCFunctionMagic *func, const char *name, int length, JSCFunctionEnum cproto, int magic) { + return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, length, cproto, + magic); +} + +/* Fixed-arity fast path constructors */ +static inline JSValue JS_NewCFuncFixed0 (JSContext *ctx, JSCFunction0 *func, const char *name) { + return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 0, JS_CFUNC_0, 0); +} + +static inline JSValue JS_NewCFuncFixed1 (JSContext *ctx, JSCFunction1 *func, const char *name) { + return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 1, JS_CFUNC_1, 0); +} + +static inline JSValue JS_NewCFuncFixed2 (JSContext *ctx, JSCFunction2 *func, const char *name) { + return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 2, JS_CFUNC_2, 0); +} + +static inline JSValue JS_NewCFuncFixed3 (JSContext *ctx, JSCFunction3 *func, const char *name) { + return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 3, JS_CFUNC_3, 0); +} + +static inline JSValue JS_NewCFuncFixed4 (JSContext *ctx, JSCFunction4 *func, const char *name) { + return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 4, JS_CFUNC_4, 0); +} + +/* C property definition */ + +typedef struct JSCFunctionListEntry { + const char *name; + uint8_t prop_flags; + uint8_t def_type; + int16_t magic; + union { + struct { + uint8_t length; /* XXX: should move outside union */ + uint8_t cproto; /* XXX: should move outside union */ + JSCFunctionType cfunc; + } func; + struct { + const char *name; + int base; + } alias; + struct { + const struct JSCFunctionListEntry *tab; + int len; + } prop_list; + const char *str; + int32_t i32; + int64_t i64; + double f64; + } u; +} JSCFunctionListEntry; + +#define JS_DEF_CFUNC 0 +#define JS_DEF_PROP_STRING 3 +#define JS_DEF_PROP_INT32 4 +#define JS_DEF_PROP_INT64 5 +#define JS_DEF_PROP_DOUBLE 6 +#define JS_DEF_PROP_UNDEFINED 7 +#define JS_DEF_OBJECT 8 +#define JS_DEF_ALIAS 9 + +/* Note: c++ does not like nested designators */ +#define JS_CFUNC_DEF(name, length, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { length, JS_CFUNC_generic, { .generic = func1 } } } \ + } +#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) \ + { \ + name, 0, JS_DEF_CFUNC, magic, .u = { \ + .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } \ + } \ + } +#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { length, JS_CFUNC_##cproto, { .cproto = func1 } } } \ + } +/* Fixed-arity fast path macros */ +#define JS_CFUNC0_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 0, JS_CFUNC_0, { .f0 = func1 } } } \ + } +#define JS_CFUNC1_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 1, JS_CFUNC_1, { .f1 = func1 } } } \ + } +#define JS_CFUNC2_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 2, JS_CFUNC_2, { .f2 = func1 } } } \ + } +#define JS_CFUNC3_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 3, JS_CFUNC_3, { .f3 = func1 } } } \ + } +/* Pure function (no this_val) macros */ +#define JS_CFUNC_PURE_DEF(name, length, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { length, JS_CFUNC_PURE, { .pure = func1 } } } \ + } +#define JS_CFUNC_PURE0_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 0, JS_CFUNC_PURE_0, { .pure0 = func1 } } } \ + } +#define JS_CFUNC_PURE1_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 1, JS_CFUNC_PURE_1, { .pure1 = func1 } } } \ + } +#define JS_CFUNC_PURE2_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 2, JS_CFUNC_PURE_2, { .pure2 = func1 } } } \ + } +#define JS_CFUNC_PURE3_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 3, JS_CFUNC_PURE_3, { .pure3 = func1 } } } \ + } +#define JS_CFUNC_PURE4_DEF(name, func1) \ + { \ + name, 0, JS_DEF_CFUNC, 0, \ + .u \ + = {.func = { 4, JS_CFUNC_PURE_4, { .pure4 = func1 } } } \ + } +#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) \ + { \ + name, 0, JS_DEF_CFUNC, magic, .u = { \ + .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } \ + } \ + } +#define JS_PROP_STRING_DEF(name, cstr, prop_flags) \ + { \ + name, prop_flags, JS_DEF_PROP_STRING, 0, .u = {.str = cstr } \ + } +#define JS_PROP_INT32_DEF(name, val, prop_flags) \ + { \ + name, prop_flags, JS_DEF_PROP_INT32, 0, .u = {.i32 = val } \ + } +#define JS_PROP_INT64_DEF(name, val, prop_flags) \ + { \ + name, prop_flags, JS_DEF_PROP_INT64, 0, .u = {.i64 = val } \ + } +#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) \ + { \ + name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = {.f64 = val } \ + } +#define JS_PROP_UNDEFINED_DEF(name, prop_flags) \ + { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } +#define JS_OBJECT_DEF(name, tab, len, prop_flags) \ + { \ + name, prop_flags, JS_DEF_OBJECT, 0, .u = {.prop_list = { tab, len } } \ + } +#define JS_ALIAS_DEF(name, from) \ + { \ + name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, \ + .u \ + = {.alias = { from, -1 } } \ + } +#define JS_ALIAS_BASE_DEF(name, from, base) \ + { \ + name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, \ + .u \ + = {.alias = { from, base } } \ + } + +int JS_SetPropertyFunctionList (JSContext *ctx, JSValue obj, + const JSCFunctionListEntry *tab, int len); + +/* ============================================================ + Debug Hooks (public) + ============================================================ */ + +typedef struct js_debug { + char name[64]; + char filename[96]; + int unique; + int line; + int param_n; + int closure_n; + int vararg; + const char *what; + const uint8_t *source; + int srclen; +} js_debug; + +typedef void (*js_hook) (JSContext *, int type, js_debug *dbg, void *user); +#define JS_HOOK_CALL 1 +#define JS_HOOK_RET 2 +#define JS_HOOK_CYCLE 4 +#define JS_HOOK_GC 8 +void js_debug_sethook (JSContext *ctx, js_hook, int type, void *user); + +/* ============================================================ + Cell Hooks + ============================================================ */ #define CELL_HOOK_ENTER 1 #define CELL_HOOK_EXIT 2 @@ -47,7 +891,53 @@ const char *cell_rt_name(struct cell_rt *rt); JSContext *cell_rt_context(struct cell_rt *rt); void js_debug_gethook(JSContext *ctx, js_hook *hook, int *type, void **user); -// Macros to help with creating scripts +/* ============================================================ + Off-heap Memory Allocation (not GC-managed) + ============================================================ */ + +void *js_malloc_rt (size_t size); +void *js_mallocz_rt (size_t size); +void js_free_rt (void *ptr); + +/* ============================================================ + Random Number Generation + ============================================================ */ + +double cell_random(); +uint64_t cell_random_fit(); + +/* ============================================================ + Blob API + ============================================================ */ + +JSValue js_new_blob_alloc(JSContext *js, size_t bytes, void **out); +void js_blob_stone(JSValue blob, size_t actual_bytes); +JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t bytes); +void *js_get_blob_data(JSContext *js, size_t *size, JSValue v); // bytes +void *js_get_blob_data_bits(JSContext *js, size_t *bits, JSValue v); // bits +int js_is_blob(JSContext *js, JSValue v); + +#include "blob.h" + +/* ============================================================ + Convenience Functions + ============================================================ */ + +int JS_ArrayLength(JSContext *js, JSValue a); + +int js2bool(JSContext *js, JSValue v); +JSValue bool2js(JSContext *js, int b); +double js2number(JSContext *js, JSValue v); +JSValue number2js(JSContext *js, double g); + +/* ============================================================ + Helper Macros + ============================================================ */ + +#ifndef countof +#define countof(x) (sizeof(x)/sizeof((x)[0])) +#endif + #define MIST_CFUNC_DEF(name, length, func1, props) { name, props, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } #define MIST_FUNC_DEF(TYPE, FN, LEN) MIST_CFUNC_DEF(#FN, LEN, js_##TYPE##_##FN, 0) @@ -82,6 +972,10 @@ void js_debug_gethook(JSContext *ctx, js_hook *hook, int *type, void **user); JS_FreeCString(js,str); \ ) \ +/* ============================================================ + Class Definition Macros + ============================================================ */ + #define QJSCLASS(TYPE, ...)\ JSClassID js_##TYPE##_id;\ static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\ @@ -159,7 +1053,9 @@ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \ TYPE##_ctor; \ }) -#define countof(x) (sizeof(x)/sizeof((x)[0])) +/* ============================================================ + GC Safety Macros + ============================================================ */ /* GC safety macros for C functions that allocate multiple heap objects. Any allocation call (JS_NewObject, JS_SetPropertyStr, etc.) can trigger GC. @@ -198,6 +1094,10 @@ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \ return JS_EXCEPTION; \ } while (0) +/* ============================================================ + Property Extraction Macros + ============================================================ */ + // Safe integer property extraction (null → 0) #define JS_GETINT(JS, TARGET, VALUE, PROP) { \ JSValue __##PROP##__v = JS_GetPropertyStr(JS, VALUE, #PROP); \ @@ -215,6 +1115,10 @@ JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#ATOM); \ TARGET = js2##TYPE(JS, __##PROP##__v); \ JS_FreeValue(JS,__##PROP##__v); }\ +/* ============================================================ + Enum Mapping System + ============================================================ */ + // X-macro enum definition system for string<->enum conversion #define ENUM_MAPPING_TABLE(ENUM) \ static const struct { int value; const char *name; } ENUM##_mapping[] @@ -239,6 +1143,10 @@ JSValue NAME##2js(JSContext *js, int enumval) { \ return JS_NULL; \ } +/* ============================================================ + Module Init Macros + ============================================================ */ + #define CELL_USE_INIT(c) \ JSValue CELL_USE_NAME(JSContext *js) { do { c ; } while(0); } @@ -252,9 +1160,11 @@ JSValue CELL_USE_NAME(JSContext *js) { \ #define CELL_PROGRAM_INIT(c) \ JSValue CELL_USE_NAME(JSContext *js) { do { c ; } while(0); } +#undef js_unlikely +#undef inline #ifdef __cplusplus } #endif -#endif +#endif /* CELL_H */ diff --git a/source/cell_internal.h b/source/cell_internal.h index 533a9630..54011057 100644 --- a/source/cell_internal.h +++ b/source/cell_internal.h @@ -2,6 +2,12 @@ #include #include +/* Internal runtime accessors — not in public cell.h API */ +void *JS_GetContextOpaque (JSContext *ctx); +void JS_SetContextOpaque (JSContext *ctx, void *opaque); +void JS_SetPauseFlag(JSContext *ctx, int value); +JSValue JS_GetStack (JSContext *ctx); + /* Letter type for unified message queue */ typedef enum { LETTER_BLOB, /* Blob message */ diff --git a/source/quickjs-atom.h b/source/quickjs-atom.h deleted file mode 100644 index 9e845d47..00000000 --- a/source/quickjs-atom.h +++ /dev/null @@ -1,265 +0,0 @@ -/* - * QuickJS atom definitions - * - * Copyright (c) 2017-2018 Fabrice Bellard - * Copyright (c) 2017-2018 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifdef DEF - -/* Note: first atoms are considered as keywords in the parser */ -DEF(null, "null") /* must be first */ -DEF(false, "false") -DEF(true, "true") -DEF(if, "if") -DEF(else, "else") -DEF(return, "return") -DEF(go, "go") -DEF(var, "var") -DEF(def, "def") -DEF(this, "this") -DEF(delete, "delete") -DEF(void, "void") -DEF(new, "new") -DEF(in, "in") -DEF(do, "do") -DEF(while, "while") -DEF(for, "for") -DEF(break, "break") -DEF(continue, "continue") -DEF(switch, "switch") -DEF(case, "case") -DEF(default, "default") -DEF(throw, "throw") -DEF(try, "try") -DEF(catch, "catch") -DEF(finally, "finally") -DEF(function, "function") -DEF(debugger, "debugger") -DEF(with, "with") -/* FutureReservedWord */ -DEF(class, "class") -DEF(const, "const") -DEF(enum, "enum") -DEF(export, "export") -DEF(extends, "extends") -DEF(import, "import") -DEF(super, "super") -/* FutureReservedWords when parsing strict mode code */ -DEF(implements, "implements") -DEF(interface, "interface") -DEF(let, "let") -DEF(private, "private") -DEF(protected, "protected") -DEF(public, "public") -DEF(static, "static") -DEF(yield, "yield") -DEF(await, "await") - -/* empty string */ -DEF(empty_string, "") -/* identifiers */ -DEF(length, "length") -DEF(fileName, "fileName") -DEF(lineNumber, "lineNumber") -DEF(columnNumber, "columnNumber") -DEF(message, "message") -DEF(cause, "cause") -DEF(errors, "errors") -DEF(stack, "stack") -DEF(name, "name") -DEF(toString, "toString") -DEF(toLocaleString, "toLocaleString") -DEF(valueOf, "valueOf") -DEF(eval, "eval") -DEF(prototype, "prototype") -DEF(constructor, "constructor") -DEF(configurable, "configurable") -DEF(writable, "writable") -DEF(enumerable, "enumerable") -DEF(value, "value") -DEF(get, "get") -DEF(set, "set") -DEF(of, "of") -DEF(__proto__, "__proto__") -DEF(undefined, "undefined") -DEF(number, "number") -DEF(boolean, "boolean") -DEF(string, "string") -DEF(object, "object") -DEF(symbol, "symbol") -DEF(integer, "integer") -DEF(unknown, "unknown") -DEF(callee, "callee") -DEF(caller, "caller") -DEF(_eval_, "") -DEF(_ret_, "") -DEF(_var_, "") -DEF(_arg_var_, "") -DEF(_with_, "") -DEF(lastIndex, "lastIndex") -DEF(target, "target") -DEF(index, "index") -DEF(input, "input") -DEF(defineProperties, "defineProperties") -DEF(apply, "apply") -DEF(join, "join") -DEF(concat, "concat") -DEF(split, "split") -DEF(construct, "construct") -DEF(getPrototypeOf, "getPrototypeOf") -DEF(setPrototypeOf, "setPrototypeOf") -DEF(isExtensible, "isExtensible") -DEF(preventExtensions, "preventExtensions") -DEF(has, "has") -DEF(deleteProperty, "deleteProperty") -DEF(defineProperty, "defineProperty") -DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") -DEF(ownKeys, "ownKeys") -DEF(add, "add") -DEF(done, "done") -DEF(next, "next") -DEF(values, "values") -DEF(source, "source") -DEF(flags, "flags") -DEF(global, "global") -DEF(unicode, "unicode") -DEF(raw, "raw") -DEF(new_target, "new.target") -DEF(this_active_func, "this.active_func") -DEF(home_object, "") -DEF(computed_field, "") -DEF(static_computed_field, "") /* must come after computed_fields */ -DEF(class_fields_init, "") -DEF(brand, "") -DEF(hash_constructor, "#constructor") -DEF(as, "as") -DEF(from, "from") -DEF(meta, "meta") -DEF(_default_, "*default*") -DEF(_star_, "*") -DEF(Module, "Module") -DEF(then, "then") -DEF(resolve, "resolve") -DEF(reject, "reject") -DEF(promise, "promise") -DEF(proxy, "proxy") -DEF(revoke, "revoke") -DEF(async, "async") -DEF(exec, "exec") -DEF(groups, "groups") -DEF(indices, "indices") -DEF(status, "status") -DEF(reason, "reason") -DEF(globalThis, "globalThis") -DEF(bigint, "bigint") -DEF(minus_zero, "-0") -DEF(Infinity, "Infinity") -DEF(minus_Infinity, "-Infinity") -DEF(NaN, "NaN") -DEF(hasIndices, "hasIndices") -DEF(ignoreCase, "ignoreCase") -DEF(multiline, "multiline") -DEF(dotAll, "dotAll") -DEF(sticky, "sticky") -DEF(unicodeSets, "unicodeSets") -/* the following 3 atoms are only used with CONFIG_ATOMICS */ -DEF(not_equal, "not-equal") -DEF(timed_out, "timed-out") -DEF(ok, "ok") -/* */ -DEF(toJSON, "toJSON") -/* class names */ -DEF(Object, "Object") -DEF(Array, "Array") -DEF(Error, "Error") -DEF(Number, "Number") -DEF(String, "String") -DEF(Boolean, "Boolean") -DEF(Symbol, "Symbol") -DEF(Math, "Math") -DEF(JSON, "JSON") -DEF(Date, "Date") -DEF(Function, "Function") -DEF(GeneratorFunction, "GeneratorFunction") -DEF(ForInIterator, "ForInIterator") -DEF(RegExp, "RegExp") -DEF(ArrayBuffer, "ArrayBuffer") -DEF(SharedArrayBuffer, "SharedArrayBuffer") -/* must keep same order as class IDs for typed arrays */ -DEF(Uint8ClampedArray, "Uint8ClampedArray") -DEF(Int8Array, "Int8Array") -DEF(Uint8Array, "Uint8Array") -DEF(Int16Array, "Int16Array") -DEF(Uint16Array, "Uint16Array") -DEF(Int32Array, "Int32Array") -DEF(Uint32Array, "Uint32Array") -DEF(BigInt64Array, "BigInt64Array") -DEF(BigUint64Array, "BigUint64Array") -DEF(Float16Array, "Float16Array") -DEF(Float32Array, "Float32Array") -DEF(Float64Array, "Float64Array") -DEF(DataView, "DataView") -DEF(BigInt, "BigInt") -DEF(WeakRef, "WeakRef") -DEF(FinalizationRegistry, "FinalizationRegistry") -DEF(Map, "Map") -DEF(Set, "Set") /* Map + 1 */ -DEF(WeakMap, "WeakMap") /* Map + 2 */ -DEF(WeakSet, "WeakSet") /* Map + 3 */ -DEF(Map_Iterator, "Map Iterator") -DEF(Set_Iterator, "Set Iterator") -DEF(Array_Iterator, "Array Iterator") -DEF(String_Iterator, "String Iterator") -DEF(RegExp_String_Iterator, "RegExp String Iterator") -DEF(Generator, "Generator") -DEF(Proxy, "Proxy") -DEF(Promise, "Promise") -DEF(PromiseResolveFunction, "PromiseResolveFunction") -DEF(PromiseRejectFunction, "PromiseRejectFunction") -DEF(AsyncFunction, "AsyncFunction") -DEF(AsyncFunctionResolve, "AsyncFunctionResolve") -DEF(AsyncFunctionReject, "AsyncFunctionReject") -DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction") -DEF(AsyncGenerator, "AsyncGenerator") -DEF(EvalError, "EvalError") -DEF(RangeError, "RangeError") -DEF(ReferenceError, "ReferenceError") -DEF(SyntaxError, "SyntaxError") -DEF(TypeError, "TypeError") -DEF(URIError, "URIError") -DEF(InternalError, "InternalError") -/* symbols */ -DEF(Symbol_toPrimitive, "Symbol.toPrimitive") -DEF(Symbol_iterator, "Symbol.iterator") -DEF(Symbol_match, "Symbol.match") -DEF(Symbol_matchAll, "Symbol.matchAll") -DEF(Symbol_replace, "Symbol.replace") -DEF(Symbol_search, "Symbol.search") -DEF(Symbol_split, "Symbol.split") -DEF(Symbol_toStringTag, "Symbol.toStringTag") -DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") -DEF(Symbol_hasInstance, "Symbol.hasInstance") -DEF(Symbol_species, "Symbol.species") -DEF(Symbol_unscopables, "Symbol.unscopables") -DEF(Symbol_asyncIterator, "Symbol.asyncIterator") - -#endif /* DEF */ diff --git a/source/quickjs-internal.h b/source/quickjs-internal.h index e155f1cd..d0a195fb 100644 --- a/source/quickjs-internal.h +++ b/source/quickjs-internal.h @@ -49,12 +49,173 @@ #include "libregexp.h" #include "libunicode.h" #include "list.h" -#include "quickjs.h" +#include "cell.h" #include "cJSON.h" #include "blob.h" #include "nota.h" #include "wota.h" +/* ============================================================ + Internal API — not for C module authors + ============================================================ */ + +/* Object header types */ +enum mist_obj_type { + OBJ_ARRAY = 0, + OBJ_BLOB = 1, + OBJ_TEXT = 2, + OBJ_RECORD = 3, // js style objects + OBJ_FUNCTION = 4, + OBJ_CODE = 5, + OBJ_FRAME = 6, + OBJ_FORWARD = 7 +}; + +/* Object header bits */ +#define OBJHDR_S_BIT 3u +#define OBJHDR_P_BIT 4u +#define OBJHDR_A_BIT 5u +#define OBJHDR_R_BIT 7u + +#define OBJHDR_FLAG(bit) ((objhdr_t)1ull << (bit)) +#define OBJHDR_S_MASK OBJHDR_FLAG (OBJHDR_S_BIT) +#define OBJHDR_P_MASK OBJHDR_FLAG (OBJHDR_P_BIT) +#define OBJHDR_A_MASK OBJHDR_FLAG (OBJHDR_A_BIT) +#define OBJHDR_R_MASK OBJHDR_FLAG (OBJHDR_R_BIT) + +typedef uint64_t word_t; // one actor-memory word +typedef uint64_t objhdr_t; // header word +typedef uint64_t objref_t; // 56-bit word address (0 = null) + +static inline uint8_t objhdr_type (objhdr_t h) { return (uint8_t)(h & 7u); } +static inline int objhdr_s (objhdr_t h) { return (h & OBJHDR_S_MASK) != 0; } + +/* Word size constant */ +#define JSW 8 + +/* Runtime / Context lifecycle */ +JSRuntime *JS_NewRuntime (void); +void JS_FreeRuntime (JSRuntime *rt); +void JS_SetMemoryLimit (JSRuntime *rt, size_t limit); +void JS_SetPoolSize (JSRuntime *rt, size_t initial, size_t cap); + +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); + +typedef void (*JS_GCScanFn)(JSContext *ctx, + uint8_t *from_base, uint8_t *from_end, + uint8_t *to_base, uint8_t **to_free, uint8_t *to_end); +void JS_SetGCScanExternal(JSContext *ctx, JS_GCScanFn fn); + +void JS_SetActorSym (JSContext *ctx, JSValue sym); +JSValue JS_GetActorSym (JSContext *ctx); +JSRuntime *JS_GetRuntime (JSContext *ctx); +void JS_SetMaxStackSize (JSContext *ctx, size_t stack_size); +void JS_UpdateStackTop (JSContext *ctx); +int JS_GetVMCallDepth(JSContext *ctx); +void JS_SetHeapMemoryLimit(JSContext *ctx, size_t limit); +void JS_SetPauseFlag(JSContext *ctx, int value); +JS_BOOL JS_IsLiveObject (JSRuntime *rt, JSValue obj); + +/* Suspended state */ +#define JS_TAG_SUSPENDED 0x13 /* 10011 - distinct special tag */ +#define JS_SUSPENDED ((JSValue)JS_TAG_SUSPENDED) + +static inline JS_BOOL JS_IsSuspended(JSValue v) { + return JS_VALUE_GET_TAG(v) == JS_TAG_SUSPENDED; +} + +#ifndef JS_DEFAULT_STACK_SIZE +#define JS_DEFAULT_STACK_SIZE (1024 * 1024) +#endif + +/* Internal compile flags */ +#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) + +/* Compilation and MachCode */ +struct cJSON; +typedef struct MachCode MachCode; + +void JS_FreeMachCode(MachCode *mc); +uint8_t *JS_SerializeMachCode(MachCode *mc, size_t *out_size); +MachCode *JS_DeserializeMachCode(const uint8_t *data, size_t size); +struct JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env); +JSValue JS_RunMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env); +JSValue JS_RunMachMcode(JSContext *ctx, const char *json_str, size_t len, JSValue env); +void JS_DumpMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env); +MachCode *mach_compile_mcode(struct cJSON *mcode_json); + +/* 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; + JS_BOOL raw_dump : 8; + uint32_t max_depth; + uint32_t max_string_length; + uint32_t max_item_count; +} JSPrintValueOptions; + +typedef void JSPrintValueWrite (void *opaque, const char *buf, size_t len); + +void JS_PrintValueSetDefaultOptions (JSPrintValueOptions *options); +void JS_PrintValueRT (JSRuntime *rt, JSPrintValueWrite *write_func, + void *write_opaque, JSValue val, + const JSPrintValueOptions *options); +void JS_PrintValue (JSContext *ctx, JSPrintValueWrite *write_func, + void *write_opaque, JSValue val, + const JSPrintValueOptions *options); + +void js_debug_info (JSContext *js, JSValue fn, js_debug *dbg); + +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); + +/* Stack trace */ +JSValue JS_GetStack (JSContext *ctx); +void JS_CrashPrintStack(JSContext *ctx); + +/* Serialization (internal) */ +JSValue wota2value(JSContext *js, void *v); +void *value2wota(JSContext *js, JSValue v, JSValue replacer, size_t *bytes); +JSValue nota2value(JSContext *js, void *nota); +void *value2nota(JSContext *js, JSValue v); + +/* Internal module init (called during context init) */ +JSValue js_core_blob_use(JSContext *js); +JSValue js_core_json_use(JSContext *js); + +/* ============================================================ + End internal API declarations + ============================================================ */ + void *js_malloc (JSContext *ctx, size_t size); void *js_mallocz (JSContext *ctx, size_t size); diff --git a/source/quickjs.h b/source/quickjs.h deleted file mode 100644 index 00fcec24..00000000 --- a/source/quickjs.h +++ /dev/null @@ -1,1075 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef QUICKJS_H -#define QUICKJS_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__GNUC__) || defined(__clang__) -#define __js_printf_like(f, a) __attribute__ ((format (printf, f, a))) -#else -#define __js_printf_like(a, b) -#endif - -// #define BINARY16 // 16 bit word type (half) -// #define BINARY32 // 32 bit word type (float) -// #define BINARY64 // 64 bit word type (double) -// #define DEC64 // 64 bit word type (dec) - -enum mist_obj_type { - OBJ_ARRAY = 0, - OBJ_BLOB = 1, - OBJ_TEXT = 2, - OBJ_RECORD = 3, // js style objects - OBJ_FUNCTION = 4, - OBJ_CODE = 5, - OBJ_FRAME = 6, - OBJ_FORWARD = 7 -}; - -typedef uint64_t JSValue; - -#define OBJHDR_S_BIT 3u -#define OBJHDR_P_BIT 4u -#define OBJHDR_A_BIT 5u -#define OBJHDR_R_BIT 7u - -#define OBJHDR_FLAG(bit) ((objhdr_t)1ull << (bit)) -#define OBJHDR_S_MASK OBJHDR_FLAG (OBJHDR_S_BIT) -#define OBJHDR_P_MASK OBJHDR_FLAG (OBJHDR_P_BIT) -#define OBJHDR_A_MASK OBJHDR_FLAG (OBJHDR_A_BIT) -#define OBJHDR_R_MASK OBJHDR_FLAG (OBJHDR_R_BIT) - -typedef uint64_t word_t; // one actor-memory word -typedef uint64_t objhdr_t; // header word -typedef uint64_t objref_t; // 56-bit word address (0 = null) - -static inline uint8_t objhdr_type (objhdr_t h) { return (uint8_t)(h & 7u); } -static inline int objhdr_s (objhdr_t h) { return (h & OBJHDR_S_MASK) != 0; } - -/* - Half: 10 bits - Float: 23 bits - Double: 52 bits - Dec16: 11 bits - Dec32: 26 bits - Dec64: 56 bits - - On double builds, 48 bits - On Dec64, max -*/ - -#define JS_BOOL int - -typedef struct JSRuntime JSRuntime; // the entire VM -typedef struct JSContext JSContext; // Each actor -typedef struct JSClass JSClass; -typedef uint32_t JSClassID; - -/* Forward declaration - JSGCRef moved after JSValue definition */ -struct JSGCRef; - -/* ============================================================ - Mist Value Encoding (LSB-based type discrimination) - ============================================================ - - 64-bit builds: - LSB = 0 → 31-bit signed integer (value >> 1) - LSB = 001 → 61-bit pointer (aligned, clear low 3 bits) - LSB = 101 → Short float (61-bit, 3 fewer exponent bits than double) - LSB = 11 → Special tag (next 3 bits = subtype, 5 bits total) - - 32-bit builds: - LSB = 0 → 31-bit signed integer - LSB = 01 → 30-bit pointer - LSB = 11 → Special tag (next 3 bits = subtype) - - ============================================================ */ - -/* JSValueConst is just JSValue (const is not needed in value semantics) */ -typedef JSValue JSValueConst; - -#define JSW 8 - -/* LSB-based tags */ -enum { - /* Primary tags (low bits) */ - JS_TAG_INT = 0, /* LSB = 0 */ - JS_TAG_PTR = 1, /* LSB = 01 */ - JS_TAG_SHORT_FLOAT = 5, /* LSB = 101 */ - JS_TAG_SPECIAL = 3, /* LSB = 11 */ - - /* Special subtypes (5 bits: xxxx11) */ - JS_TAG_BOOL = 0x03, /* 00011 */ - JS_TAG_NULL = 0x07, /* 00111 */ - JS_TAG_EXCEPTION = 0x0F, /* 01111 */ - JS_TAG_STRING_IMM = 0x0B, /* 01011 - immediate ASCII (up to 7 chars) */ -}; - -/* Compatibility tag aliases for external code */ -#define JS_TAG_STRING JS_TAG_STRING_IMM /* Alias: text/string type */ -#define JS_TAG_FLOAT64 JS_TAG_SHORT_FLOAT /* Alias: floats use short float encoding */ - -#define JS_EMPTY_TEXT ((JSValue)JS_TAG_STRING_IMM) - -/* JSGCRef - for rooting values during GC */ -typedef struct JSGCRef { - JSValue val; - struct JSGCRef *prev; -} JSGCRef; - -/* JSLocalRef - GC updates C locals through pointers (OCaml-style) */ -typedef struct JSLocalRef { - JSValue *ptr; - struct JSLocalRef *prev; -} JSLocalRef; - -/* stack of JSGCRef */ -JSValue *JS_PushGCRef(JSContext *ctx, JSGCRef *ref); -JSValue JS_PopGCRef(JSContext *ctx, JSGCRef *ref); - -/* JS_FRAME/JS_ROOT/JS_LOCAL helpers (for use from cell.h macros) */ -JSGCRef *JS_GetGCFrame(JSContext *ctx); -JSLocalRef *JS_GetLocalFrame(JSContext *ctx); -void JS_PushLocalRef(JSContext *ctx, JSLocalRef *ref); -void JS_RestoreFrame(JSContext *ctx, JSGCRef *gc_frame, JSLocalRef *local_frame); - -#define JS_PUSH_VALUE(ctx, v) do { JS_PushGCRef(ctx, &v ## _ref); v ## _ref.val = v; } while (0) -#define JS_POP_VALUE(ctx, v) v = JS_PopGCRef(ctx, &v ## _ref) - -/* list of JSGCRef (they can be removed in any order, slower) */ -JSValue *JS_AddGCRef(JSContext *ctx, JSGCRef *ref); -void JS_DeleteGCRef(JSContext *ctx, JSGCRef *ref); - -/* ============================================================ - Value Extraction - ============================================================ */ - -/* Get primary tag (low 2-3 bits) */ -static inline int -JS_VALUE_GET_TAG (JSValue v) { - if ((v & 1) == 0) return JS_TAG_INT; - if ((v & 7) == JS_TAG_SHORT_FLOAT) return JS_TAG_SHORT_FLOAT; - if ((v & 3) == JS_TAG_PTR) return JS_TAG_PTR; - return (int)(v & 0x1F); /* special tag */ -} - -#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG (v) - -/* Extract 31-bit signed int (when LSB=0) */ -#define JS_VALUE_GET_INT(v) ((int32_t)((int64_t)(v) >> 1)) - -/* Extract bool value from special tag */ -#define JS_VALUE_GET_BOOL(v) ((int)((v) >> 5) & 1) - -/* Extract special tag payload (bits 5+) */ -#define JS_VALUE_GET_SPECIAL_PAYLOAD(v) ((int32_t)((v) >> 5)) - -/* ============================================================ - Value Creation - ============================================================ */ - -#define JS_MKVAL(tag, val) _JS_MkVal (tag, val) -static inline JSValue _JS_MkVal (int tag, int32_t val) { - if (tag == JS_TAG_INT) { return ((JSValue)(uint32_t)val << 1); } - /* Special tags encode payload in upper bits */ - return ((JSValue)tag) | ((JSValue)(uint32_t)val << 5); -} - -/* ============================================================ - Short Float (64-bit only) - Range: ~+-3.4e38 (8-bit exponent vs double's 11-bit) - Out of range → JS_NULL - ============================================================ */ - -static inline JSValue -__JS_NewFloat64 (JSContext *ctx, double d) { - union { - double d; - uint64_t u; - } u; - u.d = d; - - uint64_t sign = u.u >> 63; - int exp = (u.u >> 52) & 0x7FF; - uint64_t mantissa = u.u & ((1ULL << 52) - 1); - - /* Zero → short float zero (always +0, no -0) */ - if (exp == 0 && mantissa == 0) { return JS_TAG_SHORT_FLOAT; } - - /* NaN/Inf → NULL */ - if (exp == 0x7FF) { return JS_MKVAL (JS_TAG_NULL, 0); } - - /* Subnormals → zero */ - if (exp == 0) { return (sign << 63) | JS_TAG_SHORT_FLOAT; } - - /* Convert exponent: double bias 1023 → short bias 127 */ - int short_exp = exp - 1023 + 127; - if (short_exp < 1 || short_exp > 254) { - return JS_MKVAL (JS_TAG_NULL, 0); /* out of range */ - } - - /* Prefer integer if exact */ - if (d >= INT32_MIN && d <= INT32_MAX) { - int32_t i = (int32_t)d; - if ((double)i == d) { return JS_MKVAL (JS_TAG_INT, i); } - } - - /* Encode: [sign:1][exp:8][mantissa:52][tag:3] */ - return (sign << 63) | ((uint64_t)short_exp << 55) | (mantissa << 3) - | JS_TAG_SHORT_FLOAT; -} - -static inline double JS_VALUE_GET_FLOAT64 (JSValue v) { - if ((v & 7) != JS_TAG_SHORT_FLOAT) return 0.0; - - uint64_t sign = v >> 63; - uint64_t short_exp = (v >> 55) & 0xFF; - uint64_t mantissa = (v >> 3) & ((1ULL << 52) - 1); - - if (short_exp == 0) return 0.0; /* Always +0, no -0 */ - - uint64_t exp = short_exp - 127 + 1023; - union { - double d; - uint64_t u; - } u; - u.u = (sign << 63) | (exp << 52) | mantissa; - return u.d; -} - -#define JS_TAG_IS_FLOAT64(tag) ((tag) == JS_TAG_SHORT_FLOAT) -#define JS_NAN JS_MKVAL (JS_TAG_NULL, 0) - -/* ============================================================ - Type Checks - ============================================================ */ - -static inline JS_BOOL JS_IsInt (JSValue v) { return (v & 1) == 0; } -static inline JS_BOOL JS_IsPtr (JSValue v) { return (v & 7) == JS_TAG_PTR; } -static inline JS_BOOL JS_IsSpecial (JSValue v) { return (v & 3) == JS_TAG_SPECIAL; } - -static inline JS_BOOL -JS_IsShortFloat (JSValue v) { - return (v & 7) == JS_TAG_SHORT_FLOAT; -} - -#define JS_VALUE_IS_BOTH_INT(v1, v2) (((v1) & 1) == 0 && ((v2) & 1) == 0) -#define JS_VALUE_IS_BOTH_FLOAT(v1, v2) \ - (JS_IsShortFloat (v1) && JS_IsShortFloat (v2)) - -/* ============================================================ - Special Constants - ============================================================ */ - -#define JS_NULL ((JSValue)JS_TAG_NULL) -#define JS_FALSE ((JSValue)JS_TAG_BOOL) -#define JS_TRUE ((JSValue)(JS_TAG_BOOL | (1 << 5))) -#define JS_EXCEPTION ((JSValue)JS_TAG_EXCEPTION) -#define JS_TAG_SUSPENDED 0x13 /* 10011 - distinct special tag */ -#define JS_SUSPENDED ((JSValue)JS_TAG_SUSPENDED) - -static inline JS_BOOL JS_IsSuspended(JSValue v) { - return JS_VALUE_GET_TAG(v) == JS_TAG_SUSPENDED; -} - -#ifndef JS_DEFAULT_STACK_SIZE -#define JS_DEFAULT_STACK_SIZE (1024 * 1024) -#endif - -/* Internal compile flags */ -#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) /* internal use */ - -typedef JSValue JSCFunction (JSContext *ctx, JSValue this_val, int argc, - JSValue *argv); -typedef JSValue JSCFunctionMagic (JSContext *ctx, JSValue this_val, - int argc, JSValue *argv, int magic); -typedef JSValue JSCFunctionData (JSContext *ctx, JSValue this_val, - int argc, JSValue *argv, int magic, - JSValue *data); - -/* ============================================================ - 1. Runtime / Context Lifecycle - ============================================================ */ - -JSRuntime *JS_NewRuntime (void); -void JS_FreeRuntime (JSRuntime *rt); -void JS_SetMemoryLimit (JSRuntime *rt, size_t limit); -void JS_SetPoolSize (JSRuntime *rt, size_t initial, size_t cap); - -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); - -typedef void (*JS_GCScanFn)(JSContext *ctx, - uint8_t *from_base, uint8_t *from_end, - uint8_t *to_base, uint8_t **to_free, uint8_t *to_end); -void JS_SetGCScanExternal(JSContext *ctx, JS_GCScanFn fn); - -void JS_SetActorSym (JSContext *ctx, JSValue sym); -JSValue JS_GetActorSym (JSContext *ctx); -JSRuntime *JS_GetRuntime (JSContext *ctx); -/* 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); - -/* Returns the current VM call depth (0 = pure bytecode, >0 = C frames) */ -int JS_GetVMCallDepth(JSContext *ctx); - -/* Set per-context heap memory limit (0 = no limit) */ -void JS_SetHeapMemoryLimit(JSContext *ctx, size_t limit); - -/* Set the pause flag on a context (0=normal, 1=suspend, 2=kill) */ -void JS_SetPauseFlag(JSContext *ctx, int value); - -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, - JSValue *argv, int flags); - -typedef struct JSClassDef { - const char *class_name; - JSClassFinalizer *finalizer; - JSClassCall *call; -} 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. */ -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); -void JS_SetClassProto (JSContext *ctx, JSClassID class_id, JSValue obj); -JSValue JS_GetClassProto (JSContext *ctx, JSClassID class_id); - -/* ============================================================ - 2. Value Creation and Type Checks - ============================================================ */ - -static inline JSValue -JS_NewBool (JSContext *ctx, JS_BOOL val) { - return JS_MKVAL (JS_TAG_BOOL, (val != 0)); -} - -static inline JSValue -JS_NewInt32 (JSContext *ctx, int32_t val) { - return JS_MKVAL (JS_TAG_INT, val); -} - -static inline JSValue -JS_NewInt64 (JSContext *ctx, int64_t val) { - JSValue v; - if (val == (int32_t)val) { - v = JS_NewInt32 (ctx, val); - } else { - v = __JS_NewFloat64 (ctx, val); - } - return v; -} - -static inline JSValue -JS_NewUint32 (JSContext *ctx, uint32_t val) { - JSValue v; - if (val <= 0x7fffffff) { - v = JS_NewInt32 (ctx, val); - } else { - v = __JS_NewFloat64 (ctx, val); - } - return v; -} - -static inline JSValue -JS_NewFloat64 (JSContext *ctx, double d) { - int32_t val; - union { - double d; - uint64_t u; - } u, t; - if (d >= INT32_MIN && d <= INT32_MAX) { - u.d = d; - val = (int32_t)d; - t.d = val; - /* -0 cannot be represented as integer, so we compare the bit - representation */ - if (u.u == t.u) return JS_MKVAL (JS_TAG_INT, val); - } - 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); -} - -static inline JS_BOOL JS_IsBool (JSValue v) { - return JS_VALUE_GET_TAG (v) == JS_TAG_BOOL; -} - -static inline JS_BOOL JS_IsNull (JSValue v) { - return JS_VALUE_GET_TAG (v) == JS_TAG_NULL; -} - -static inline JS_BOOL JS_IsException (JSValue v) { - return (JS_VALUE_GET_TAG (v) == JS_TAG_EXCEPTION); -} - -/* Immediate ASCII string helpers */ -#define MIST_ASCII_MAX_LEN 7 - -static inline JS_BOOL -MIST_IsImmediateASCII (JSValue v) { - return (v & 0x1F) == JS_TAG_STRING_IMM; -} - -static inline int -MIST_GetImmediateASCIILen (JSValue v) { - return (int)((v >> 5) & 0x7); -} - -static inline int MIST_GetImmediateASCIIChar (JSValue v, int idx) { - return (int)((v >> (8 + idx * 8)) & 0xFF); -} - -static inline JSValue MIST_TryNewImmediateASCII (const char *str, size_t len) { - if (len > MIST_ASCII_MAX_LEN) return JS_NULL; - JSValue v = (JSValue)JS_TAG_STRING_IMM | ((JSValue)len << 5); - for (size_t i = 0; i < len; i++) { - uint8_t c = (uint8_t)str[i]; - if (c >= 0x80) return JS_NULL; - v |= (JSValue)c << (8 + i * 8); - } - 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 -JS_BOOL JS_IsFunction(JSValue v); -JS_BOOL JS_IsBlob(JSValue v); -JS_BOOL JS_IsText(JSValue v); -JS_BOOL JS_IsStone(JSValue v); - -/* ============================================================ - 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_NewObjectCap (JSContext *ctx, uint32_t n); - -JSValue JS_NewArray (JSContext *ctx); -JSValue JS_NewArrayLen (JSContext *ctx, uint32_t len); -JSValue JS_NewArrayCap (JSContext *ctx, uint32_t cap); -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_GetException (JSContext *ctx); -JS_BOOL JS_HasException (JSContext *ctx); - -/* Set the disruption flag. No logging. */ -JSValue JS_Disrupt (JSContext *ctx); - -/* Log a message to a named channel. Routes through the ƿit log callback - if one has been set, otherwise falls back to fprintf(stderr). */ -void __js_printf_like (3, 4) - JS_Log (JSContext *ctx, const char *channel, const char *fmt, ...); - -/* Log to "error" channel + raise disruption. The common case. */ -JSValue __js_printf_like (2, 3) - JS_RaiseDisrupt (JSContext *ctx, const char *fmt, ...); - -/* Log to "memory" channel + disrupt. Skips JS callback (can't allocate). */ -JSValue JS_RaiseOOM (JSContext *ctx); -#define JS_ThrowOutOfMemory JS_RaiseOOM -#define JS_ThrowReferenceError JS_RaiseDisrupt -#define JS_ThrowTypeError JS_RaiseDisrupt -#define JS_ThrowInternalError JS_RaiseDisrupt -#define JS_ThrowRangeError JS_RaiseDisrupt - -/* ============================================================ - 8. Function Creation and Invocation - ============================================================ */ - -JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv); -JSValue JS_Stone (JSContext *ctx, JSValue this_val); - -/* 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, - JS_BOOL compact_arrays); - -/* ============================================================ - 9. Intrinsic Wrappers (JS_Cell* / JS_Array*) - ============================================================ */ - -/* 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); -JSValue JS_ArrayFind (JSContext *ctx, JSValue arr, JSValue target_or_fn, JSValue reverse, JSValue from); -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); - -/* Core cell functions */ -JSValue JS_CellStone (JSContext *ctx, JSValue val); -JSValue JS_CellLength (JSContext *ctx, JSValue val); -JSValue JS_CellReverse (JSContext *ctx, JSValue val); -JSValue JS_CellProto (JSContext *ctx, JSValue obj); -JSValue JS_CellSplat (JSContext *ctx, JSValue val); -JSValue JS_CellMeme (JSContext *ctx, JSValue obj, JSValue deep); -JSValue JS_CellApply (JSContext *ctx, JSValue fn, JSValue args); -JSValue JS_CellCall (JSContext *ctx, JSValue fn, JSValue this_val, JSValue args); -JSValue JS_CellModulo (JSContext *ctx, JSValue a, JSValue b); -JSValue JS_CellNeg (JSContext *ctx, JSValue val); -JSValue JS_CellNot (JSContext *ctx, JSValue val); - -/* Text cell functions */ -JSValue JS_CellText (JSContext *ctx, JSValue val); -JSValue JS_CellLower (JSContext *ctx, JSValue text); -JSValue JS_CellUpper (JSContext *ctx, JSValue text); -JSValue JS_CellTrim (JSContext *ctx, JSValue text, JSValue chars); -JSValue JS_CellCodepoint (JSContext *ctx, JSValue text, JSValue idx); -JSValue JS_CellReplace (JSContext *ctx, JSValue text, JSValue pattern, JSValue replacement); -JSValue JS_CellSearch (JSContext *ctx, JSValue text, JSValue pattern, JSValue from); -JSValue JS_CellExtract (JSContext *ctx, JSValue text, JSValue from, JSValue to); -JSValue JS_CellCharacter (JSContext *ctx, JSValue codepoint); - -/* Number cell functions */ -JSValue JS_CellNumber (JSContext *ctx, JSValue val); -JSValue JS_CellAbs (JSContext *ctx, JSValue num); -JSValue JS_CellSign (JSContext *ctx, JSValue num); -JSValue JS_CellFloor (JSContext *ctx, JSValue num); -JSValue JS_CellCeiling (JSContext *ctx, JSValue num); -JSValue JS_CellRound (JSContext *ctx, JSValue num); -JSValue JS_CellTrunc (JSContext *ctx, JSValue num); -JSValue JS_CellWhole (JSContext *ctx, JSValue num); -JSValue JS_CellFraction (JSContext *ctx, JSValue num); -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 cell functions */ -JSValue JS_CellObject (JSContext *ctx, JSValue proto, JSValue props); - -/* Format */ -JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue transformer); - -/* 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); - -/* ============================================================ - 10. C Function Definition - ============================================================ */ -typedef enum JSCFunctionEnum { - JS_CFUNC_generic, - JS_CFUNC_generic_magic, - JS_CFUNC_f_f, - JS_CFUNC_f_f_f, - /* Fixed-arity fast paths - no argc/argv overhead */ - JS_CFUNC_0, /* JSValue f(ctx, this_val) */ - JS_CFUNC_1, /* JSValue f(ctx, this_val, arg0) */ - JS_CFUNC_2, /* JSValue f(ctx, this_val, arg0, arg1) */ - JS_CFUNC_3, /* JSValue f(ctx, this_val, arg0, arg1, arg2) */ - JS_CFUNC_4, - /* Pure functions (no this_val) - for global utility functions */ - JS_CFUNC_PURE, /* JSValue f(ctx, argc, argv) - generic pure */ - JS_CFUNC_PURE_0, /* JSValue f(ctx) */ - JS_CFUNC_PURE_1, /* JSValue f(ctx, arg0) */ - JS_CFUNC_PURE_2, /* JSValue f(ctx, arg0, arg1) */ - JS_CFUNC_PURE_3, /* JSValue f(ctx, arg0, arg1, arg2) */ - JS_CFUNC_PURE_4 /* JSValue f(ctx, arg0, arg1, arg2, arg3) */ -} JSCFunctionEnum; - -/* Fixed-arity C function types for fast paths */ -typedef JSValue JSCFunction0 (JSContext *ctx, JSValue this_val); -typedef JSValue JSCFunction1 (JSContext *ctx, JSValue this_val, - JSValue arg0); -typedef JSValue JSCFunction2 (JSContext *ctx, JSValue this_val, - JSValue arg0, JSValue arg1); -typedef JSValue JSCFunction3 (JSContext *ctx, JSValue this_val, - JSValue arg0, JSValue arg1, - JSValue arg2); -typedef JSValue JSCFunction4 (JSContext *ctx, JSValue this_val, - JSValue arg0, JSValue arg1, - JSValue arg2, JSValue arg3); - -/* Pure function types (no this_val) */ -typedef JSValue JSCFunctionPure (JSContext *ctx, int argc, JSValue *argv); -typedef JSValue JSCFunctionPure0 (JSContext *ctx); -typedef JSValue JSCFunctionPure1 (JSContext *ctx, JSValue arg0); -typedef JSValue JSCFunctionPure2 (JSContext *ctx, JSValue arg0, JSValue arg1); -typedef JSValue JSCFunctionPure3 (JSContext *ctx, JSValue arg0, JSValue arg1, - JSValue arg2); -typedef JSValue JSCFunctionPure4 (JSContext *ctx, JSValue arg0, JSValue arg1, - JSValue arg2, JSValue arg3); - -typedef union JSCFunctionType { - JSCFunction *generic; - JSValue (*generic_magic) (JSContext *ctx, JSValue this_val, int argc, - JSValue *argv, int magic); - double (*f_f) (double); - double (*f_f_f) (double, double); - /* Fixed-arity fast paths */ - JSCFunction0 *f0; - JSCFunction1 *f1; - JSCFunction2 *f2; - JSCFunction3 *f3; - JSCFunction4 *f4; - /* Pure function pointers */ - JSCFunctionPure *pure; - JSCFunctionPure0 *pure0; - JSCFunctionPure1 *pure1; - JSCFunctionPure2 *pure2; - JSCFunctionPure3 *pure3; - JSCFunctionPure4 *pure4; -} JSCFunctionType; - -JSValue JS_NewCFunction2 (JSContext *ctx, JSCFunction *func, const char *name, - int length, JSCFunctionEnum cproto, int magic); - -static inline JSValue JS_NewCFunction (JSContext *ctx, JSCFunction *func, const char *name, int length) { - return JS_NewCFunction2 (ctx, func, name, length, JS_CFUNC_generic, 0); -} - -static inline JSValue JS_NewCFunctionMagic (JSContext *ctx, JSCFunctionMagic *func, const char *name, int length, JSCFunctionEnum cproto, int magic) { - return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, length, cproto, - magic); -} - -/* Fixed-arity fast path constructors */ -static inline JSValue JS_NewCFuncFixed0 (JSContext *ctx, JSCFunction0 *func, const char *name) { - return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 0, JS_CFUNC_0, 0); -} - -static inline JSValue JS_NewCFuncFixed1 (JSContext *ctx, JSCFunction1 *func, const char *name) { - return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 1, JS_CFUNC_1, 0); -} - -static inline JSValue JS_NewCFuncFixed2 (JSContext *ctx, JSCFunction2 *func, const char *name) { - return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 2, JS_CFUNC_2, 0); -} - -static inline JSValue JS_NewCFuncFixed3 (JSContext *ctx, JSCFunction3 *func, const char *name) { - return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 3, JS_CFUNC_3, 0); -} - -static inline JSValue JS_NewCFuncFixed4 (JSContext *ctx, JSCFunction4 *func, const char *name) { - return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 4, JS_CFUNC_4, 0); -} - -/* C property definition */ - -typedef struct JSCFunctionListEntry { - const char *name; - uint8_t prop_flags; - uint8_t def_type; - int16_t magic; - union { - struct { - uint8_t length; /* XXX: should move outside union */ - uint8_t cproto; /* XXX: should move outside union */ - JSCFunctionType cfunc; - } func; - struct { - const char *name; - int base; - } alias; - struct { - const struct JSCFunctionListEntry *tab; - int len; - } prop_list; - const char *str; - int32_t i32; - int64_t i64; - double f64; - } u; -} JSCFunctionListEntry; - -#define JS_DEF_CFUNC 0 -#define JS_DEF_PROP_STRING 3 -#define JS_DEF_PROP_INT32 4 -#define JS_DEF_PROP_INT64 5 -#define JS_DEF_PROP_DOUBLE 6 -#define JS_DEF_PROP_UNDEFINED 7 -#define JS_DEF_OBJECT 8 -#define JS_DEF_ALIAS 9 - -/* Note: c++ does not like nested designators */ -#define JS_CFUNC_DEF(name, length, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { length, JS_CFUNC_generic, { .generic = func1 } } } \ - } -#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) \ - { \ - name, 0, JS_DEF_CFUNC, magic, .u = { \ - .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } \ - } \ - } -#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { length, JS_CFUNC_##cproto, { .cproto = func1 } } } \ - } -/* Fixed-arity fast path macros */ -#define JS_CFUNC0_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 0, JS_CFUNC_0, { .f0 = func1 } } } \ - } -#define JS_CFUNC1_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 1, JS_CFUNC_1, { .f1 = func1 } } } \ - } -#define JS_CFUNC2_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 2, JS_CFUNC_2, { .f2 = func1 } } } \ - } -#define JS_CFUNC3_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 3, JS_CFUNC_3, { .f3 = func1 } } } \ - } -/* Pure function (no this_val) macros */ -#define JS_CFUNC_PURE_DEF(name, length, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { length, JS_CFUNC_PURE, { .pure = func1 } } } \ - } -#define JS_CFUNC_PURE0_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 0, JS_CFUNC_PURE_0, { .pure0 = func1 } } } \ - } -#define JS_CFUNC_PURE1_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 1, JS_CFUNC_PURE_1, { .pure1 = func1 } } } \ - } -#define JS_CFUNC_PURE2_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 2, JS_CFUNC_PURE_2, { .pure2 = func1 } } } \ - } -#define JS_CFUNC_PURE3_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 3, JS_CFUNC_PURE_3, { .pure3 = func1 } } } \ - } -#define JS_CFUNC_PURE4_DEF(name, func1) \ - { \ - name, 0, JS_DEF_CFUNC, 0, \ - .u \ - = {.func = { 4, JS_CFUNC_PURE_4, { .pure4 = func1 } } } \ - } -#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) \ - { \ - name, 0, JS_DEF_CFUNC, magic, .u = { \ - .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } \ - } \ - } -#define JS_PROP_STRING_DEF(name, cstr, prop_flags) \ - { \ - name, prop_flags, JS_DEF_PROP_STRING, 0, .u = {.str = cstr } \ - } -#define JS_PROP_INT32_DEF(name, val, prop_flags) \ - { \ - name, prop_flags, JS_DEF_PROP_INT32, 0, .u = {.i32 = val } \ - } -#define JS_PROP_INT64_DEF(name, val, prop_flags) \ - { \ - name, prop_flags, JS_DEF_PROP_INT64, 0, .u = {.i64 = val } \ - } -#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) \ - { \ - name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = {.f64 = val } \ - } -#define JS_PROP_UNDEFINED_DEF(name, prop_flags) \ - { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } -#define JS_OBJECT_DEF(name, tab, len, prop_flags) \ - { \ - name, prop_flags, JS_DEF_OBJECT, 0, .u = {.prop_list = { tab, len } } \ - } -#define JS_ALIAS_DEF(name, from) \ - { \ - name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, \ - .u \ - = {.alias = { from, -1 } } \ - } -#define JS_ALIAS_BASE_DEF(name, from, base) \ - { \ - name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, \ - .u \ - = {.alias = { from, base } } \ - } - -int JS_SetPropertyFunctionList (JSContext *ctx, JSValue obj, - const JSCFunctionListEntry *tab, int len); - -/* ============================================================ - 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 */ - JS_BOOL raw_dump : 8; /* avoid doing autoinit and avoid any malloc() call - (for internal use) */ - uint32_t max_depth; /* recurse up to this depth, 0 = no limit */ - uint32_t max_string_length; /* print no more than this length for - strings, 0 = no limit */ - uint32_t max_item_count; /* print no more than this count for - arrays or objects, 0 = no limit */ -} JSPrintValueOptions; - -typedef void JSPrintValueWrite (void *opaque, const char *buf, size_t len); - -void JS_PrintValueSetDefaultOptions (JSPrintValueOptions *options); -void JS_PrintValueRT (JSRuntime *rt, JSPrintValueWrite *write_func, - void *write_opaque, JSValue val, - const JSPrintValueOptions *options); -void JS_PrintValue (JSContext *ctx, JSPrintValueWrite *write_func, - void *write_opaque, JSValue val, - const JSPrintValueOptions *options); - -typedef struct js_debug { - char name[64]; - char filename[96]; - int unique; - int line; - int param_n; - int closure_n; - int vararg; - const char *what; - const uint8_t *source; - int srclen; -} js_debug; - -void js_debug_info (JSContext *js, JSValue fn, js_debug *dbg); - -typedef void (*js_hook) (JSContext *, int type, js_debug *dbg, void *user); -#define JS_HOOK_CALL 1 -#define JS_HOOK_RET 2 -#define JS_HOOK_CYCLE 4 -#define JS_HOOK_GC 8 -void js_debug_sethook (JSContext *ctx, js_hook, int type, void *user); - -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 - ============================================================ */ -/* Runtime-level memory functions */ -void *js_malloc_rt (size_t size); -void *js_mallocz_rt (size_t size); -void js_free_rt (void *ptr); - -/* ============================================================ - 13. Compilation and Bytecode - ============================================================ */ - -struct cJSON; -typedef struct MachCode MachCode; - -/* Free a compiled MachCode tree. */ -void JS_FreeMachCode(MachCode *mc); - -/* Serialize MachCode to binary. Returns sys_malloc'd buffer; caller frees. */ -uint8_t *JS_SerializeMachCode(MachCode *mc, size_t *out_size); - -/* Deserialize binary back to MachCode. Returns NULL on error. */ -MachCode *JS_DeserializeMachCode(const uint8_t *data, size_t size); - -/* Load compiled MachCode into a JSContext, materializing JSValues. */ -struct JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env); - -/* Deserialize and execute pre-compiled MACH binary bytecode. */ -JSValue JS_RunMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env); - -/* Parse mcode JSON IR, compile, and execute via register VM. */ -JSValue JS_RunMachMcode(JSContext *ctx, const char *json_str, size_t len, JSValue env); - -/* Dump disassembly of pre-compiled MACH binary bytecode. */ -void JS_DumpMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env); - -/* Compile mcode JSON IR to MachCode binary. */ -MachCode *mach_compile_mcode(struct cJSON *mcode_json); - -/* Get stack trace as JS array of {fn, file, line, col} objects. - Returns an empty array if no register VM frame is active. - Does NOT clear reg_current_frame — caller is responsible if needed. */ -JSValue JS_GetStack (JSContext *ctx); - -/* Crash-safe stack printer: walks JS frames and writes to stderr. - Uses only write() (async-signal-safe). No GC allocations. - Safe to call from signal handlers. */ -void JS_CrashPrintStack(JSContext *ctx); - -#undef js_unlikely -#undef inline - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - -#endif /* QUICKJS_H */ diff --git a/source/suite.c b/source/suite.c index c395dcad..2e63c111 100644 --- a/source/suite.c +++ b/source/suite.c @@ -4,8 +4,8 @@ * Bypasses parser/bytecode to verify low-level operations */ -#include "quickjs.h" -#include "cJSON.h" +#include "cell.h" +#include "quickjs-internal.h" #include #include #include