From a88cee7faea5bbdf08547b0ec7b21bbca91d040a Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 16 Jun 2025 17:02:05 -0500 Subject: [PATCH] Remove weak-everything. remove throwing on type differences in equality; remove using 'def' as some variable names --- prosperon/draw2d.cm | 30 +- prosperon/prosperon.ce | 1 + scripts/util.cm | 6 +- source/quickjs.c | 609 ++++------------------------------------- source/quickjs.h | 1 - 5 files changed, 68 insertions(+), 579 deletions(-) diff --git a/prosperon/draw2d.cm b/prosperon/draw2d.cm index 88028acb..f7555a13 100644 --- a/prosperon/draw2d.cm +++ b/prosperon/draw2d.cm @@ -76,8 +76,8 @@ draw.point = function(pos, size, opt = {}, material) { }) } -draw.ellipse = function(pos, radii, def, material) { - var opt = def ? {...ellipse_def, ...def} : ellipse_def +draw.ellipse = function(pos, radii, defl, material) { + var opt = defl ? {...ellipse_def, ...defl} : ellipse_def if (opt.thickness <= 0) opt.thickness = Math.max(radii[0], radii[1]) add_command("draw_ellipse", { @@ -88,9 +88,9 @@ draw.ellipse = function(pos, radii, def, material) { }) } -draw.line = function(points, def, material) +draw.line = function(points, defl, material) { - var opt = def ? {...line_def, ...def} : line_def + var opt = defl ? {...line_def, ...defl} : line_def add_command("draw_line", { points: points, @@ -99,24 +99,24 @@ draw.line = function(points, def, material) }) } -draw.cross = function render_cross(pos, size, def, material) { +draw.cross = function render_cross(pos, size, defl, material) { var a = [pos.add([0, size]), pos.add([0, -size])] var b = [pos.add([size, 0]), pos.add([-size, 0])] - draw.line(a, def, material) - draw.line(b, def, material) + draw.line(a, defl, material) + draw.line(b, defl, material) } -draw.arrow = function render_arrow(start, end, wingspan = 4, wingangle = 10, def, material) { +draw.arrow = function render_arrow(start, end, wingspan = 4, wingangle = 10, defl, material) { var dir = math.norm(end.sub(start)) var wing1 = [math.rotate(dir, wingangle).scale(wingspan).add(end), end] var wing2 = [math.rotate(dir, -wingangle).scale(wingspan).add(end), end] - draw.line([start, end], def, material) - draw.line(wing1, def, material) - draw.line(wing2, def, material) + draw.line([start, end], defl, material) + draw.line(wing1, defl, material) + draw.line(wing2, defl, material) } -draw.rectangle = function render_rectangle(rect, def, material) { - var opt = def ? {...rect_def, ...def} : rect_def +draw.rectangle = function render_rectangle(rect, defl, material) { + var opt = defl ? {...rect_def, ...defl} : rect_def add_command("draw_rect", { rect: rect, @@ -154,8 +154,8 @@ draw.image = function image(image, rect, rotation, anchor, shear, info, material }) } -draw.circle = function render_circle(pos, radius, def, material) { - draw.ellipse(pos, [radius,radius], def, material) +draw.circle = function render_circle(pos, radius, defl, material) { + draw.ellipse(pos, [radius,radius], defl, material) } draw.text = function text(text, pos, font = 'fonts/c64.ttf', size = 8, color = color.white, wrap = 0) { diff --git a/prosperon/prosperon.ce b/prosperon/prosperon.ce index 3a1048ba..8f496a76 100644 --- a/prosperon/prosperon.ce +++ b/prosperon/prosperon.ce @@ -260,6 +260,7 @@ function translate_draw_commands(commands) { return graphics.texture(tile) }) var geom = geometry.tilemap_to_data(cmd.tilemap) + if (!texid) break if (texid.gpu) geom.texture_id = texid.gpu.id diff --git a/scripts/util.cm b/scripts/util.cm index a08948e3..6f5e7b85 100644 --- a/scripts/util.cm +++ b/scripts/util.cm @@ -23,13 +23,13 @@ util.isEmpty = function(o) { return Object.keys(o).length == 0 } -util.dig = function (obj, path, def = {}) { +util.dig = function (obj, path, deflt = {}) { var pp = path.split(".") for (var i = 0; i < pp.length - 1; i++) { obj = obj[pp[i]] = obj[pp[i]] || {} } - obj[pp[pp.length - 1]] = def - return def + obj[pp[pp.length - 1]] = deflt + return deflt } util.access = function (obj, name) { diff --git a/source/quickjs.c b/source/quickjs.c index 055c54d6..3ad27fd5 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -134,15 +134,12 @@ enum { JS_CLASS_BIG_INT, /* u.object_data */ JS_CLASS_MAP, /* u.map_state */ JS_CLASS_SET, /* u.map_state */ - JS_CLASS_WEAKMAP, /* u.map_state */ - JS_CLASS_WEAKSET, /* u.map_state */ JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */ JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */ JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */ JS_CLASS_STRING_ITERATOR, /* u.array_iterator_data */ JS_CLASS_REGEXP_STRING_ITERATOR, /* u.regexp_string_iterator_data */ JS_CLASS_PROXY, /* u.proxy_data */ - JS_CLASS_WEAK_REF, JS_CLASS_FINALIZATION_REGISTRY, JS_CLASS_INIT_COUNT, /* last entry for predefined classes */ @@ -219,7 +216,6 @@ struct JSRuntime { struct list_head tmp_obj_list; /* used during GC */ JSGCPhaseEnum gc_phase : 8; size_t malloc_gc_threshold; - struct list_head weakref_list; /* list of JSWeakRefHeader.link */ #ifdef DUMP_LEAKS struct list_head string_list; /* list of JSString.link */ #endif @@ -295,17 +291,6 @@ struct JSGCObjectHeader { struct list_head link; }; -typedef enum { - JS_WEAKREF_TYPE_MAP, - JS_WEAKREF_TYPE_WEAKREF, - JS_WEAKREF_TYPE_FINREC, -} JSWeakRefHeaderTypeEnum; - -typedef struct { - struct list_head link; - JSWeakRefHeaderTypeEnum weakref_type; -} JSWeakRefHeader; - typedef struct JSVarRef { union { JSGCObjectHeader header; /* must come first */ @@ -724,10 +709,6 @@ struct JSObject { uint16_t class_id; /* see JS_CLASS_x */ }; }; - /* count the number of weak references to this object. The object - structure is freed only if header.ref_count = 0 and - weakref_count = 0 */ - uint32_t weakref_count; JSShape *shape; /* prototype and property names + flag */ JSProperty *prop; /* array of properties */ union { @@ -776,7 +757,6 @@ typedef struct JSMapRecord { } JSMapRecord; typedef struct JSMapState { - BOOL is_weak; /* TRUE if WeakSet/WeakMap */ struct list_head records; /* list of JSMapRecord.link */ uint32_t record_count; JSMapRecord **hash_table; @@ -784,7 +764,6 @@ typedef struct JSMapState { uint32_t hash_size; /* = 2 ^ hash_bits */ uint32_t record_count_threshold; /* count at which a hash table resize is needed */ - JSWeakRefHeader weakref_header; /* only used if is_weak = TRUE */ } JSMapState; enum { @@ -994,10 +973,7 @@ static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int is_map); -static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh); -static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh); -static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh); -static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects); +static void JS_RunGCInternal(JSRuntime *rt); static int js_string_find_invalid_codepoint(JSString *p); static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); @@ -1208,8 +1184,6 @@ static JSClassShortDef const js_std_class_def[] = { { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */ { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */ { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */ - { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKMAP */ - { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKSET */ { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */ { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */ { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ @@ -1285,7 +1259,6 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) init_list_head(&rt->gc_obj_list); init_list_head(&rt->gc_zero_ref_count_list); rt->gc_phase = JS_GC_PHASE_NONE; - init_list_head(&rt->weakref_list); #ifdef DUMP_LEAKS init_list_head(&rt->string_list); @@ -1517,9 +1490,7 @@ void JS_FreeRuntime(JSRuntime *rt) JS_FreeValueRT(rt, rt->current_exception); - /* don't remove the weak objects to avoid create new jobs with - FinalizationRegistry */ - JS_RunGCInternal(rt, FALSE); + JS_RunGCInternal(rt); #ifdef DUMP_LEAKS /* leaking objects */ @@ -1561,7 +1532,6 @@ void JS_FreeRuntime(JSRuntime *rt) } #endif assert(list_empty(&rt->gc_obj_list)); - assert(list_empty(&rt->weakref_list)); /* free the classes */ for(i = 0; i < rt->class_count; i++) { @@ -4578,7 +4548,6 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas p->is_constructor = 0; p->has_immutable_prototype = 0; p->tmp_mark = 0; - p->weakref_count = 0; p->u.opaque = NULL; p->shape = sh; p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size); @@ -5212,22 +5181,11 @@ static void free_object(JSRuntime *rt, JSObject *p) p->u.func.var_refs = NULL; remove_gc_object(&p->header); - if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES) { - if (p->header.ref_count == 0 && p->weakref_count == 0) { - js_free_rt(rt, p); - } else { - /* keep the object structure because there are may be - references to it */ - list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list); - } - } else { - /* keep the object structure in case there are weak references to it */ - if (p->weakref_count == 0) { - js_free_rt(rt, p); - } else { - p->header.mark = 0; /* reset the mark so that the weakref can be freed */ - } - } + /* no more weakrefs: free if no strong refs, else queue for zero-ref processing */ + if (p->header.ref_count == 0) + js_free_rt(rt, p); + else + list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list); } static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp) @@ -5339,36 +5297,6 @@ void __JS_FreeValue(JSContext *ctx, JSValue v) /* garbage collection */ -static void gc_remove_weak_objects(JSRuntime *rt) -{ - struct list_head *el; - - /* add the freed objects to rt->gc_zero_ref_count_list so that - rt->weakref_list is not modified while we traverse it */ - rt->gc_phase = JS_GC_PHASE_DECREF; - - list_for_each(el, &rt->weakref_list) { - JSWeakRefHeader *wh = list_entry(el, JSWeakRefHeader, link); - switch(wh->weakref_type) { - case JS_WEAKREF_TYPE_MAP: - map_delete_weakrefs(rt, wh); - break; - case JS_WEAKREF_TYPE_WEAKREF: - weakref_delete_weakref(rt, wh); - break; - case JS_WEAKREF_TYPE_FINREC: - finrec_delete_weakref(rt, wh); - break; - default: - abort(); - } - } - - rt->gc_phase = JS_GC_PHASE_NONE; - /* free the freed objects here. */ - free_zero_refcount(rt); -} - static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, JSGCObjectTypeEnum type) { @@ -5592,27 +5520,14 @@ static void gc_free_cycles(JSRuntime *rt) p = list_entry(el, JSGCObjectHeader, link); assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); - if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT && - ((JSObject *)p)->weakref_count != 0) { - /* keep the object because there are weak references to it */ - p->mark = 0; - } else { - js_free_rt(rt, p); - } + js_free_rt(rt, p); } init_list_head(&rt->gc_zero_ref_count_list); } -static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects) +static void JS_RunGCInternal(JSRuntime *rt) { - if (remove_weak_objects) { - /* free the weakly referenced object or symbol structures, delete - the associated Map/Set entries and queue the finalization - registry callbacks. */ - gc_remove_weak_objects(rt); - } - /* decrement the reference of the children of each object. mark = 1 after this pass. */ gc_decref(rt); @@ -5626,7 +5541,7 @@ static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects) void JS_RunGC(JSRuntime *rt) { - JS_RunGCInternal(rt, TRUE); + JS_RunGCInternal(rt); } /* Return false if not an object or if the object has already been @@ -5874,8 +5789,6 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) break; case JS_CLASS_MAP: /* u.map_state */ case JS_CLASS_SET: /* u.map_state */ - case JS_CLASS_WEAKMAP: /* u.map_state */ - case JS_CLASS_WEAKSET: /* u.map_state */ case JS_CLASS_MAP_ITERATOR: /* u.map_iterator_data */ case JS_CLASS_SET_ITERATOR: /* u.map_iterator_data */ case JS_CLASS_ARRAY_ITERATOR: /* u.array_iterator_data */ @@ -13838,15 +13751,6 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); - /* throw on any mismatched non-numeric tags */ - if (tag1 != tag2 - && !((tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64) - && (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64))) { - JS_ThrowTypeError(ctx, - "Strict equality: cannot compare two differing types"); - goto done_no_free; - } - switch(tag1) { case JS_TAG_BOOL: if (tag1 != tag2) { @@ -40593,81 +40497,7 @@ static const JSCFunctionListEntry js_symbol_funcs[] = { /* Set/Map/WeakSet/WeakMap */ -static BOOL js_weakref_is_target(JSValueConst val) -{ - switch (JS_VALUE_GET_TAG(val)) { - case JS_TAG_OBJECT: - return TRUE; - case JS_TAG_SYMBOL: - { - JSAtomStruct *p = JS_VALUE_GET_PTR(val); - if (p->atom_type == JS_ATOM_TYPE_SYMBOL && - p->hash != JS_ATOM_HASH_PRIVATE) - return TRUE; - } - break; - default: - break; - } - return FALSE; -} - -/* JS_UNDEFINED is considered as a live weakref */ -/* XXX: add a specific JSWeakRef value type ? */ -static BOOL js_weakref_is_live(JSValueConst val) -{ - int *pref_count; - if (JS_IsUndefined(val)) - return TRUE; - pref_count = JS_VALUE_GET_PTR(val); - return (*pref_count != 0); -} - -/* 'val' can be JS_UNDEFINED */ -static void js_weakref_free(JSRuntime *rt, JSValue val) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(val); - assert(p->weakref_count >= 1); - p->weakref_count--; - /* 'mark' is tested to avoid freeing the object structure when - it is about to be freed in a cycle or in - free_zero_refcount() */ - if (p->weakref_count == 0 && p->header.ref_count == 0 && - p->header.mark == 0) { - js_free_rt(rt, p); - } - } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) { - JSString *p = JS_VALUE_GET_STRING(val); - assert(p->hash >= 1); - p->hash--; - if (p->hash == 0 && p->header.ref_count == 0) { - /* can remove the dummy structure */ - js_free_rt(rt, p); - } - } -} - -/* val must be an object, a symbol or undefined (see - js_weakref_is_target). */ -static JSValue js_weakref_new(JSContext *ctx, JSValueConst val) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(val); - p->weakref_count++; - } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) { - JSString *p = JS_VALUE_GET_STRING(val); - /* XXX: could return an exception if too many references */ - assert(p->hash < JS_ATOM_HASH_MASK - 2); - p->hash++; - } else { - assert(JS_IsUndefined(val)); - } - return (JSValue)val; -} - #define MAGIC_SET (1 << 0) -#define MAGIC_WEAK (1 << 1) static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic) @@ -40675,10 +40505,9 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, JSMapState *s; JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED; JSValueConst arr; - BOOL is_set, is_weak; + BOOL is_set; is_set = magic & MAGIC_SET; - is_weak = ((magic & MAGIC_WEAK) != 0); obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic); if (JS_IsException(obj)) return JS_EXCEPTION; @@ -40686,11 +40515,6 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, if (!s) goto fail; init_list_head(&s->records); - s->is_weak = is_weak; - if (is_weak) { - s->weakref_header.weakref_type = JS_WEAKREF_TYPE_MAP; - list_add_tail(&s->weakref_header.link, &ctx->rt->weakref_list); - } JS_SetOpaque(obj, s); s->hash_bits = 1; s->hash_size = 1U << s->hash_bits; @@ -40881,7 +40705,7 @@ static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s, uint32_t h; h = map_hash_key(key, s->hash_bits); for(mr = s->hash_table[h]; mr != NULL; mr = mr->hash_next) { - if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) { + if (mr->empty) { /* cannot match */ } else { if (js_same_value_zero(ctx, mr->key, key)) @@ -40910,7 +40734,7 @@ static void map_hash_resize(JSContext *ctx, JSMapState *s) list_for_each(el, &s->records) { mr = list_entry(el, JSMapRecord, link); - if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) { + if (mr->empty) { } else { h = map_hash_key(mr->key, new_hash_bits); mr->hash_next = new_hash_table[h]; @@ -40934,11 +40758,7 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s, return NULL; mr->ref_count = 1; mr->empty = FALSE; - if (s->is_weak) { - mr->key = js_weakref_new(ctx, key); - } else { - mr->key = JS_DupValue(ctx, key); - } + mr->key = JS_DupValue(ctx, key); h = map_hash_key(key, s->hash_bits); mr->hash_next = s->hash_table[h]; s->hash_table[h] = mr; @@ -40956,11 +40776,7 @@ static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr) if (mr->empty) return; - if (s->is_weak) { - js_weakref_free(rt, mr->key); - } else { - JS_FreeValueRT(rt, mr->key); - } + JS_FreeValueRT(rt, mr->key); JS_FreeValueRT(rt, mr->value); if (--mr->ref_count == 0) { list_del(&mr->link); @@ -40984,38 +40800,6 @@ static void map_decref_record(JSRuntime *rt, JSMapRecord *mr) } } -static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh) -{ - JSMapState *s = container_of(wh, JSMapState, weakref_header); - struct list_head *el, *el1; - JSMapRecord *mr1, **pmr; - uint32_t h; - - list_for_each_safe(el, el1, &s->records) { - JSMapRecord *mr = list_entry(el, JSMapRecord, link); - if (!js_weakref_is_live(mr->key)) { - - /* even if key is not live it can be hashed as a pointer */ - h = map_hash_key(mr->key, s->hash_bits); - pmr = &s->hash_table[h]; - for(;;) { - mr1 = *pmr; - /* the entry may already be removed from the hash - table if the map was resized */ - if (mr1 == NULL) - goto done; - if (mr1 == mr) - break; - pmr = &mr1->hash_next; - } - /* remove from the hash table */ - *pmr = mr1->hash_next; - done: - map_delete_record(rt, s, mr); - } - } -} - static JSValue js_map_set(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) { @@ -41026,8 +40810,6 @@ static JSValue js_map_set(JSContext *ctx, JSValueConst this_val, if (!s) return JS_EXCEPTION; key = map_normalize_key(ctx, argv[0]); - if (s->is_weak && !js_weakref_is_target(key)) - return JS_ThrowTypeError(ctx, "invalid value used as %s key", (magic & MAGIC_SET) ? "WeakSet" : "WeakMap"); if (magic & MAGIC_SET) value = JS_UNDEFINED; else @@ -41093,7 +40875,7 @@ static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val, mr = *pmr; if (mr == NULL) return JS_FALSE; - if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) { + if (mr->empty) { /* not valid */ } else { if (js_same_value_zero(ctx, mr->key, key)) @@ -41317,18 +41099,12 @@ static void js_map_finalizer(JSRuntime *rt, JSValue val) list_for_each_safe(el, el1, &s->records) { mr = list_entry(el, JSMapRecord, link); if (!mr->empty) { - if (s->is_weak) - js_weakref_free(rt, mr->key); - else - JS_FreeValueRT(rt, mr->key); + JS_FreeValueRT(rt, mr->key); JS_FreeValueRT(rt, mr->value); } js_free_rt(rt, mr); } js_free_rt(rt, s->hash_table); - if (s->is_weak) { - list_del(&s->weakref_header.link); - } js_free_rt(rt, s); } } @@ -41344,8 +41120,7 @@ static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) if (s) { list_for_each(el, &s->records) { mr = list_entry(el, JSMapRecord, link); - if (!s->is_weak) - JS_MarkValue(rt, mr->key, mark_func); + JS_MarkValue(rt, mr->key, mark_func); JS_MarkValue(rt, mr->value, mark_func); } } @@ -41528,68 +41303,53 @@ static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = { JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ), }; -static const JSCFunctionListEntry js_weak_map_proto_funcs[] = { - JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_weak_set_proto_funcs[] = { - JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = { +static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[4] = { js_map_proto_funcs, js_set_proto_funcs, - js_weak_map_proto_funcs, - js_weak_set_proto_funcs, js_map_iterator_proto_funcs, js_set_iterator_proto_funcs, }; -static const uint8_t js_map_proto_funcs_count[6] = { +static const uint8_t js_map_proto_funcs_count[4] = { countof(js_map_proto_funcs), countof(js_set_proto_funcs), - countof(js_weak_map_proto_funcs), - countof(js_weak_set_proto_funcs), countof(js_map_iterator_proto_funcs), countof(js_set_iterator_proto_funcs), }; void JS_AddIntrinsicMapSet(JSContext *ctx) { - int i; - JSValue obj1; - char buf[ATOM_GET_STR_BUF_SIZE]; + int i; + JSValue obj1; + char buf[ATOM_GET_STR_BUF_SIZE]; - for(i = 0; i < 4; i++) { - const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf), - JS_ATOM_Map + i); - ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i], - js_map_proto_funcs_ptr[i], - js_map_proto_funcs_count[i]); - obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0, - JS_CFUNC_constructor_magic, i); - if (i < 2) { - JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs, - countof(js_map_funcs)); - } - JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]); - } + /* --- Map and Set --- */ + for(i = 0; i < 2; i++) { + const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf), + JS_ATOM_Map + i); + ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, + ctx->class_proto[JS_CLASS_MAP + i], + js_map_proto_funcs_ptr[i], + js_map_proto_funcs_count[i]); + obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, + 0, JS_CFUNC_constructor_magic, i); + JS_SetPropertyFunctionList(ctx, obj1, + js_map_funcs, countof(js_map_funcs)); + JS_NewGlobalCConstructor2(ctx, obj1, name, + ctx->class_proto[JS_CLASS_MAP + i]); + } - for(i = 0; i < 2; i++) { - ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] = - JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i], - js_map_proto_funcs_ptr[i + 4], - js_map_proto_funcs_count[i + 4]); - } + /* --- MapIterator and SetIterator --- */ + for(i = 0; i < 2; i++) { + ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] = + JS_NewObjectProto(ctx, ctx->iterator_proto); + JS_SetPropertyFunctionList(ctx, + ctx->class_proto[JS_CLASS_MAP_ITERATOR + i], + /* now offset by +2, not +4 */ + js_map_proto_funcs_ptr[i + 2], + js_map_proto_funcs_count[i + 2]); + } } /* URI handling */ @@ -42346,277 +42106,6 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) JS_AddIntrinsicBigInt(ctx); } -/* WeakRef */ - -typedef struct JSWeakRefData { - JSWeakRefHeader weakref_header; - JSValue target; -} JSWeakRefData; - -static void js_weakref_finalizer(JSRuntime *rt, JSValue val) -{ - JSWeakRefData *wrd = JS_GetOpaque(val, JS_CLASS_WEAK_REF); - if (!wrd) - return; - js_weakref_free(rt, wrd->target); - list_del(&wrd->weakref_header.link); - js_free_rt(rt, wrd); -} - -static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh) -{ - JSWeakRefData *wrd = container_of(wh, JSWeakRefData, weakref_header); - - if (!js_weakref_is_live(wrd->target)) { - js_weakref_free(rt, wrd->target); - wrd->target = JS_UNDEFINED; - } -} - -static JSValue js_weakref_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValueConst arg; - JSValue obj; - - if (JS_IsUndefined(new_target)) - return JS_ThrowTypeError(ctx, "constructor requires 'new'"); - arg = argv[0]; - if (!js_weakref_is_target(arg)) - return JS_ThrowTypeError(ctx, "invalid target"); - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_WEAK_REF); - if (JS_IsException(obj)) - return JS_EXCEPTION; - JSWeakRefData *wrd = js_mallocz(ctx, sizeof(*wrd)); - if (!wrd) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - wrd->target = js_weakref_new(ctx, arg); - wrd->weakref_header.weakref_type = JS_WEAKREF_TYPE_WEAKREF; - list_add_tail(&wrd->weakref_header.link, &ctx->rt->weakref_list); - JS_SetOpaque(obj, wrd); - return obj; -} - -static JSValue js_weakref_deref(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - JSWeakRefData *wrd = JS_GetOpaque2(ctx, this_val, JS_CLASS_WEAK_REF); - if (!wrd) - return JS_EXCEPTION; - if (js_weakref_is_live(wrd->target)) - return JS_DupValue(ctx, wrd->target); - else - return JS_UNDEFINED; -} - -static const JSCFunctionListEntry js_weakref_proto_funcs[] = { - JS_CFUNC_DEF("deref", 0, js_weakref_deref ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakRef", JS_PROP_CONFIGURABLE ), -}; - -static const JSClassShortDef js_weakref_class_def[] = { - { JS_ATOM_WeakRef, js_weakref_finalizer, NULL }, /* JS_CLASS_WEAK_REF */ -}; - -typedef struct JSFinRecEntry { - struct list_head link; - JSValue target; - JSValue held_val; - JSValue token; -} JSFinRecEntry; - -typedef struct JSFinalizationRegistryData { - JSWeakRefHeader weakref_header; - struct list_head entries; /* list of JSFinRecEntry.link */ - JSContext *ctx; - JSValue cb; -} JSFinalizationRegistryData; - -static void js_finrec_finalizer(JSRuntime *rt, JSValue val) -{ - JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY); - if (frd) { - struct list_head *el, *el1; - list_for_each_safe(el, el1, &frd->entries) { - JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link); - js_weakref_free(rt, fre->target); - js_weakref_free(rt, fre->token); - JS_FreeValueRT(rt, fre->held_val); - js_free_rt(rt, fre); - } - JS_FreeValueRT(rt, frd->cb); - list_del(&frd->weakref_header.link); - js_free_rt(rt, frd); - } -} - -static void js_finrec_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY); - struct list_head *el; - if (frd) { - list_for_each(el, &frd->entries) { - JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link); - JS_MarkValue(rt, fre->held_val, mark_func); - } - JS_MarkValue(rt, frd->cb, mark_func); - } -} - -static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh) -{ - JSFinalizationRegistryData *frd = container_of(wh, JSFinalizationRegistryData, weakref_header); - struct list_head *el, *el1; - - list_for_each_safe(el, el1, &frd->entries) { - JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link); - - if (!js_weakref_is_live(fre->token)) { - js_weakref_free(rt, fre->token); - fre->token = JS_UNDEFINED; - } - - if (!js_weakref_is_live(fre->target)) { - JSValueConst args[2]; - args[0] = frd->cb; - args[1] = fre->held_val; - - js_weakref_free(rt, fre->target); - js_weakref_free(rt, fre->token); - JS_FreeValueRT(rt, fre->held_val); - list_del(&fre->link); - js_free_rt(rt, fre); - } - } -} - -static JSValue js_finrec_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValueConst cb; - JSValue obj; - JSFinalizationRegistryData *frd; - - if (JS_IsUndefined(new_target)) - return JS_ThrowTypeError(ctx, "constructor requires 'new'"); - cb = argv[0]; - if (!JS_IsFunction(ctx, cb)) - return JS_ThrowTypeError(ctx, "argument must be a function"); - - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_FINALIZATION_REGISTRY); - if (JS_IsException(obj)) - return JS_EXCEPTION; - frd = js_mallocz(ctx, sizeof(*frd)); - if (!frd) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - frd->weakref_header.weakref_type = JS_WEAKREF_TYPE_FINREC; - list_add_tail(&frd->weakref_header.link, &ctx->rt->weakref_list); - init_list_head(&frd->entries); - frd->ctx = ctx; /* XXX: JS_DupContext() ? */ - frd->cb = JS_DupValue(ctx, cb); - JS_SetOpaque(obj, frd); - return obj; -} - -static JSValue js_finrec_register(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst target, held_val, token; - JSFinalizationRegistryData *frd; - JSFinRecEntry *fre; - - frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY); - if (!frd) - return JS_EXCEPTION; - target = argv[0]; - held_val = argv[1]; - token = argc > 2 ? argv[2] : JS_UNDEFINED; - - if (!js_weakref_is_target(target)) - return JS_ThrowTypeError(ctx, "invalid target"); - if (js_same_value(ctx, target, held_val)) - return JS_ThrowTypeError(ctx, "held value cannot be the target"); - if (!JS_IsUndefined(token) && !js_weakref_is_target(token)) - return JS_ThrowTypeError(ctx, "invalid unregister token"); - fre = js_malloc(ctx, sizeof(*fre)); - if (!fre) - return JS_EXCEPTION; - fre->target = js_weakref_new(ctx, target); - fre->held_val = JS_DupValue(ctx, held_val); - fre->token = js_weakref_new(ctx, token); - list_add_tail(&fre->link, &frd->entries); - return JS_UNDEFINED; -} - -static JSValue js_finrec_unregister(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY); - JSValueConst token; - BOOL removed; - struct list_head *el, *el1; - - if (!frd) - return JS_EXCEPTION; - token = argv[0]; - if (!js_weakref_is_target(token)) - return JS_ThrowTypeError(ctx, "invalid unregister token"); - - removed = FALSE; - list_for_each_safe(el, el1, &frd->entries) { - JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link); - if (js_weakref_is_live(fre->token) && js_same_value(ctx, fre->token, token)) { - js_weakref_free(ctx->rt, fre->target); - js_weakref_free(ctx->rt, fre->token); - JS_FreeValue(ctx, fre->held_val); - list_del(&fre->link); - js_free(ctx, fre); - removed = TRUE; - } - } - return JS_NewBool(ctx, removed); -} - -static const JSCFunctionListEntry js_finrec_proto_funcs[] = { - JS_CFUNC_DEF("register", 2, js_finrec_register ), - JS_CFUNC_DEF("unregister", 1, js_finrec_unregister ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "FinalizationRegistry", JS_PROP_CONFIGURABLE ), -}; - -static const JSClassShortDef js_finrec_class_def[] = { - { JS_ATOM_FinalizationRegistry, js_finrec_finalizer, js_finrec_mark }, /* JS_CLASS_FINALIZATION_REGISTRY */ -}; - -void JS_AddIntrinsicWeakRef(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - - /* WeakRef */ - if (!JS_IsRegisteredClass(rt, JS_CLASS_WEAK_REF)) { - init_class_range(rt, js_weakref_class_def, JS_CLASS_WEAK_REF, - countof(js_weakref_class_def)); - } - ctx->class_proto[JS_CLASS_WEAK_REF] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_WEAK_REF], - js_weakref_proto_funcs, - countof(js_weakref_proto_funcs)); - JS_NewGlobalCConstructor(ctx, "WeakRef", js_weakref_constructor, 1, ctx->class_proto[JS_CLASS_WEAK_REF]); - - /* FinalizationRegistry */ - if (!JS_IsRegisteredClass(rt, JS_CLASS_FINALIZATION_REGISTRY)) { - init_class_range(rt, js_finrec_class_def, JS_CLASS_FINALIZATION_REGISTRY, - countof(js_finrec_class_def)); - } - ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY], - js_finrec_proto_funcs, - countof(js_finrec_proto_funcs)); - JS_NewGlobalCConstructor(ctx, "FinalizationRegistry", js_finrec_constructor, 1, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY]); -} - #define STRLEN(s) (sizeof(s)/sizeof(s[0])) #define CSTR "" diff --git a/source/quickjs.h b/source/quickjs.h index a84775ce..54b5518d 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -400,7 +400,6 @@ void JS_AddIntrinsicRegExp(JSContext *ctx); void JS_AddIntrinsicJSON(JSContext *ctx); void JS_AddIntrinsicProxy(JSContext *ctx); void JS_AddIntrinsicMapSet(JSContext *ctx); -void JS_AddIntrinsicWeakRef(JSContext *ctx); JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);