Files
cell/source/quickjs.h
2026-01-31 14:43:21 -06:00

1040 lines
38 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)
/*
NaN boxing is used, always. A value is the length of the word.
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 - has its own GC
typedef struct JSClass JSClass;
typedef uint32_t JSClassID;
/* ============================================================
Mist Value Encoding (LSB-based type discrimination)
============================================================
64-bit builds:
LSB = 0 → 31-bit signed integer (value >> 1)
LSB = 01 → 61-bit pointer (aligned, clear low 2 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 */
/* Object subtypes (stored in object header, not value) */
JS_TAG_STRING = -8, /* mist_text pointer */
JS_TAG_ARRAY = -6, /* JSArray pointer */
JS_TAG_FUNCTION = -5, /* JSFunction pointer */
JS_TAG_FUNCTION_BYTECODE = -2,
JS_TAG_OBJECT = -1, /* JSRecord/JSObject pointer */
/* Legacy - for gradual migration (to be removed) */
JS_TAG_FIRST = -10,
JS_TAG_FLOAT64 = 8, /* unused in new encoding */
};
typedef struct JSRefCountHeader {
int ref_count;
} JSRefCountHeader;
/* ============================================================
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 pointer (clear low bits) */
#define JS_VALUE_GET_PTR(v) ((void *)((v) & ~((JSValue)(JSW - 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)
#define JS_MKPTR(tag, ptr) (((JSValue)(uintptr_t)(ptr)) | JS_TAG_PTR)
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 */
if (exp == 0 && mantissa == 0) { return (sign << 63) | 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 sign ? -0.0 : 0.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;
}
static inline JS_BOOL
JS_VALUE_IS_NAN (JSValue v) {
return 0; /* NaN becomes NULL in Mist encoding */
}
#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);
static inline JS_BOOL
JS_VALUE_IS_NAN (JSValue v) {
return 0;
}
#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 & 3) == 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))
/* Pointer values have ref counts */
#define JS_VALUE_HAS_REF_COUNT(v) JS_IsPtr (v)
/* ============================================================
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
/* JS_Eval() flags */
#define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */
#define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */
#define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */
#define JS_EVAL_TYPE_MASK (3 << 0)
/* compile but do not run. The result is an object with a
JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
with JS_EvalFunction(). */
#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
/* don't include the stack frames before this eval in the Error() backtraces */
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
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);
int JS_IsStone (JSContext *ctx, JSValue 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);
void JS_SetGCThreshold (JSRuntime *rt, size_t gc_threshold);
/* 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);
JSRuntime *JS_NewRuntime2 (const JSMallocFunctions *mf, void *opaque);
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);
void JS_MarkValue (JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func);
void JS_RunGC (JSRuntime *rt);
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);
/* the following functions are used to select the intrinsic object to
save memory */
JSContext *JS_NewContextRaw (JSRuntime *rt);
void JS_AddIntrinsicBaseObjects (JSContext *ctx);
void JS_AddIntrinsicEval (JSContext *ctx);
void JS_AddIntrinsicRegExpCompiler (JSContext *ctx);
void JS_AddIntrinsicRegExp (JSContext *ctx);
void JS_AddIntrinsicJSON (JSContext *ctx);
JSValue js_string_codePointRange (JSContext *ctx, JSValue this_val,
int argc, JSValue *argv);
void *js_malloc_rt (JSRuntime *rt, size_t size);
void js_free_rt (JSRuntime *rt, void *ptr);
void *js_realloc_rt (JSRuntime *rt, void *ptr, size_t size);
size_t js_malloc_usable_size_rt (JSRuntime *rt, const void *ptr);
void *js_mallocz_rt (JSRuntime *rt, size_t size);
void *js_malloc (JSContext *ctx, size_t size);
void js_free (JSContext *ctx, void *ptr);
void *js_realloc (JSContext *ctx, void *ptr, size_t size);
size_t js_malloc_usable_size (JSContext *ctx, const void *ptr);
void *js_realloc2 (JSContext *ctx, void *ptr, size_t size, size_t *pslack);
void *js_mallocz (JSContext *ctx, size_t size);
char *js_strdup (JSContext *ctx, const char *str);
char *js_strndup (JSContext *ctx, const char *s, size_t n);
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;
/* 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;
}
JS_BOOL JS_IsString (JSValue v);
JS_BOOL JS_IsText (JSValue v);
/* Symbols removed in Mist encoding */
/* JS_IsFunction - check if value is a callable function.
With new tagging, must check gc_obj_type in JSGCObjectHeader. */
JS_BOOL JS_IsFunction (JSValue v);
static inline JS_BOOL
JS_IsInteger (JSValue v) {
return JS_VALUE_GET_TAG (v) == JS_TAG_INT;
}
/* JS_IsObject - check if value is a settable object (record or array).
With new tagging, must check gc_obj_type in JSGCObjectHeader. */
JS_BOOL JS_IsObject (JSValue v);
int JS_IsArray (JSContext *ctx, JSValue val);
// 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);
void __JS_FreeValue (JSContext *ctx, JSValue v);
static inline void
JS_FreeValue (JSContext *ctx, JSValue v) {
if (JS_VALUE_HAS_REF_COUNT (v)) {
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR (v);
if (--p->ref_count <= 0) { __JS_FreeValue (ctx, v); }
}
}
void __JS_FreeValueRT (JSRuntime *rt, JSValue v);
static inline void
JS_FreeValueRT (JSRuntime *rt, JSValue v) {
if (JS_VALUE_HAS_REF_COUNT (v)) {
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR (v);
if (--p->ref_count <= 0) { __JS_FreeValueRT (rt, v); }
}
}
static inline JSValue
JS_DupValue (JSContext *ctx, JSValue v) {
if (JS_VALUE_HAS_REF_COUNT (v)) {
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR (v);
p->ref_count++;
}
return (JSValue)v;
}
static inline JSValue
JS_DupValueRT (JSRuntime *rt, JSValue v) {
if (JS_VALUE_HAS_REF_COUNT (v)) {
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR (v);
p->ref_count++;
}
return (JSValue)v;
}
JS_BOOL JS_StrictEq (JSContext *ctx, JSValue op1, JSValue op2);
JS_BOOL JS_SameValue (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);
int JS_ArrayPush (JSContext *ctx, JSValue obj, JSValue val);
JSValue JS_ArrayPop (JSContext *ctx, JSValue obj);
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);
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
JSValue JS_Eval (JSContext *ctx, const char *input, size_t input_len,
const char *filename, int eval_flags);
/* same as JS_Eval() but with an explicit 'this_obj' parameter */
JSValue JS_EvalThis (JSContext *ctx, JSValue this_obj, const char *input,
size_t input_len, const char *filename, int eval_flags);
JSValue JS_GetGlobalObject (JSContext *ctx);
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);
/* instantiate and evaluate a bytecode function. Only used when
reading a script or module with JS_ReadObject() */
JSValue JS_EvalFunction (JSContext *ctx, JSValue fun_obj);
/* 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
} 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);
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;
} 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 } } } \
}
#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);
#undef js_unlikely
#undef inline
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* QUICKJS_H */