Skip to content

Commit 1df9615

Browse files
committed
Generalize weakref handling logic
1 parent 3313566 commit 1df9615

File tree

1 file changed

+69
-31
lines changed

1 file changed

+69
-31
lines changed

quickjs.c

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,18 @@ typedef union JSFloat64Union {
419419
uint32_t u32[2];
420420
} JSFloat64Union;
421421

422+
typedef enum {
423+
JS_WEAK_REF_KIND_MAP,
424+
} JSWeakRefKindEnum;
425+
426+
typedef struct JSWeakRefRecord {
427+
JSWeakRefKindEnum kind;
428+
struct JSWeakRefRecord *next_weak_ref;
429+
union {
430+
struct JSMapRecord *map_record;
431+
} u;
432+
} JSWeakRefRecord;
433+
422434
enum {
423435
JS_ATOM_TYPE_STRING = 1,
424436
JS_ATOM_TYPE_GLOBAL_SYMBOL,
@@ -449,7 +461,7 @@ struct JSString {
449461
uint32_t hash : 30;
450462
uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
451463
uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
452-
struct JSMapRecord *first_weak_ref;
464+
JSWeakRefRecord *first_weak_ref;
453465
#ifdef DUMP_LEAKS
454466
struct list_head link; /* string list */
455467
#endif
@@ -802,7 +814,7 @@ struct JSObject {
802814
JSShape *shape; /* prototype and property names + flag */
803815
JSProperty *prop; /* array of properties */
804816
/* byte offsets: 24/40 */
805-
struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */
817+
JSWeakRefRecord *first_weak_ref;
806818
/* byte offsets: 28/48 */
807819
union {
808820
void *opaque;
@@ -1056,7 +1068,7 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p,
10561068
JSValueConst getter, JSValueConst setter,
10571069
int flags);
10581070
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
1059-
static void reset_weak_ref(JSRuntime *rt, struct JSMapRecord **first_weak_ref);
1071+
static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref);
10601072
static JSValue js_array_buffer_constructor3(JSContext *ctx,
10611073
JSValueConst new_target,
10621074
uint64_t len, JSClassID class_id,
@@ -43521,7 +43533,6 @@ typedef struct JSMapRecord {
4352143533
int ref_count; /* used during enumeration to avoid freeing the record */
4352243534
BOOL empty; /* TRUE if the record is deleted */
4352343535
struct JSMapState *map;
43524-
struct JSMapRecord *next_weak_ref;
4352543536
struct list_head link;
4352643537
struct list_head hash_link;
4352743538
JSValue key;
@@ -43754,7 +43765,7 @@ static void map_hash_resize(JSContext *ctx, JSMapState *s)
4375443765
s->record_count_threshold = new_hash_size * 2;
4375543766
}
4375643767

43757-
static JSMapRecord **get_first_weak_ref(JSValueConst key)
43768+
static JSWeakRefRecord **get_first_weak_ref(JSValueConst key)
4375843769
{
4375943770
switch (JS_VALUE_GET_TAG(key)) {
4376043771
case JS_TAG_OBJECT:
@@ -43778,7 +43789,7 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
4377843789
JSValueConst key)
4377943790
{
4378043791
uint32_t h;
43781-
JSMapRecord *mr, **pmr;
43792+
JSMapRecord *mr;
4378243793

4378343794
mr = js_malloc(ctx, sizeof(*mr));
4378443795
if (!mr)
@@ -43787,10 +43798,18 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
4378743798
mr->map = s;
4378843799
mr->empty = FALSE;
4378943800
if (s->is_weak) {
43790-
pmr = get_first_weak_ref(key);
43801+
JSWeakRefRecord *wr, **pwr;
43802+
wr = js_malloc(ctx, sizeof(*wr));
43803+
if (!wr) {
43804+
js_free(ctx, mr);
43805+
return NULL;
43806+
}
43807+
wr->kind = JS_WEAK_REF_KIND_MAP;
43808+
wr->u.map_record = mr;
43809+
pwr = get_first_weak_ref(key);
4379143810
/* Add the weak reference */
43792-
mr->next_weak_ref = *pmr;
43793-
*pmr = mr;
43811+
wr->next_weak_ref = *pwr;
43812+
*pwr = wr;
4379443813
} else {
4379543814
JS_DupValue(ctx, key);
4379643815
}
@@ -43809,19 +43828,20 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
4380943828
reference list. we don't use a doubly linked list to
4381043829
save space, assuming a given object has few weak
4381143830
references to it */
43812-
static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr)
43831+
static void delete_map_weak_ref(JSRuntime *rt, JSMapRecord *mr)
4381343832
{
43814-
JSMapRecord **pmr, *mr1;
43833+
JSWeakRefRecord **pwr, *wr;
4381543834

43816-
pmr = get_first_weak_ref(mr->key);
43835+
pwr = get_first_weak_ref(mr->key);
4381743836
for(;;) {
43818-
mr1 = *pmr;
43819-
assert(mr1 != NULL);
43820-
if (mr1 == mr)
43837+
wr = *pwr;
43838+
assert(wr != NULL);
43839+
if (wr->kind == JS_WEAK_REF_KIND_MAP && wr->u.map_record == mr)
4382143840
break;
43822-
pmr = &mr1->next_weak_ref;
43841+
pwr = &wr->next_weak_ref;
4382343842
}
43824-
*pmr = mr1->next_weak_ref;
43843+
*pwr = wr->next_weak_ref;
43844+
js_free_rt(rt, wr);
4382543845
}
4382643846

4382743847
static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
@@ -43830,7 +43850,7 @@ static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
4383043850
return;
4383143851
list_del(&mr->hash_link);
4383243852
if (s->is_weak) {
43833-
delete_weak_ref(rt, mr);
43853+
delete_map_weak_ref(rt, mr);
4383443854
} else {
4383543855
JS_FreeValueRT(rt, mr->key);
4383643856
}
@@ -43857,27 +43877,45 @@ static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
4385743877
}
4385843878
}
4385943879

43860-
static void reset_weak_ref(JSRuntime *rt, struct JSMapRecord **first_weak_ref)
43880+
static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
4386143881
{
43862-
JSMapRecord *mr, *mr_next;
43882+
JSWeakRefRecord *wr, *wr_next;
43883+
JSMapRecord *mr;
4386343884
JSMapState *s;
4386443885

4386543886
/* first pass to remove the records from the WeakMap/WeakSet
4386643887
lists */
43867-
for(mr = *first_weak_ref; mr != NULL; mr = mr->next_weak_ref) {
43868-
s = mr->map;
43869-
assert(s->is_weak);
43870-
assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
43871-
list_del(&mr->hash_link);
43872-
list_del(&mr->link);
43888+
for(wr = *first_weak_ref; wr != NULL; wr = wr->next_weak_ref) {
43889+
switch(wr->kind) {
43890+
case JS_WEAK_REF_KIND_MAP: {
43891+
mr = wr->u.map_record;
43892+
s = mr->map;
43893+
assert(s->is_weak);
43894+
assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
43895+
list_del(&mr->hash_link);
43896+
list_del(&mr->link);
43897+
break;
43898+
}
43899+
default:
43900+
abort();
43901+
}
4387343902
}
4387443903

4387543904
/* second pass to free the values to avoid modifying the weak
4387643905
reference list while traversing it. */
43877-
for(mr = *first_weak_ref; mr != NULL; mr = mr_next) {
43878-
mr_next = mr->next_weak_ref;
43879-
JS_FreeValueRT(rt, mr->value);
43880-
js_free_rt(rt, mr);
43906+
for(wr = *first_weak_ref; wr != NULL; wr = wr_next) {
43907+
wr_next = wr->next_weak_ref;
43908+
switch(wr->kind) {
43909+
case JS_WEAK_REF_KIND_MAP: {
43910+
mr = wr->u.map_record;
43911+
JS_FreeValueRT(rt, mr->value);
43912+
js_free_rt(rt, mr);
43913+
break;
43914+
}
43915+
default:
43916+
abort();
43917+
}
43918+
js_free_rt(rt, wr);
4388143919
}
4388243920

4388343921
*first_weak_ref = NULL; /* fail safe */
@@ -44149,7 +44187,7 @@ static void js_map_finalizer(JSRuntime *rt, JSValue val)
4414944187
mr = list_entry(el, JSMapRecord, link);
4415044188
if (!mr->empty) {
4415144189
if (s->is_weak)
44152-
delete_weak_ref(rt, mr);
44190+
delete_map_weak_ref(rt, mr);
4415344191
else
4415444192
JS_FreeValueRT(rt, mr->key);
4415544193
JS_FreeValueRT(rt, mr->value);

0 commit comments

Comments
 (0)