before gc rewrite
This commit is contained in:
595
source/quickjs.c
595
source/quickjs.c
@@ -499,7 +499,9 @@ typedef struct mist_blob {
|
||||
Packed: 2 UTF32 per word, high 32 then low 32.
|
||||
*/
|
||||
typedef struct mist_text {
|
||||
objhdr_t hdr;
|
||||
JSRefCountHeader _dummy_header; /* unused, for offset alignment with JSString */
|
||||
uint32_t _pad; /* padding to align objhdr_t to offset 8 */
|
||||
objhdr_t hdr; /* NOW at offset 8, like JSString */
|
||||
word_t length;
|
||||
word_t packed[]; // count = (cap + 1)/2
|
||||
} mist_text;
|
||||
@@ -1045,7 +1047,9 @@ static JSValue intern_text_to_value (JSContext *ctx, const uint32_t *utf32,
|
||||
mist_text *text = st_alloc (ctx, text_size, 8);
|
||||
if (!text) return JS_NULL; /* OOM */
|
||||
|
||||
/* Initialize the text */
|
||||
/* Initialize the text (with unified layout: hdr at offset 8) */
|
||||
text->_dummy_header.ref_count = 1; /* dummy, not used for GC */
|
||||
text->_pad = 0;
|
||||
text->hdr = objhdr_make (len, OBJ_TEXT, false, false, false,
|
||||
true); /* s=1 for stoned */
|
||||
text->length = hash; /* Store hash in length field for stoned text */
|
||||
@@ -1165,17 +1169,17 @@ static void rc_dump_atom (JSRuntime *rt, uint32_t atom) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* JS_IsString implementation: checks for immediate string or OBJ_TEXT pointer
|
||||
*/
|
||||
JS_BOOL
|
||||
JS_IsString (JSValue v) {
|
||||
/* JS_IsString implementation: checks for immediate string or OBJ_TEXT pointer.
|
||||
Both mist_text and JSString now have objhdr_t at offset 8. */
|
||||
JS_BOOL JS_IsString (JSValue v) {
|
||||
/* Check tag - immediate string? */
|
||||
if (MIST_IsImmediateASCII (v)) return 1;
|
||||
|
||||
/* Check pointer type */
|
||||
if (JS_IsPtr (v)) {
|
||||
void *ptr = JS_VALUE_GET_PTR (v);
|
||||
objhdr_t hdr = *(objhdr_t *)ptr;
|
||||
/* objhdr_t is at offset 8 (after dummy header/pad) */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
return objhdr_type (hdr) == OBJ_TEXT;
|
||||
}
|
||||
return 0;
|
||||
@@ -1199,7 +1203,7 @@ static inline uint8_t JS_VALUE_GET_MIST_TYPE (JSValue v) {
|
||||
|
||||
/* Check if a JSValue points to a mist-based object (has mist_hdr) */
|
||||
static inline JS_BOOL JS_VALUE_IS_MIST (JSValue v) {
|
||||
if (JS_VALUE_GET_TAG (v) != JS_TAG_OBJECT) return FALSE;
|
||||
if (!JS_IsPtr (v)) return FALSE;
|
||||
JSMistBase *p = (JSMistBase *)JS_VALUE_GET_PTR (v);
|
||||
uint8_t type = objhdr_type (p->mist_hdr);
|
||||
return type != 0;
|
||||
@@ -1279,7 +1283,7 @@ typedef struct JSRecord {
|
||||
|
||||
/* Check if a JSValue is a JSRecord */
|
||||
static inline JS_BOOL JS_VALUE_IS_RECORD (JSValue v) {
|
||||
if (JS_VALUE_GET_TAG (v) != JS_TAG_OBJECT) return FALSE;
|
||||
if (!JS_IsPtr (v)) return FALSE;
|
||||
return ((JSGCObjectHeader *)JS_VALUE_GET_PTR (v))->gc_obj_type
|
||||
== JS_GC_OBJ_TYPE_RECORD;
|
||||
}
|
||||
@@ -1303,10 +1307,17 @@ static uint64_t js_key_hash (JSValue key) {
|
||||
if (!JS_IsPtr (key)) return 0;
|
||||
|
||||
void *ptr = JS_VALUE_GET_PTR (key);
|
||||
objhdr_t hdr = *(objhdr_t *)ptr;
|
||||
|
||||
/* Both mist_text and JSString now have objhdr_t at offset 8.
|
||||
JSRecord and JSArray also have mist_hdr at offset 8. */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
uint8_t type = objhdr_type (hdr);
|
||||
|
||||
if (type == OBJ_TEXT) return get_text_hash ((mist_text *)ptr);
|
||||
if (type == OBJ_TEXT) {
|
||||
/* For mist_text (stoned strings), use get_text_hash */
|
||||
mist_text *text = (mist_text *)ptr;
|
||||
return get_text_hash (text);
|
||||
}
|
||||
if (type == OBJ_RECORD) {
|
||||
JSRecord *rec = (JSRecord *)ptr;
|
||||
if (rec->rec_id == 0) return 0;
|
||||
@@ -1337,14 +1348,15 @@ static JS_BOOL js_key_equal (JSValue a, JSValue b) {
|
||||
|
||||
void *pa = JS_VALUE_GET_PTR (a);
|
||||
void *pb = JS_VALUE_GET_PTR (b);
|
||||
objhdr_t ha = *(objhdr_t *)pa;
|
||||
objhdr_t hb = *(objhdr_t *)pb;
|
||||
uint8_t ta = objhdr_type (ha);
|
||||
uint8_t tb = objhdr_type (hb);
|
||||
/* objhdr_t is at offset 8 for all heap objects (mist_text, JSString, JSRecord) */
|
||||
objhdr_t ha = *((objhdr_t *)((char *)pa + 8));
|
||||
objhdr_t hb = *((objhdr_t *)((char *)pb + 8));
|
||||
uint8_t type_a = objhdr_type (ha);
|
||||
uint8_t type_b = objhdr_type (hb);
|
||||
|
||||
if (ta != tb) return FALSE;
|
||||
if (ta == OBJ_RECORD) return FALSE; /* pointer equality handled above */
|
||||
if (ta == OBJ_TEXT)
|
||||
if (type_a != type_b) return FALSE;
|
||||
if (type_a == OBJ_RECORD) return FALSE; /* pointer equality handled above */
|
||||
if (type_a == OBJ_TEXT)
|
||||
return mist_text_equal ((mist_text *)pa, (mist_text *)pb);
|
||||
|
||||
return FALSE;
|
||||
@@ -1630,11 +1642,73 @@ typedef struct JSFunction {
|
||||
#define JS_VALUE_GET_ARRAY(v) ((JSArray *)JS_VALUE_GET_PTR (v))
|
||||
#define JS_VALUE_GET_FUNCTION(v) ((JSFunction *)JS_VALUE_GET_PTR (v))
|
||||
|
||||
/* Check if a JSValue is an intrinsic array (JS_TAG_OBJECT with OBJ_ARRAY mist
|
||||
* type) */
|
||||
/* ============================================================
|
||||
Pointer Type Checking Helpers
|
||||
============================================================
|
||||
With the new tagging system, JS_VALUE_GET_TAG returns JS_TAG_PTR
|
||||
for all pointer types. To distinguish objects, arrays, functions,
|
||||
etc., we check the gc_obj_type field in JSGCObjectHeader.
|
||||
============================================================ */
|
||||
|
||||
/* Check if value is a GC object (record, array, function, etc) */
|
||||
static inline JS_BOOL js_is_gc_object (JSValue v) {
|
||||
return JS_IsPtr (v);
|
||||
}
|
||||
|
||||
/* Get gc_obj_type from a pointer JSValue */
|
||||
static inline JSGCObjectTypeEnum js_get_gc_type (JSValue v) {
|
||||
return ((JSGCObjectHeader *)JS_VALUE_GET_PTR (v))->gc_obj_type;
|
||||
}
|
||||
|
||||
/* Check if value is a Record (JS_GC_OBJ_TYPE_RECORD) */
|
||||
static inline JS_BOOL js_is_record (JSValue v) {
|
||||
if (!JS_IsPtr (v)) return FALSE;
|
||||
return js_get_gc_type (v) == JS_GC_OBJ_TYPE_RECORD;
|
||||
}
|
||||
|
||||
/* Check if value is an Array (JS_GC_OBJ_TYPE_ARRAY) */
|
||||
static inline JS_BOOL js_is_array (JSValue v) {
|
||||
if (!JS_IsPtr (v)) return FALSE;
|
||||
return js_get_gc_type (v) == JS_GC_OBJ_TYPE_ARRAY;
|
||||
}
|
||||
|
||||
/* Check if value is a Function (JS_GC_OBJ_TYPE_FUNCTION) */
|
||||
static inline JS_BOOL js_is_function (JSValue v) {
|
||||
if (!JS_IsPtr (v)) return FALSE;
|
||||
return js_get_gc_type (v) == JS_GC_OBJ_TYPE_FUNCTION;
|
||||
}
|
||||
|
||||
/* Check if value is a FunctionBytecode (JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) */
|
||||
static inline JS_BOOL js_is_function_bytecode (JSValue v) {
|
||||
if (!JS_IsPtr (v)) return FALSE;
|
||||
return js_get_gc_type (v) == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE;
|
||||
}
|
||||
|
||||
/* Check if value is an "object" - record or array (can have properties set) */
|
||||
static inline JS_BOOL js_is_object (JSValue v) {
|
||||
if (!JS_IsPtr (v)) return FALSE;
|
||||
JSGCObjectTypeEnum t = js_get_gc_type (v);
|
||||
return t == JS_GC_OBJ_TYPE_RECORD || t == JS_GC_OBJ_TYPE_ARRAY;
|
||||
}
|
||||
|
||||
/* Check if value is a callable (function) */
|
||||
static inline JS_BOOL js_is_callable (JSValue v) {
|
||||
return js_is_function (v);
|
||||
}
|
||||
|
||||
/* Check if a JSValue is an intrinsic array (OBJ_ARRAY via gc_obj_type) */
|
||||
static inline JS_BOOL JS_VALUE_IS_INTRINSIC_ARRAY (JSValue v) {
|
||||
if (JS_VALUE_GET_TAG (v) != JS_TAG_OBJECT) return FALSE;
|
||||
return JS_VALUE_GET_MIST_TYPE (v) == OBJ_ARRAY;
|
||||
return js_is_array (v);
|
||||
}
|
||||
|
||||
/* Public API: check if value is a function */
|
||||
JS_BOOL JS_IsFunction (JSValue v) {
|
||||
return js_is_function (v);
|
||||
}
|
||||
|
||||
/* Public API: check if value is an object (record or array) */
|
||||
JS_BOOL JS_IsObject (JSValue v) {
|
||||
return js_is_object (v);
|
||||
}
|
||||
|
||||
typedef struct JSClosureVar {
|
||||
@@ -1839,8 +1913,7 @@ static void gc_decref_child (JSRuntime *rt, JSGCObjectHeader *p);
|
||||
Internal use only. */
|
||||
int JS_SetPropertyInternal (JSContext *ctx, JSValue this_obj, JSValue prop,
|
||||
JSValue val) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (this_obj);
|
||||
if (tag != JS_TAG_OBJECT) {
|
||||
if (!js_is_object (this_obj)) {
|
||||
JS_FreeValue (ctx, val);
|
||||
return -1;
|
||||
}
|
||||
@@ -2337,6 +2410,9 @@ static JSString *js_alloc_string_rt (JSRuntime *rt, int max_len) {
|
||||
str = js_malloc_rt (rt, size);
|
||||
if (unlikely (!str)) return NULL;
|
||||
str->header.ref_count = 1;
|
||||
str->pad = 0;
|
||||
/* Initialize objhdr_t with OBJ_TEXT type so JS_IsString can detect it */
|
||||
str->hdr = objhdr_make (max_len, OBJ_TEXT, false, false, false, false);
|
||||
str->len = max_len;
|
||||
// Initialize content to 0?
|
||||
// memset(str->u, 0, data_words * sizeof(uint64_t));
|
||||
@@ -2801,7 +2877,7 @@ JSClassID JS_NewClassID (JSClassID *pclass_id) {
|
||||
|
||||
JSClassID JS_GetClassID (JSValue v) {
|
||||
JSRecord *rec;
|
||||
if (JS_VALUE_GET_TAG (v) != JS_TAG_OBJECT) return JS_INVALID_CLASS_ID;
|
||||
if (!js_is_record (v)) return JS_INVALID_CLASS_ID;
|
||||
rec = JS_VALUE_GET_RECORD (v);
|
||||
return rec->class_id;
|
||||
}
|
||||
@@ -3519,7 +3595,7 @@ static JSValue JS_ConcatString (JSContext *ctx, JSValue op1, JSValue op2) {
|
||||
}
|
||||
|
||||
static JSRecord *get_proto_obj (JSValue proto_val) {
|
||||
if (JS_VALUE_GET_TAG (proto_val) != JS_TAG_OBJECT)
|
||||
if (!js_is_record (proto_val))
|
||||
return NULL;
|
||||
else
|
||||
return JS_VALUE_GET_OBJ (proto_val);
|
||||
@@ -3532,8 +3608,7 @@ JSValue JS_NewObjectProtoClass (JSContext *ctx, JSValue proto_val,
|
||||
if (!rec) return JS_EXCEPTION;
|
||||
|
||||
/* Set prototype if provided */
|
||||
if (JS_VALUE_GET_TAG (proto_val) == JS_TAG_OBJECT
|
||||
&& JS_VALUE_IS_RECORD (proto_val)) {
|
||||
if (js_is_record (proto_val)) {
|
||||
rec->proto = JS_VALUE_GET_RECORD (proto_val);
|
||||
}
|
||||
|
||||
@@ -4035,12 +4110,10 @@ static void free_zero_refcount (JSRuntime *rt) {
|
||||
|
||||
/* called with the ref_count of 'v' reaches zero. */
|
||||
void __JS_FreeValueRT (JSRuntime *rt, JSValue v) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (v);
|
||||
|
||||
#ifdef DUMP_FREE
|
||||
{
|
||||
printf ("Freeing ");
|
||||
if (tag == JS_TAG_OBJECT) {
|
||||
if (js_is_record (v)) {
|
||||
JS_DumpObject (rt, JS_VALUE_GET_RECORD (v));
|
||||
} else {
|
||||
JS_DumpValueShort (rt, v);
|
||||
@@ -4049,33 +4122,52 @@ void __JS_FreeValueRT (JSRuntime *rt, JSValue v) {
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (tag) {
|
||||
case JS_TAG_STRING: {
|
||||
JSString *p = JS_VALUE_GET_STRING (v);
|
||||
/* atom_type removed - strings are no longer atoms */
|
||||
/* New tag system: JS_TAG_PTR for all pointer types */
|
||||
if (JS_IsPtr (v)) {
|
||||
void *ptr = JS_VALUE_GET_PTR (v);
|
||||
|
||||
/* Check objhdr_t at offset 8 to determine type.
|
||||
Both strings (mist_text/JSString) and GC objects have objhdr_t at offset 8. */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
uint8_t type = objhdr_type (hdr);
|
||||
|
||||
/* Handle heap strings - type is OBJ_TEXT */
|
||||
if (type == OBJ_TEXT) {
|
||||
/* Check if this is a stone-allocated mist_text (don't free) or
|
||||
a heap-allocated JSString (do free) */
|
||||
if (objhdr_s (hdr)) {
|
||||
/* Stone-allocated mist_text - don't free (lives in stone arena) */
|
||||
return;
|
||||
}
|
||||
/* Heap-allocated JSString - free it */
|
||||
JSString *str = (JSString *)ptr;
|
||||
#ifdef DUMP_LEAKS
|
||||
list_del (&p->link);
|
||||
list_del (&str->link);
|
||||
#endif
|
||||
js_free_rt (rt, p);
|
||||
} break;
|
||||
case JS_TAG_STRING_IMM:
|
||||
/* Immediate strings do not need freeing */
|
||||
break;
|
||||
case JS_TAG_OBJECT: /* includes arrays (OBJ_ARRAY), functions, etc. via
|
||||
mist_hdr */
|
||||
case JS_TAG_FUNCTION_BYTECODE:
|
||||
case JS_TAG_FUNCTION: {
|
||||
JSGCObjectHeader *p = JS_VALUE_GET_PTR (v);
|
||||
js_free_rt (rt, str);
|
||||
return;
|
||||
}
|
||||
|
||||
/* GC objects: record, array, function, function_bytecode, var_ref, etc. */
|
||||
JSGCObjectHeader *p = (JSGCObjectHeader *)ptr;
|
||||
if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
|
||||
list_del (&p->link);
|
||||
list_add (&p->link, &rt->gc_zero_ref_count_list);
|
||||
p->mark = 1; /* indicate that the object is about to be freed */
|
||||
if (rt->gc_phase == JS_GC_PHASE_NONE) { free_zero_refcount (rt); }
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
abort ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Non-pointer values that shouldn't reach here (except immediate strings) */
|
||||
uint32_t tag = JS_VALUE_GET_TAG (v);
|
||||
if (tag == JS_TAG_STRING_IMM) {
|
||||
/* Immediate strings do not need freeing */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unexpected value type */
|
||||
abort ();
|
||||
}
|
||||
|
||||
void __JS_FreeValue (JSContext *ctx, JSValue v) {
|
||||
@@ -4094,15 +4186,14 @@ static void add_gc_object (JSRuntime *rt, JSGCObjectHeader *h,
|
||||
static void remove_gc_object (JSGCObjectHeader *h) { list_del (&h->link); }
|
||||
|
||||
void JS_MarkValue (JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) {
|
||||
if (JS_VALUE_HAS_REF_COUNT (val)) {
|
||||
switch (JS_VALUE_GET_TAG (val)) {
|
||||
case JS_TAG_OBJECT: /* includes arrays (OBJ_ARRAY) via mist_hdr */
|
||||
case JS_TAG_FUNCTION_BYTECODE:
|
||||
case JS_TAG_FUNCTION:
|
||||
mark_func (rt, JS_VALUE_GET_PTR (val));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (JS_IsPtr (val)) {
|
||||
void *ptr = JS_VALUE_GET_PTR (val);
|
||||
/* Check objhdr_t at offset 8 to determine type */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
uint8_t type = objhdr_type (hdr);
|
||||
/* Only mark GC objects (not OBJ_TEXT strings) */
|
||||
if (type != OBJ_TEXT) {
|
||||
mark_func (rt, (JSGCObjectHeader *)ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4227,22 +4318,21 @@ static inline void JS_MarkValueEdgeEx (JSRuntime *rt, JSValue val,
|
||||
JSGCObjectHeader *parent,
|
||||
const char *edge, uint32_t atom,
|
||||
int32_t prop_index) {
|
||||
if (!JS_VALUE_HAS_REF_COUNT (val)) { return; }
|
||||
if (!JS_IsPtr (val)) { return; }
|
||||
|
||||
switch (JS_VALUE_GET_TAG (val)) {
|
||||
case JS_TAG_OBJECT: /* includes arrays (OBJ_ARRAY) via mist_hdr */
|
||||
case JS_TAG_FUNCTION_BYTECODE:
|
||||
case JS_TAG_FUNCTION: {
|
||||
JSGCObjectHeader *child = JS_VALUE_GET_PTR (val);
|
||||
void *ptr = JS_VALUE_GET_PTR (val);
|
||||
/* Check objhdr_t at offset 8 to determine type */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
uint8_t type = objhdr_type (hdr);
|
||||
/* Only mark GC objects (not OBJ_TEXT strings) */
|
||||
if (type != OBJ_TEXT) {
|
||||
JSGCObjectHeader *child = (JSGCObjectHeader *)ptr;
|
||||
#ifdef RC_TRACE
|
||||
gc_decref_child_dbg (rt, parent, edge, atom, prop_index, child, __FILE__,
|
||||
__LINE__);
|
||||
#else
|
||||
gc_decref_child (rt, child);
|
||||
#endif
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4875,7 +4965,7 @@ fail:
|
||||
when dumping the stack trace or in debug print). */
|
||||
static const char *get_prop_string (JSContext *ctx, JSValue obj,
|
||||
JSValue prop) {
|
||||
if (JS_VALUE_GET_TAG (obj) != JS_TAG_OBJECT) return NULL;
|
||||
if (!js_is_record (obj)) return NULL;
|
||||
JSRecord *rec = (JSRecord *)JS_VALUE_GET_OBJ (obj);
|
||||
|
||||
int slot = rec_find_slot (rec, prop);
|
||||
@@ -4890,7 +4980,7 @@ static const char *get_prop_string (JSContext *ctx, JSValue obj,
|
||||
}
|
||||
|
||||
JSValue val = rec->tab[slot].val;
|
||||
if (JS_VALUE_GET_TAG (val) != JS_TAG_STRING) return NULL;
|
||||
if (!JS_IsString (val)) return NULL;
|
||||
return JS_ToCString (ctx, val);
|
||||
}
|
||||
|
||||
@@ -4898,7 +4988,7 @@ static const char *get_prop_string (JSContext *ctx, JSValue obj,
|
||||
generation, we only look at simple 'name' properties containing a
|
||||
string. */
|
||||
static const char *get_func_name (JSContext *ctx, JSValue func) {
|
||||
if (JS_VALUE_GET_TAG (func) != JS_TAG_OBJECT) return NULL;
|
||||
if (!js_is_record (func)) return NULL;
|
||||
JSRecord *rec = (JSRecord *)JS_VALUE_GET_OBJ (func);
|
||||
|
||||
/* Create "name" key as immediate ASCII string */
|
||||
@@ -4908,7 +4998,7 @@ static const char *get_func_name (JSContext *ctx, JSValue func) {
|
||||
if (slot <= 0) return NULL;
|
||||
|
||||
JSValue val = rec->tab[slot].val;
|
||||
if (JS_VALUE_GET_TAG (val) != JS_TAG_STRING) return NULL;
|
||||
if (!JS_IsString (val)) return NULL;
|
||||
return JS_ToCString (ctx, val);
|
||||
}
|
||||
|
||||
@@ -5008,7 +5098,7 @@ static void build_backtrace (JSContext *ctx, JSValue error_obj,
|
||||
/* Note: it is important that no exception is returned by this function */
|
||||
static BOOL is_backtrace_needed (JSContext *ctx, JSValue obj) {
|
||||
JSRecord *p;
|
||||
if (JS_VALUE_GET_TAG (obj) != JS_TAG_OBJECT) return FALSE;
|
||||
if (!js_is_record (obj)) return FALSE;
|
||||
p = JS_VALUE_GET_OBJ (obj);
|
||||
if (p->class_id != JS_CLASS_ERROR) return FALSE;
|
||||
/* Check if "stack" property already exists */
|
||||
@@ -5194,7 +5284,7 @@ static inline __exception int js_poll_interrupts (JSContext *ctx) {
|
||||
/* Return an Object, JS_NULL or JS_EXCEPTION in case of exotic object. */
|
||||
JSValue JS_GetPrototype (JSContext *ctx, JSValue obj) {
|
||||
JSValue val;
|
||||
if (JS_VALUE_GET_TAG (obj) == JS_TAG_OBJECT) {
|
||||
if (js_is_record (obj)) {
|
||||
JSRecord *p;
|
||||
p = JS_VALUE_GET_OBJ (obj);
|
||||
p = JS_OBJ_GET_PROTO (p);
|
||||
@@ -5218,18 +5308,12 @@ static JSValue JS_GetPrototypeFree (JSContext *ctx, JSValue obj) {
|
||||
|
||||
/* Get property from object using JSRecord-based lookup */
|
||||
JSValue JS_GetProperty (JSContext *ctx, JSValue obj, JSValue prop) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (obj);
|
||||
if (JS_IsNull (obj)) return JS_NULL;
|
||||
if (JS_IsException (obj)) return JS_EXCEPTION;
|
||||
|
||||
if (unlikely (tag != JS_TAG_OBJECT)) {
|
||||
switch (tag) {
|
||||
case JS_TAG_NULL:
|
||||
return JS_NULL;
|
||||
case JS_TAG_EXCEPTION:
|
||||
return JS_EXCEPTION;
|
||||
default:
|
||||
/* Primitives have no properties */
|
||||
return JS_NULL;
|
||||
}
|
||||
if (unlikely (!js_is_object (obj))) {
|
||||
/* Primitives have no properties */
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
/* All objects are JSRecords now */
|
||||
@@ -5244,7 +5328,7 @@ JSValue JS_GetOwnPropertyNames (JSContext *ctx, JSValue obj) {
|
||||
uint32_t mask, count, i;
|
||||
JSValue arr;
|
||||
|
||||
if (JS_VALUE_GET_TAG (obj) != JS_TAG_OBJECT) {
|
||||
if (!js_is_record (obj)) {
|
||||
JS_ThrowTypeErrorNotAnObject (ctx);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
@@ -5287,7 +5371,7 @@ static int JS_GetOwnPropertyInternal (JSContext *ctx,
|
||||
}
|
||||
|
||||
int JS_GetOwnProperty (JSContext *ctx, JSValue *desc, JSValue obj, JSValue prop) {
|
||||
if (JS_VALUE_GET_TAG (obj) != JS_TAG_OBJECT) {
|
||||
if (!js_is_record (obj)) {
|
||||
JS_ThrowTypeErrorNotAnObject (ctx);
|
||||
return -1;
|
||||
}
|
||||
@@ -5298,7 +5382,7 @@ int JS_GetOwnProperty (JSContext *ctx, JSValue *desc, JSValue obj, JSValue prop)
|
||||
int JS_HasProperty (JSContext *ctx, JSValue obj, JSValue prop) {
|
||||
JSRecord *p;
|
||||
int ret;
|
||||
if (unlikely (JS_VALUE_GET_TAG (obj) != JS_TAG_OBJECT)) return FALSE;
|
||||
if (unlikely (!js_is_record (obj))) return FALSE;
|
||||
p = JS_VALUE_GET_OBJ (obj);
|
||||
for (;;) {
|
||||
/* JS_GetOwnPropertyInternal can free the prototype */
|
||||
@@ -5313,9 +5397,15 @@ int JS_HasProperty (JSContext *ctx, JSValue obj, JSValue prop) {
|
||||
}
|
||||
|
||||
static uint32_t js_string_get_length (JSValue val) {
|
||||
if (JS_VALUE_GET_TAG (val) == JS_TAG_STRING) {
|
||||
JSString *p = JS_VALUE_GET_STRING (val);
|
||||
return p->len;
|
||||
if (JS_IsPtr (val)) {
|
||||
void *ptr = JS_VALUE_GET_PTR (val);
|
||||
/* Check objhdr_t at offset 8 for type */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
if (objhdr_type (hdr) == OBJ_TEXT) {
|
||||
/* String (JSString or mist_text) */
|
||||
return (uint32_t)objhdr_cap56 (hdr);
|
||||
}
|
||||
return 0;
|
||||
} else if (MIST_IsImmediateASCII (val)) {
|
||||
return MIST_GetImmediateASCIILen (val);
|
||||
} else {
|
||||
@@ -5327,9 +5417,8 @@ static JSValue JS_GetPropertyValue (JSContext *ctx, JSValue this_obj,
|
||||
JSValue prop) {
|
||||
JSValue ret;
|
||||
uint32_t prop_tag = JS_VALUE_GET_TAG (prop);
|
||||
int this_tag = JS_VALUE_GET_TAG (this_obj);
|
||||
|
||||
if (this_tag == JS_TAG_NULL) {
|
||||
if (JS_IsNull (this_obj)) {
|
||||
JS_FreeValue (ctx, prop);
|
||||
return JS_NULL;
|
||||
}
|
||||
@@ -5340,7 +5429,7 @@ static JSValue JS_GetPropertyValue (JSContext *ctx, JSValue this_obj,
|
||||
return JS_GetPropertyNumber (ctx, this_obj, idx);
|
||||
}
|
||||
|
||||
if (prop_tag == JS_TAG_FLOAT64) {
|
||||
if (prop_tag == JS_TAG_SHORT_FLOAT) {
|
||||
double d = JS_VALUE_GET_FLOAT64 (prop);
|
||||
uint32_t idx = (uint32_t)d;
|
||||
JS_FreeValue (ctx, prop);
|
||||
@@ -5348,9 +5437,10 @@ static JSValue JS_GetPropertyValue (JSContext *ctx, JSValue this_obj,
|
||||
return JS_GetPropertyNumber (ctx, this_obj, idx);
|
||||
}
|
||||
|
||||
if (prop_tag == JS_TAG_STRING || prop_tag == JS_TAG_STRING_IMM) {
|
||||
/* Check for string property (immediate or heap) */
|
||||
if (JS_IsString (prop)) {
|
||||
/* Intrinsic arrays don't support string keys */
|
||||
if (JS_VALUE_IS_INTRINSIC_ARRAY (this_obj)) {
|
||||
if (js_is_array (this_obj)) {
|
||||
JS_FreeValue (ctx, prop);
|
||||
return JS_NULL;
|
||||
}
|
||||
@@ -5363,9 +5453,9 @@ static JSValue JS_GetPropertyValue (JSContext *ctx, JSValue this_obj,
|
||||
}
|
||||
|
||||
/* Handle object keys directly via objkey map */
|
||||
if (prop_tag == JS_TAG_OBJECT) {
|
||||
if (js_is_record (prop)) {
|
||||
/* Intrinsic arrays don't support object keys */
|
||||
if (this_tag != JS_TAG_OBJECT || JS_VALUE_IS_INTRINSIC_ARRAY (this_obj)) {
|
||||
if (!js_is_record (this_obj)) {
|
||||
JS_FreeValue (ctx, prop);
|
||||
return JS_NULL;
|
||||
}
|
||||
@@ -5400,17 +5490,16 @@ JSValue JS_SetPropertyNumber (JSContext *js, JSValue obj, int idx,
|
||||
}
|
||||
|
||||
JSValue JS_GetPropertyNumber (JSContext *js, JSValue obj, int idx) {
|
||||
if (JS_VALUE_IS_INTRINSIC_ARRAY (obj)) {
|
||||
if (js_is_array (obj)) {
|
||||
JSArray *a = JS_VALUE_GET_ARRAY (obj);
|
||||
int len = a->len;
|
||||
if (idx < 0 || idx >= len) { return JS_NULL; }
|
||||
return JS_DupValue (js, a->values[idx]);
|
||||
}
|
||||
|
||||
if (JS_VALUE_GET_TAG (obj) == JS_TAG_STRING
|
||||
|| JS_VALUE_GET_TAG (obj) == JS_TAG_STRING_IMM) {
|
||||
if (JS_IsString (obj)) {
|
||||
uint32_t len = js_string_get_length (obj);
|
||||
if (idx < 0 || idx >= len) { return JS_NULL; }
|
||||
if (idx < 0 || (uint32_t)idx >= len) { return JS_NULL; }
|
||||
return js_sub_string (js, JS_VALUE_GET_STRING (obj), idx, idx + 1);
|
||||
}
|
||||
|
||||
@@ -5486,11 +5575,9 @@ static int delete_property (JSContext *ctx, JSRecord *rec, JSValue key) {
|
||||
|
||||
int JS_SetProperty (JSContext *ctx, JSValue this_obj, JSValue prop,
|
||||
JSValue val) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (this_obj);
|
||||
|
||||
if (tag != JS_TAG_OBJECT) {
|
||||
if (!js_is_object (this_obj)) {
|
||||
JS_FreeValue (ctx, val);
|
||||
if (tag == JS_TAG_NULL) {
|
||||
if (JS_IsNull (this_obj)) {
|
||||
JS_ThrowTypeError (ctx, "cannot set property of null");
|
||||
} else {
|
||||
JS_ThrowTypeError (ctx, "cannot set property on a primitive");
|
||||
@@ -5549,17 +5636,46 @@ int JS_SetPropertyStr (JSContext *ctx, JSValue this_obj, const char *prop,
|
||||
return JS_SetProperty (ctx, this_obj, key, val);
|
||||
}
|
||||
|
||||
/* Set property with JSValue prop/key - handles int, string, object keys */
|
||||
static int JS_SetPropertyValue (JSContext *ctx, JSValue this_obj, JSValue prop,
|
||||
JSValue val) {
|
||||
uint32_t prop_tag = JS_VALUE_GET_TAG (prop);
|
||||
|
||||
if (prop_tag == JS_TAG_INT) {
|
||||
int idx = JS_VALUE_GET_INT (prop);
|
||||
JS_FreeValue (ctx, prop);
|
||||
JSValue ret = JS_SetPropertyNumber (ctx, this_obj, idx, val);
|
||||
if (JS_IsException (ret)) return -1;
|
||||
JS_FreeValue (ctx, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (JS_IsString (prop)) {
|
||||
JSValue key = js_key_from_string (ctx, prop);
|
||||
JS_FreeValue (ctx, prop);
|
||||
return JS_SetProperty (ctx, this_obj, key, val);
|
||||
}
|
||||
|
||||
if (js_is_record (prop)) {
|
||||
JS_FreeValue (ctx, prop);
|
||||
return JS_SetProperty (ctx, this_obj, prop, val);
|
||||
}
|
||||
|
||||
JS_FreeValue (ctx, prop);
|
||||
JS_FreeValue (ctx, val);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Property access with JSValue key - supports object keys directly */
|
||||
JSValue JS_GetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (key);
|
||||
if (tag == JS_TAG_OBJECT) {
|
||||
if (JS_VALUE_GET_TAG (this_obj) != JS_TAG_OBJECT) return JS_NULL;
|
||||
if (js_is_record (key)) {
|
||||
if (!js_is_record (this_obj)) return JS_NULL;
|
||||
JSRecord *rec = JS_VALUE_GET_RECORD (this_obj);
|
||||
return rec_get (ctx, rec, key);
|
||||
}
|
||||
|
||||
/* For string keys, create an interned key and use JS_GetProperty */
|
||||
if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_IMM) {
|
||||
if (JS_IsString (key)) {
|
||||
JSValue prop_key = js_key_from_string (ctx, key);
|
||||
return JS_GetProperty (ctx, this_obj, prop_key);
|
||||
}
|
||||
@@ -5570,9 +5686,8 @@ JSValue JS_GetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key) {
|
||||
|
||||
int JS_SetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key,
|
||||
JSValue val) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (key);
|
||||
if (tag == JS_TAG_OBJECT) {
|
||||
if (JS_VALUE_GET_TAG (this_obj) != JS_TAG_OBJECT) {
|
||||
if (js_is_record (key)) {
|
||||
if (!js_is_record (this_obj)) {
|
||||
JS_FreeValue (ctx, val);
|
||||
JS_ThrowTypeError (ctx, "cannot set property on this value");
|
||||
return -1;
|
||||
@@ -5587,7 +5702,7 @@ int JS_SetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key,
|
||||
}
|
||||
|
||||
/* For string keys, create an interned key */
|
||||
if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_IMM) {
|
||||
if (JS_IsString (key)) {
|
||||
JSValue prop_key = js_key_from_string (ctx, key);
|
||||
return JS_SetPropertyInternal (ctx, this_obj, prop_key, val);
|
||||
}
|
||||
@@ -5598,9 +5713,8 @@ int JS_SetPropertyKey (JSContext *ctx, JSValue this_obj, JSValue key,
|
||||
|
||||
/* Property existence check with JSValue key (supports object keys) */
|
||||
int JS_HasPropertyKey (JSContext *ctx, JSValue obj, JSValue key) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (key);
|
||||
if (tag == JS_TAG_OBJECT) {
|
||||
if (JS_VALUE_GET_TAG (obj) != JS_TAG_OBJECT) return FALSE;
|
||||
if (js_is_record (key)) {
|
||||
if (!js_is_record (obj)) return FALSE;
|
||||
JSRecord *rec = JS_VALUE_GET_RECORD (obj);
|
||||
/* Check own and prototype chain */
|
||||
while (rec) {
|
||||
@@ -5611,7 +5725,7 @@ int JS_HasPropertyKey (JSContext *ctx, JSValue obj, JSValue key) {
|
||||
}
|
||||
|
||||
/* For string keys, create an interned key */
|
||||
if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_IMM) {
|
||||
if (JS_IsString (key)) {
|
||||
JSValue prop_key = js_key_from_string (ctx, key);
|
||||
return JS_HasProperty (ctx, obj, prop_key);
|
||||
}
|
||||
@@ -5622,9 +5736,8 @@ int JS_HasPropertyKey (JSContext *ctx, JSValue obj, JSValue key) {
|
||||
|
||||
/* Property deletion with JSValue key (supports object keys) */
|
||||
int JS_DeletePropertyKey (JSContext *ctx, JSValue obj, JSValue key) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (key);
|
||||
if (tag == JS_TAG_OBJECT) {
|
||||
if (JS_VALUE_GET_TAG (obj) != JS_TAG_OBJECT) return FALSE;
|
||||
if (js_is_record (key)) {
|
||||
if (!js_is_record (obj)) return FALSE;
|
||||
JSRecord *rec = JS_VALUE_GET_RECORD (obj);
|
||||
if (rec_is_stone (rec)) {
|
||||
JS_ThrowTypeError (ctx, "cannot modify frozen object");
|
||||
@@ -5643,7 +5756,7 @@ int JS_DeletePropertyKey (JSContext *ctx, JSValue obj, JSValue key) {
|
||||
}
|
||||
|
||||
/* For string keys, create an interned key */
|
||||
if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_IMM) {
|
||||
if (JS_IsString (key)) {
|
||||
JSValue prop_key = js_key_from_string (ctx, key);
|
||||
return JS_DeleteProperty (ctx, obj, prop_key);
|
||||
}
|
||||
@@ -5955,7 +6068,7 @@ void *JS_GetOpaque2 (JSContext *ctx, JSValue obj, JSClassID class_id) {
|
||||
|
||||
void *JS_GetAnyOpaque (JSValue obj, JSClassID *class_id) {
|
||||
JSRecord *p;
|
||||
if (JS_VALUE_GET_TAG (obj) != JS_TAG_OBJECT) {
|
||||
if (!js_is_record (obj)) {
|
||||
*class_id = 0;
|
||||
return NULL;
|
||||
}
|
||||
@@ -5966,6 +6079,23 @@ void *JS_GetAnyOpaque (JSValue obj, JSClassID *class_id) {
|
||||
|
||||
static int JS_ToBoolFree (JSContext *ctx, JSValue val) {
|
||||
uint32_t tag = JS_VALUE_GET_TAG (val);
|
||||
|
||||
/* Check for pointer types first (new tagging system) */
|
||||
if (JS_IsPtr (val)) {
|
||||
void *ptr = JS_VALUE_GET_PTR (val);
|
||||
/* Check objhdr_t at offset 8 for type */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
if (objhdr_type (hdr) == OBJ_TEXT) {
|
||||
/* String (JSString or mist_text) - truthy if non-empty */
|
||||
BOOL ret = objhdr_cap56 (hdr) != 0;
|
||||
JS_FreeValue (ctx, val);
|
||||
return ret;
|
||||
}
|
||||
/* Objects (record, array, function) are truthy */
|
||||
JS_FreeValue (ctx, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (tag) {
|
||||
case JS_TAG_INT:
|
||||
return JS_VALUE_GET_INT (val) != 0;
|
||||
@@ -5974,19 +6104,10 @@ static int JS_ToBoolFree (JSContext *ctx, JSValue val) {
|
||||
return JS_VALUE_GET_INT (val);
|
||||
case JS_TAG_EXCEPTION:
|
||||
return -1;
|
||||
case JS_TAG_STRING: {
|
||||
BOOL ret = JS_VALUE_GET_STRING (val)->len != 0;
|
||||
JS_FreeValue (ctx, val);
|
||||
return ret;
|
||||
}
|
||||
case JS_TAG_STRING_IMM: {
|
||||
BOOL ret = MIST_GetImmediateASCIILen (val) != 0;
|
||||
JS_FreeValue (ctx, val);
|
||||
return ret;
|
||||
}
|
||||
case JS_TAG_OBJECT: /* includes arrays (OBJ_ARRAY) via mist_hdr */
|
||||
JS_FreeValue (ctx, val);
|
||||
return 1;
|
||||
default:
|
||||
if (JS_TAG_IS_FLOAT64 (tag)) {
|
||||
double d = JS_VALUE_GET_FLOAT64 (val);
|
||||
@@ -6210,9 +6331,24 @@ static JSValue JS_ToNumberFree (JSContext *ctx, JSValue val) {
|
||||
uint32_t tag;
|
||||
JSValue ret;
|
||||
|
||||
/* Handle pointer types (new tagging system) */
|
||||
if (JS_IsPtr (val)) {
|
||||
void *ptr = JS_VALUE_GET_PTR (val);
|
||||
/* Check objhdr_t at offset 8 for type */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
if (objhdr_type (hdr) == OBJ_TEXT) {
|
||||
/* String */
|
||||
JS_FreeValue (ctx, val);
|
||||
return JS_ThrowTypeError (ctx, "cannot convert text to a number");
|
||||
}
|
||||
/* Objects */
|
||||
JS_FreeValue (ctx, val);
|
||||
return JS_ThrowTypeError (ctx, "cannot convert object to number");
|
||||
}
|
||||
|
||||
tag = JS_VALUE_GET_NORM_TAG (val);
|
||||
switch (tag) {
|
||||
case JS_TAG_FLOAT64:
|
||||
case JS_TAG_SHORT_FLOAT:
|
||||
case JS_TAG_INT:
|
||||
case JS_TAG_EXCEPTION:
|
||||
ret = val;
|
||||
@@ -6221,12 +6357,7 @@ static JSValue JS_ToNumberFree (JSContext *ctx, JSValue val) {
|
||||
case JS_TAG_NULL:
|
||||
ret = JS_NewInt32 (ctx, JS_VALUE_GET_INT (val));
|
||||
break;
|
||||
case JS_TAG_OBJECT: /* includes arrays (OBJ_ARRAY) via mist_hdr */
|
||||
JS_FreeValue (ctx, val);
|
||||
return JS_ThrowTypeError (ctx, "cannot convert object to number");
|
||||
case JS_TAG_STRING:
|
||||
case JS_TAG_STRING_IMM:
|
||||
JS_FreeValue (ctx, val);
|
||||
return JS_ThrowTypeError (ctx, "cannot convert text to a number");
|
||||
default:
|
||||
JS_FreeValue (ctx, val);
|
||||
@@ -6602,10 +6733,27 @@ static JSValue JS_ToStringInternal (JSContext *ctx, JSValue val,
|
||||
uint32_t tag;
|
||||
char buf[32];
|
||||
|
||||
/* Handle pointer types (new tagging system) */
|
||||
if (JS_IsPtr (val)) {
|
||||
void *ptr = JS_VALUE_GET_PTR (val);
|
||||
/* Check objhdr_t at offset 8 for type */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
uint8_t mist_type = objhdr_type (hdr);
|
||||
if (mist_type == OBJ_TEXT) {
|
||||
/* String - return as-is */
|
||||
return JS_DupValue (ctx, val);
|
||||
}
|
||||
/* For GC objects, check gc_obj_type */
|
||||
JSGCObjectHeader *p = (JSGCObjectHeader *)ptr;
|
||||
if (p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
|
||||
return js_new_string8 (ctx, "[function bytecode]");
|
||||
}
|
||||
/* Objects (record, array, function) */
|
||||
return JS_KEY_true;
|
||||
}
|
||||
|
||||
tag = JS_VALUE_GET_NORM_TAG (val);
|
||||
switch (tag) {
|
||||
case JS_TAG_STRING:
|
||||
return JS_DupValue (ctx, val);
|
||||
case JS_TAG_STRING_IMM:
|
||||
return JS_DupValue (ctx, val);
|
||||
case JS_TAG_INT: {
|
||||
@@ -6619,11 +6767,7 @@ static JSValue JS_ToStringInternal (JSContext *ctx, JSValue val,
|
||||
return JS_KEY_null;
|
||||
case JS_TAG_EXCEPTION:
|
||||
return JS_EXCEPTION;
|
||||
case JS_TAG_OBJECT: /* includes arrays (OBJ_ARRAY) via mist_hdr */
|
||||
return JS_KEY_true;
|
||||
case JS_TAG_FUNCTION_BYTECODE:
|
||||
return js_new_string8 (ctx, "[function bytecode]");
|
||||
case JS_TAG_FLOAT64:
|
||||
case JS_TAG_SHORT_FLOAT:
|
||||
return js_dtoa2 (ctx, JS_VALUE_GET_FLOAT64 (val), 10, 0,
|
||||
JS_DTOA_FORMAT_FREE);
|
||||
default:
|
||||
@@ -6643,10 +6787,8 @@ static JSValue JS_ToStringFree (JSContext *ctx, JSValue val) {
|
||||
}
|
||||
|
||||
JSValue JS_ToPropertyKey (JSContext *ctx, JSValue val) {
|
||||
int tag = JS_VALUE_GET_TAG (val);
|
||||
|
||||
/* Objects are handled directly via objkey map, not through atoms */
|
||||
if (tag == JS_TAG_OBJECT) { return JS_DupValue (ctx, val); }
|
||||
if (js_is_object (val)) { return JS_DupValue (ctx, val); }
|
||||
|
||||
return JS_ToStringInternal (ctx, val, TRUE);
|
||||
}
|
||||
@@ -6939,6 +7081,95 @@ static void js_print_value (JSPrintValueState *s, JSValue val) {
|
||||
uint32_t tag = JS_VALUE_GET_NORM_TAG (val);
|
||||
const char *str;
|
||||
|
||||
/* Handle pointer types first (new tagging system) */
|
||||
if (JS_IsPtr (val)) {
|
||||
void *ptr = JS_VALUE_GET_PTR (val);
|
||||
/* Check objhdr_t at offset 8 for type */
|
||||
objhdr_t hdr = *((objhdr_t *)((char *)ptr + 8));
|
||||
uint8_t mist_type = objhdr_type (hdr);
|
||||
|
||||
if (mist_type == OBJ_TEXT) {
|
||||
/* String (JSString or mist_text) */
|
||||
js_print_string (s, val);
|
||||
return;
|
||||
}
|
||||
|
||||
/* For GC objects, use gc_obj_type */
|
||||
JSGCObjectHeader *p = (JSGCObjectHeader *)ptr;
|
||||
JSGCObjectTypeEnum obj_type = p->gc_obj_type;
|
||||
|
||||
switch (obj_type) {
|
||||
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: {
|
||||
JSFunctionBytecode *b = (JSFunctionBytecode *)p;
|
||||
js_puts (s, "[bytecode ");
|
||||
if (JS_IsString (b->func_name)) {
|
||||
js_print_value (s, b->func_name);
|
||||
} else {
|
||||
js_puts (s, "<anon>");
|
||||
}
|
||||
js_putc (s, ']');
|
||||
} break;
|
||||
case JS_GC_OBJ_TYPE_FUNCTION: {
|
||||
JSFunction *f = (JSFunction *)p;
|
||||
js_puts (s, "[Function");
|
||||
if (JS_IsString (f->name)) {
|
||||
js_putc (s, ' ');
|
||||
js_print_value (s, f->name);
|
||||
} else if (f->kind == JS_FUNC_KIND_BYTECODE
|
||||
&& f->u.func.function_bytecode) {
|
||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||
if (JS_IsString (b->func_name)) {
|
||||
js_putc (s, ' ');
|
||||
js_print_value (s, b->func_name);
|
||||
}
|
||||
}
|
||||
js_putc (s, ']');
|
||||
} break;
|
||||
case JS_GC_OBJ_TYPE_ARRAY: {
|
||||
JSArray *arr = (JSArray *)p;
|
||||
uint32_t i, count;
|
||||
js_putc (s, '[');
|
||||
count = min_uint32 (arr->len, s->options.max_item_count);
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i > 0) js_puts (s, ", ");
|
||||
if (s->level < s->options.max_depth) {
|
||||
s->level++;
|
||||
js_print_value (s, arr->values[i]);
|
||||
s->level--;
|
||||
} else {
|
||||
js_puts (s, "...");
|
||||
}
|
||||
}
|
||||
if (arr->len > count) {
|
||||
js_printf (s, ", ... %u more", arr->len - count);
|
||||
}
|
||||
js_putc (s, ']');
|
||||
} break;
|
||||
case JS_GC_OBJ_TYPE_RECORD: {
|
||||
JSRecord *rec = (JSRecord *)p;
|
||||
int idx;
|
||||
idx = js_print_stack_index (s, rec);
|
||||
if (idx >= 0) {
|
||||
js_printf (s, "[circular %d]", idx);
|
||||
} else if (s->level < s->options.max_depth) {
|
||||
s->print_stack[s->level++] = rec;
|
||||
js_print_object (s, rec);
|
||||
s->level--;
|
||||
} else {
|
||||
const char *class_name = s->rt->class_array[rec->class_id].class_name;
|
||||
js_putc (s, '[');
|
||||
js_puts (s, class_name ? class_name : "Object");
|
||||
if (s->options.raw_dump) { js_printf (s, " %p", (void *)rec); }
|
||||
js_putc (s, ']');
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
js_printf (s, "[gc_obj_type %d]", obj_type);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (tag) {
|
||||
case JS_TAG_INT:
|
||||
js_printf (s, "%d", JS_VALUE_GET_INT (val));
|
||||
@@ -6961,80 +7192,12 @@ static void js_print_value (JSPrintValueState *s, JSValue val) {
|
||||
print_str:
|
||||
js_puts (s, str);
|
||||
break;
|
||||
case JS_TAG_FLOAT64:
|
||||
case JS_TAG_SHORT_FLOAT:
|
||||
js_print_float64 (s, JS_VALUE_GET_FLOAT64 (val));
|
||||
break;
|
||||
case JS_TAG_STRING:
|
||||
case JS_TAG_STRING_IMM:
|
||||
js_print_string (s, val);
|
||||
break;
|
||||
case JS_TAG_FUNCTION_BYTECODE: {
|
||||
JSFunctionBytecode *b = JS_VALUE_GET_PTR (val);
|
||||
js_puts (s, "[bytecode ");
|
||||
/* func_name is a JSValue string now */
|
||||
if (JS_IsString (b->func_name)) {
|
||||
js_print_value (s, b->func_name);
|
||||
} else {
|
||||
js_puts (s, "<anon>");
|
||||
}
|
||||
js_putc (s, ']');
|
||||
} break;
|
||||
case JS_TAG_FUNCTION: {
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION (val);
|
||||
js_puts (s, "[Function");
|
||||
if (JS_IsString (f->name)) {
|
||||
js_putc (s, ' ');
|
||||
js_print_value (s, f->name);
|
||||
} else if (f->kind == JS_FUNC_KIND_BYTECODE
|
||||
&& f->u.func.function_bytecode) {
|
||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||
if (JS_IsString (b->func_name)) {
|
||||
js_putc (s, ' ');
|
||||
js_print_value (s, b->func_name);
|
||||
}
|
||||
}
|
||||
js_putc (s, ']');
|
||||
} break;
|
||||
case JS_TAG_OBJECT:
|
||||
/* Check if this is an intrinsic array (mist_hdr type OBJ_ARRAY) */
|
||||
if (JS_VALUE_IS_INTRINSIC_ARRAY (val)) {
|
||||
JSArray *arr = JS_VALUE_GET_ARRAY (val);
|
||||
uint32_t i, count;
|
||||
js_putc (s, '[');
|
||||
count = min_uint32 (arr->len, s->options.max_item_count);
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i > 0) js_puts (s, ", ");
|
||||
if (s->level < s->options.max_depth) {
|
||||
s->level++;
|
||||
js_print_value (s, arr->values[i]);
|
||||
s->level--;
|
||||
} else {
|
||||
js_puts (s, "...");
|
||||
}
|
||||
}
|
||||
if (arr->len > count) {
|
||||
js_printf (s, ", ... %u more", arr->len - count);
|
||||
}
|
||||
js_putc (s, ']');
|
||||
} else {
|
||||
JSRecord *p = JS_VALUE_GET_OBJ (val);
|
||||
int idx;
|
||||
idx = js_print_stack_index (s, p);
|
||||
if (idx >= 0) {
|
||||
js_printf (s, "[circular %d]", idx);
|
||||
} else if (s->level < s->options.max_depth) {
|
||||
s->print_stack[s->level++] = p;
|
||||
js_print_object (s, JS_VALUE_GET_OBJ (val));
|
||||
s->level--;
|
||||
} else {
|
||||
const char *class_name = s->rt->class_array[p->class_id].class_name;
|
||||
js_putc (s, '[');
|
||||
js_puts (s, class_name ? class_name : "Object");
|
||||
if (s->options.raw_dump) { js_printf (s, " %p", (void *)p); }
|
||||
js_putc (s, ']');
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
js_printf (s, "[unknown tag %d]", tag);
|
||||
break;
|
||||
|
||||
@@ -575,20 +575,18 @@ 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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static inline JS_BOOL
|
||||
JS_IsObject (JSValue v) {
|
||||
return JS_VALUE_GET_TAG (v) == JS_TAG_OBJECT;
|
||||
}
|
||||
/* 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
|
||||
|
||||
Reference in New Issue
Block a user