/* * 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) /* 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_SYMBOL = -9, /* DEPRECATED - symbols 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 */ static inline JS_BOOL JS_IsFunction (JSValue v) { return JS_VALUE_GET_TAG (v) == JS_TAG_FUNCTION; } 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_VALUE_GET_TAG (v) == JS_TAG_OBJECT; } 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 JSValue strings */ int JS_GetOwnPropertyNames (JSContext *ctx, JSValue **tab, uint32_t *plen, 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 */