Files
cell/source/quickjs.h

1292 lines
49 KiB
C

/*
* 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 <stdint.h>
#include <stdio.h>
#include <string.h>
#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
};
#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 struct JSFunctionBytecode JSFunctionBytecode;
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)
============================================================ */
#if INTPTR_MAX >= INT64_MAX
#define JS_PTR64
#define JS_PTR64_DEF(a) a
typedef uint64_t JSValue;
#define JSW 8
#else
typedef uint32_t JSValue;
#define JSW 4
#define JS_PTR64_DEF(a)
#endif
#define JSValue JSValue
/* JSValueConst is just JSValue (const is not needed in value semantics) */
typedef JSValue JSValueConst;
/* LSB-based tags */
enum {
/* Primary tags (low bits) */
JS_TAG_INT = 0, /* LSB = 0 */
JS_TAG_PTR = 1, /* LSB = 01 */
#ifdef JS_PTR64
JS_TAG_SHORT_FLOAT = 5, /* LSB = 101 */
#endif
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_UNINITIALIZED = 0x17, /* 10111 */
JS_TAG_STRING_IMM = 0x1B, /* 11011 - immediate ASCII (up to 7 chars) */
JS_TAG_CATCH_OFFSET = 0x1F, /* 11111 */
};
/* 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;
/* stack of JSGCRef */
JSValue *JS_PushGCRef(JSContext *ctx, JSGCRef *ref);
JSValue JS_PopGCRef(JSContext *ctx, JSGCRef *ref);
#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) {
#ifdef JS_PTR64
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 */
#else
if ((v & 1) == 0) return JS_TAG_INT;
if ((v & 3) == JS_TAG_PTR) return JS_TAG_PTR;
return (int)(v & 0x1F);
#endif
}
#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
============================================================ */
#ifdef JS_PTR64
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)
#else /* 32-bit: no short float, use boxed double */
static inline JSValue __JS_NewFloat64 (JSContext *ctx,
double d); /* forward decl */
static inline double JS_VALUE_GET_FLOAT64 (JSValue v);
#define JS_TAG_IS_FLOAT64(tag) (0)
#define JS_NAN JS_MKVAL (JS_TAG_NULL, 0)
#endif /* JS_PTR64 */
/* ============================================================
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; }
#ifdef JS_PTR64
static inline JS_BOOL
JS_IsShortFloat (JSValue v) {
return (v & 7) == JS_TAG_SHORT_FLOAT;
}
#endif
#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_UNINITIALIZED ((JSValue)JS_TAG_UNINITIALIZED)
/* flags for object properties - simplified model:
- No per-property writable/configurable (use stone() for immutability)
- Text keys are enumerable, object keys are not */
#define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, VARREF */
#define JS_PROP_NORMAL (0 << 4)
#define JS_PROP_VARREF (2 << 4) /* used internally for closures */
#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);
typedef struct JSMallocState {
size_t malloc_count;
size_t malloc_size;
size_t malloc_limit;
void *opaque; /* user opaque */
} JSMallocState;
typedef struct JSMallocFunctions {
void *(*js_malloc) (JSMallocState *s, size_t size);
void (*js_free) (JSMallocState *s, void *ptr);
void *(*js_realloc) (JSMallocState *s, void *ptr, size_t size);
size_t (*js_malloc_usable_size) (const void *ptr);
} JSMallocFunctions;
typedef struct JSGCObjectHeader JSGCObjectHeader;
JSValue JS_Stone (JSContext *ctx, JSValue this_val);
JSRuntime *JS_NewRuntime (void);
/* info lifetime must exceed that of rt */
void JS_SetRuntimeInfo (JSRuntime *rt, const char *info);
void JS_SetMemoryLimit (JSRuntime *rt, size_t limit);
/* use 0 to disable maximum stack size check */
void JS_SetMaxStackSize (JSRuntime *rt, size_t stack_size);
/* should be called when changing thread to update the stack top value
used to check stack overflow. */
void JS_UpdateStackTop (JSRuntime *rt);
void JS_FreeRuntime (JSRuntime *rt);
void *JS_GetRuntimeOpaque (JSRuntime *rt);
void JS_SetRuntimeOpaque (JSRuntime *rt, void *opaque);
typedef void JS_MarkFunc (JSRuntime *rt, JSGCObjectHeader *gp);
/* JS_MarkValue is a no-op with copying GC (values are traced from roots) */
void JS_MarkValue (JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func);
JS_BOOL JS_IsLiveObject (JSRuntime *rt, JSValue obj);
JSContext *JS_NewContext (JSRuntime *rt);
void JS_FreeContext (JSContext *s);
JSContext *JS_DupContext (JSContext *ctx);
JSContext *JS_GetContext (JSRuntime *rt);
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);
JSContext *JS_NewContextWithHeapSize (JSRuntime *rt, size_t heap_size);
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 void JSClassFinalizer (JSRuntime *rt, JSValue val);
typedef void JSClassGCMark (JSRuntime *rt, JSValue val,
JS_MarkFunc *mark_func);
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;
JSClassGCMark *gc_mark;
/* if call != NULL, the object is a function */
JSClassCall *call;
} JSClassDef;
#define JS_INVALID_CLASS_ID 0
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 (JSRuntime *rt, JSClassID class_id,
const JSClassDef *class_def);
int JS_IsRegisteredClass (JSRuntime *rt, JSClassID class_id);
extern JSClassID js_class_id_alloc;
/* ============================================================
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.
============================================================ */
#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) {
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_NewCatchOffset (JSContext *ctx, int32_t val) {
return JS_MKVAL (JS_TAG_CATCH_OFFSET, 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);
}
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);
}
static inline JS_BOOL JS_IsUninitialized (JSValue v) {
return (JS_VALUE_GET_TAG (v) == JS_TAG_UNINITIALIZED);
}
/* Immediate 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;
}
static inline JS_BOOL JS_IsInteger (JSValue v) {
return JS_VALUE_GET_TAG (v) == JS_TAG_INT;
}
static inline JS_BOOL JS_IsObject (JSValue v) {
return JS_IsPtr (v);
}
JS_BOOL JS_IsArray(JSValue v);
JS_BOOL JS_IsRecord(JSValue v);
JS_BOOL JS_IsFunction(JSValue v);
JS_BOOL JS_IsCode(JSValue v);
JS_BOOL JS_IsForwarded(JSValue v);
JS_BOOL JS_IsFrame(JSValue v);
JS_BOOL JS_IsBlob(JSValue v);
JS_BOOL JS_IsText(JSValue v);
static JS_BOOL JS_IsStone(JSValue v);
// Fundamental
int JS_GetLength (JSContext *ctx, JSValue obj, int64_t *pres);
JSValue JS_Throw (JSContext *ctx, JSValue obj);
void JS_SetUncatchableException (JSContext *ctx, JS_BOOL flag);
JSValue JS_GetException (JSContext *ctx);
JS_BOOL JS_HasException (JSContext *ctx);
JS_BOOL JS_IsError (JSContext *ctx, JSValue val);
JSValue JS_NewError (JSContext *ctx);
JSValue __js_printf_like (2, 3)
JS_ThrowSyntaxError (JSContext *ctx, const char *fmt, ...);
JSValue __js_printf_like (2, 3)
JS_ThrowTypeError (JSContext *ctx, const char *fmt, ...);
JSValue __js_printf_like (2, 3)
JS_ThrowReferenceError (JSContext *ctx, const char *fmt, ...);
JSValue __js_printf_like (2, 3)
JS_ThrowRangeError (JSContext *ctx, const char *fmt, ...);
JSValue __js_printf_like (2, 3)
JS_ThrowInternalError (JSContext *ctx, const char *fmt, ...);
JSValue JS_ThrowOutOfMemory (JSContext *ctx);
JS_BOOL JS_StrictEq (JSContext *ctx, JSValue op1, JSValue op2);
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_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);
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);
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);
/* GC-safe push: takes pointer to array, updates it if array grows */
int JS_ArrayPush (JSContext *ctx, JSValue *arr_ptr, JSValue val);
JSValue JS_ArrayPop (JSContext *ctx, JSValue obj);
/* Intrinsic array operations - signatures match internal functions */
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);
/* Cell intrinsic functions - C API wrappers */
/* Core 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 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 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 functions */
JSValue JS_CellObject (JSContext *ctx, JSValue proto, JSValue props);
/* Format function */
JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue transformer);
/* Helper functions */
JSValue JS_NewArrayFrom (JSContext *ctx, int count, JSValue *values);
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);
// 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);
int JS_SetProperty (JSContext *ctx, JSValue this_obj, JSValue prop, JSValue val);
JSValue JS_GetPrototype (JSContext *ctx, 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);
// Indexed property access (works with arrays and objects)
JSValue JS_GetPropertyUint32 (JSContext *ctx, JSValue this_obj, uint32_t idx);
int JS_SetPropertyUint32 (JSContext *ctx, JSValue this_obj, uint32_t idx, JSValue val);
int JS_SetPropertyInt64 (JSContext *ctx, JSValue this_obj, int64_t idx, 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);
/* Compile source code to bytecode without executing.
'input' must be zero terminated i.e. input[input_len] = '\0'.
Returns unlinked bytecode on success, JS_EXCEPTION on error. */
JSValue JS_Compile (JSContext *ctx, const char *input, size_t input_len,
const char *filename);
/* Link compiled bytecode with environment and execute.
env should be stoned record or null.
Variables resolve: env first, then global intrinsics. */
JSValue JS_Integrate (JSContext *ctx, JSValue bytecode, JSValue env);
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 (JSRuntime *rt, JSInterruptHandler *cb,
void *opaque);
/* select which debug info is stripped from the compiled code */
#define JS_STRIP_SOURCE (1 << 0) /* strip source code */
#define JS_STRIP_DEBUG \
(1 << 1) /* strip all debug info including source code */
void JS_SetStripInfo (JSRuntime *rt, int flags);
int JS_GetStripInfo (JSRuntime *rt);
/* Object Writer/Reader (currently only used to handle precompiled code) */
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
#define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
#define JS_WRITE_OBJ_REFERENCE \
(1 << 3) /* allow object references to \
encode arbitrary object \
graph */
uint8_t *JS_WriteObject (JSContext *ctx, size_t *psize, JSValue obj,
int flags);
uint8_t *JS_WriteObject2 (JSContext *ctx, size_t *psize, JSValue obj,
int flags, uint8_t ***psab_tab,
size_t *psab_tab_len);
#define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */
#define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */
#define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
JSValue JS_ReadObject (JSContext *ctx, const uint8_t *buf, size_t buf_len,
int flags);
/* Dump bytecode of a compiled function (for debugging) */
void JS_DumpFunctionBytecode (JSContext *ctx, JSValue func_val);
/* 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 value output */
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, const uint8_t *cur_pc);
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, const uint8_t *cur_pc);
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);
/* Memory allocation functions (bump allocator) */
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);
void js_free (JSContext *ctx, void *ptr);
char *js_strdup (JSContext *ctx, const char *str);
/* Runtime-level memory functions */
void *js_malloc_rt (size_t size);
void *js_mallocz_rt (size_t size);
void js_free_rt (void *ptr);
/* ============================================================================
Context-Neutral Module Format (CellModule)
============================================================================ */
/* Capture descriptor - what a nested function closes over */
typedef enum {
CAP_FROM_PARENT_LOCAL = 1, /* capture local from parent function */
CAP_FROM_PARENT_UPVALUE = 2 /* forward upvalue from parent's upvalues */
} CellCapKind;
typedef struct CellCapDesc {
uint8_t kind; /* CAP_FROM_PARENT_LOCAL or CAP_FROM_PARENT_UPVALUE */
uint16_t index; /* local index in parent, or upvalue index in parent */
} CellCapDesc;
/* External relocation - for integrate-time patching */
typedef enum {
EXT_GET = 1, /* OP_get_var -> OP_get_env_slot or OP_get_global_slot */
EXT_SET = 2 /* OP_put_var -> OP_set_env_slot or OP_set_global_slot */
} CellExtKind;
typedef struct CellExternalReloc {
uint32_t pc_offset; /* where operand lives in bytecode */
uint32_t name_sid; /* string id of the external name */
uint8_t kind; /* EXT_GET or EXT_SET */
} CellExternalReloc;
/* Constant types in cpool */
typedef enum {
CELL_CONST_NULL = 0,
CELL_CONST_INT = 1,
CELL_CONST_FLOAT = 2,
CELL_CONST_STRING = 3, /* string_sid into module string table */
CELL_CONST_UNIT = 4 /* unit_id for nested function */
} CellConstType;
typedef struct CellConst {
uint8_t type; /* CellConstType */
union {
int32_t i32;
double f64;
uint32_t string_sid;
uint32_t unit_id;
};
} CellConst;
/* Per-unit structure (context-neutral, flattened) */
typedef struct CellUnit {
/* Constant pool */
uint32_t const_count;
CellConst *constants;
/* Bytecode */
uint32_t bytecode_len;
uint8_t *bytecode;
/* Stack requirements */
uint16_t arg_count;
uint16_t var_count;
uint16_t stack_size;
/* Upvalue (capture) descriptors */
uint16_t upvalue_count;
CellCapDesc *upvalues;
/* External relocations */
uint32_t external_count;
CellExternalReloc *externals;
/* Debug info (optional) */
uint32_t pc2line_len;
uint8_t *pc2line;
uint32_t name_sid; /* unit name for stack traces */
} CellUnit;
/* Module-level structure (context-neutral) */
#define CELL_MODULE_MAGIC 0x4C4C4543 /* "CELL" */
#define CELL_MODULE_VERSION 1
typedef struct CellModule {
uint32_t magic; /* CELL_MODULE_MAGIC */
uint8_t version; /* CELL_MODULE_VERSION */
uint8_t flags;
/* Shared string table (module-global) */
uint32_t string_count;
uint32_t string_data_size;
uint8_t *string_data; /* concatenated UTF-8 strings */
uint32_t *string_offsets; /* offset for each string */
/* Unit table (entry 0 is the main/entry unit) */
uint32_t unit_count;
CellUnit *units;
/* Debug: source stored once at module level */
uint32_t source_len;
char *source;
} CellModule;
/* Free a CellModule and all its contents */
void cell_module_free (CellModule *mod);
/* Write a CellModule to a byte buffer.
Returns allocated buffer (caller must free with pjs_free), or NULL on error. */
uint8_t *cell_module_write (CellModule *mod, size_t *out_len);
/* Read a CellModule from a byte buffer.
Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */
CellModule *cell_module_read (const uint8_t *buf, size_t buf_len);
/* Convert compiled JSFunctionBytecode to CellModule.
Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */
CellModule *cell_module_from_bytecode (JSContext *ctx, JSFunctionBytecode *main_func);
/* Compile source code directly to CellModule.
Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */
CellModule *JS_CompileModule (JSContext *ctx, const char *input, size_t input_len, const char *filename);
/* Parse source code and return AST as cJSON tree.
Caller must call cJSON_Delete() on result. */
struct cJSON *JS_ASTTree (const char *source, size_t len, const char *filename);
/* Parse source code and return AST as JSON string.
Returns malloc'd JSON string (caller must free), or NULL on error. */
char *JS_AST (const char *source, size_t len, const char *filename);
/* Tokenize source code and return token array as JSON string.
Returns malloc'd JSON string (caller must free), or NULL on error. */
char *JS_Tokenize (const char *source, size_t len, const char *filename);
/* Compiled bytecode (context-free, serializable) */
typedef struct MachCode MachCode;
/* Compile AST cJSON tree to context-free MachCode. */
MachCode *JS_CompileMachTree(struct cJSON *ast);
/* Compile AST JSON string to context-free MachCode. */
MachCode *JS_CompileMach(const char *ast_json);
/* Free a compiled MachCode tree. */
void JS_FreeMachCode(MachCode *mc);
/* Load compiled MachCode into a JSContext, materializing JSValues. */
struct JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env);
/* Dump MACH bytecode to stdout. Takes AST cJSON tree. */
void JS_DumpMachTree (JSContext *ctx, struct cJSON *ast, JSValue env);
/* Dump MACH bytecode to stdout. Takes AST JSON string. */
void JS_DumpMach (JSContext *ctx, const char *ast_json, JSValue env);
/* Compile and execute MACH bytecode from AST cJSON tree. */
JSValue JS_RunMachTree (JSContext *ctx, struct cJSON *ast, JSValue env);
/* Compile and execute MACH bytecode from AST JSON string. */
JSValue JS_RunMach (JSContext *ctx, const char *ast_json, JSValue env);
/* Compile AST cJSON tree to MCODE cJSON tree.
Caller must call cJSON_Delete() on result. */
struct cJSON *JS_McodeTree (struct cJSON *ast);
/* Compile AST JSON string to MCODE JSON string.
Returns malloc'd JSON string, or NULL on error. Caller must free. */
char *JS_Mcode (const char *ast_json);
/* Execute MCODE from cJSON tree. Takes ownership of root. */
JSValue JS_CallMcodeTree (JSContext *ctx, struct cJSON *root);
/* Parse and execute MCODE JSON string.
Returns result of execution, or JS_EXCEPTION on error. */
JSValue JS_CallMcode (JSContext *ctx, const char *mcode_json);
/* Get stack trace as cJSON array of frame objects.
Returns NULL if no register VM frame is active.
Caller must call cJSON_Delete() on the result. */
struct cJSON *JS_GetStack (JSContext *ctx);
/* Integrate a CellModule with an environment and execute.
Returns callable function value, or JS_EXCEPTION on error. */
JSValue cell_module_integrate (JSContext *ctx, CellModule *mod, JSValue env);
#undef js_unlikely
#undef inline
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* QUICKJS_H */