Generalize weakref handling logic
This commit is contained in:
parent
331356625e
commit
1df9615638
1 changed files with 69 additions and 31 deletions
100
quickjs.c
100
quickjs.c
|
@ -419,6 +419,18 @@ typedef union JSFloat64Union {
|
||||||
uint32_t u32[2];
|
uint32_t u32[2];
|
||||||
} JSFloat64Union;
|
} JSFloat64Union;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
JS_WEAK_REF_KIND_MAP,
|
||||||
|
} JSWeakRefKindEnum;
|
||||||
|
|
||||||
|
typedef struct JSWeakRefRecord {
|
||||||
|
JSWeakRefKindEnum kind;
|
||||||
|
struct JSWeakRefRecord *next_weak_ref;
|
||||||
|
union {
|
||||||
|
struct JSMapRecord *map_record;
|
||||||
|
} u;
|
||||||
|
} JSWeakRefRecord;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
JS_ATOM_TYPE_STRING = 1,
|
JS_ATOM_TYPE_STRING = 1,
|
||||||
JS_ATOM_TYPE_GLOBAL_SYMBOL,
|
JS_ATOM_TYPE_GLOBAL_SYMBOL,
|
||||||
|
@ -449,7 +461,7 @@ struct JSString {
|
||||||
uint32_t hash : 30;
|
uint32_t hash : 30;
|
||||||
uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
|
uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
|
||||||
uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
|
uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
|
||||||
struct JSMapRecord *first_weak_ref;
|
JSWeakRefRecord *first_weak_ref;
|
||||||
#ifdef DUMP_LEAKS
|
#ifdef DUMP_LEAKS
|
||||||
struct list_head link; /* string list */
|
struct list_head link; /* string list */
|
||||||
#endif
|
#endif
|
||||||
|
@ -802,7 +814,7 @@ struct JSObject {
|
||||||
JSShape *shape; /* prototype and property names + flag */
|
JSShape *shape; /* prototype and property names + flag */
|
||||||
JSProperty *prop; /* array of properties */
|
JSProperty *prop; /* array of properties */
|
||||||
/* byte offsets: 24/40 */
|
/* byte offsets: 24/40 */
|
||||||
struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */
|
JSWeakRefRecord *first_weak_ref;
|
||||||
/* byte offsets: 28/48 */
|
/* byte offsets: 28/48 */
|
||||||
union {
|
union {
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
@ -1056,7 +1068,7 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p,
|
||||||
JSValueConst getter, JSValueConst setter,
|
JSValueConst getter, JSValueConst setter,
|
||||||
int flags);
|
int flags);
|
||||||
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
|
static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
|
||||||
static void reset_weak_ref(JSRuntime *rt, struct JSMapRecord **first_weak_ref);
|
static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref);
|
||||||
static JSValue js_array_buffer_constructor3(JSContext *ctx,
|
static JSValue js_array_buffer_constructor3(JSContext *ctx,
|
||||||
JSValueConst new_target,
|
JSValueConst new_target,
|
||||||
uint64_t len, JSClassID class_id,
|
uint64_t len, JSClassID class_id,
|
||||||
|
@ -43521,7 +43533,6 @@ typedef struct JSMapRecord {
|
||||||
int ref_count; /* used during enumeration to avoid freeing the record */
|
int ref_count; /* used during enumeration to avoid freeing the record */
|
||||||
BOOL empty; /* TRUE if the record is deleted */
|
BOOL empty; /* TRUE if the record is deleted */
|
||||||
struct JSMapState *map;
|
struct JSMapState *map;
|
||||||
struct JSMapRecord *next_weak_ref;
|
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
struct list_head hash_link;
|
struct list_head hash_link;
|
||||||
JSValue key;
|
JSValue key;
|
||||||
|
@ -43754,7 +43765,7 @@ static void map_hash_resize(JSContext *ctx, JSMapState *s)
|
||||||
s->record_count_threshold = new_hash_size * 2;
|
s->record_count_threshold = new_hash_size * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSMapRecord **get_first_weak_ref(JSValueConst key)
|
static JSWeakRefRecord **get_first_weak_ref(JSValueConst key)
|
||||||
{
|
{
|
||||||
switch (JS_VALUE_GET_TAG(key)) {
|
switch (JS_VALUE_GET_TAG(key)) {
|
||||||
case JS_TAG_OBJECT:
|
case JS_TAG_OBJECT:
|
||||||
|
@ -43778,7 +43789,7 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
|
||||||
JSValueConst key)
|
JSValueConst key)
|
||||||
{
|
{
|
||||||
uint32_t h;
|
uint32_t h;
|
||||||
JSMapRecord *mr, **pmr;
|
JSMapRecord *mr;
|
||||||
|
|
||||||
mr = js_malloc(ctx, sizeof(*mr));
|
mr = js_malloc(ctx, sizeof(*mr));
|
||||||
if (!mr)
|
if (!mr)
|
||||||
|
@ -43787,10 +43798,18 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
|
||||||
mr->map = s;
|
mr->map = s;
|
||||||
mr->empty = FALSE;
|
mr->empty = FALSE;
|
||||||
if (s->is_weak) {
|
if (s->is_weak) {
|
||||||
pmr = get_first_weak_ref(key);
|
JSWeakRefRecord *wr, **pwr;
|
||||||
|
wr = js_malloc(ctx, sizeof(*wr));
|
||||||
|
if (!wr) {
|
||||||
|
js_free(ctx, mr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
wr->kind = JS_WEAK_REF_KIND_MAP;
|
||||||
|
wr->u.map_record = mr;
|
||||||
|
pwr = get_first_weak_ref(key);
|
||||||
/* Add the weak reference */
|
/* Add the weak reference */
|
||||||
mr->next_weak_ref = *pmr;
|
wr->next_weak_ref = *pwr;
|
||||||
*pmr = mr;
|
*pwr = wr;
|
||||||
} else {
|
} else {
|
||||||
JS_DupValue(ctx, key);
|
JS_DupValue(ctx, key);
|
||||||
}
|
}
|
||||||
|
@ -43809,19 +43828,20 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
|
||||||
reference list. we don't use a doubly linked list to
|
reference list. we don't use a doubly linked list to
|
||||||
save space, assuming a given object has few weak
|
save space, assuming a given object has few weak
|
||||||
references to it */
|
references to it */
|
||||||
static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr)
|
static void delete_map_weak_ref(JSRuntime *rt, JSMapRecord *mr)
|
||||||
{
|
{
|
||||||
JSMapRecord **pmr, *mr1;
|
JSWeakRefRecord **pwr, *wr;
|
||||||
|
|
||||||
pmr = get_first_weak_ref(mr->key);
|
pwr = get_first_weak_ref(mr->key);
|
||||||
for(;;) {
|
for(;;) {
|
||||||
mr1 = *pmr;
|
wr = *pwr;
|
||||||
assert(mr1 != NULL);
|
assert(wr != NULL);
|
||||||
if (mr1 == mr)
|
if (wr->kind == JS_WEAK_REF_KIND_MAP && wr->u.map_record == mr)
|
||||||
break;
|
break;
|
||||||
pmr = &mr1->next_weak_ref;
|
pwr = &wr->next_weak_ref;
|
||||||
}
|
}
|
||||||
*pmr = mr1->next_weak_ref;
|
*pwr = wr->next_weak_ref;
|
||||||
|
js_free_rt(rt, wr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
|
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)
|
||||||
return;
|
return;
|
||||||
list_del(&mr->hash_link);
|
list_del(&mr->hash_link);
|
||||||
if (s->is_weak) {
|
if (s->is_weak) {
|
||||||
delete_weak_ref(rt, mr);
|
delete_map_weak_ref(rt, mr);
|
||||||
} else {
|
} else {
|
||||||
JS_FreeValueRT(rt, mr->key);
|
JS_FreeValueRT(rt, mr->key);
|
||||||
}
|
}
|
||||||
|
@ -43857,27 +43877,45 @@ static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset_weak_ref(JSRuntime *rt, struct JSMapRecord **first_weak_ref)
|
static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
|
||||||
{
|
{
|
||||||
JSMapRecord *mr, *mr_next;
|
JSWeakRefRecord *wr, *wr_next;
|
||||||
|
JSMapRecord *mr;
|
||||||
JSMapState *s;
|
JSMapState *s;
|
||||||
|
|
||||||
/* first pass to remove the records from the WeakMap/WeakSet
|
/* first pass to remove the records from the WeakMap/WeakSet
|
||||||
lists */
|
lists */
|
||||||
for(mr = *first_weak_ref; mr != NULL; mr = mr->next_weak_ref) {
|
for(wr = *first_weak_ref; wr != NULL; wr = wr->next_weak_ref) {
|
||||||
s = mr->map;
|
switch(wr->kind) {
|
||||||
assert(s->is_weak);
|
case JS_WEAK_REF_KIND_MAP: {
|
||||||
assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
|
mr = wr->u.map_record;
|
||||||
list_del(&mr->hash_link);
|
s = mr->map;
|
||||||
list_del(&mr->link);
|
assert(s->is_weak);
|
||||||
|
assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
|
||||||
|
list_del(&mr->hash_link);
|
||||||
|
list_del(&mr->link);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* second pass to free the values to avoid modifying the weak
|
/* second pass to free the values to avoid modifying the weak
|
||||||
reference list while traversing it. */
|
reference list while traversing it. */
|
||||||
for(mr = *first_weak_ref; mr != NULL; mr = mr_next) {
|
for(wr = *first_weak_ref; wr != NULL; wr = wr_next) {
|
||||||
mr_next = mr->next_weak_ref;
|
wr_next = wr->next_weak_ref;
|
||||||
JS_FreeValueRT(rt, mr->value);
|
switch(wr->kind) {
|
||||||
js_free_rt(rt, mr);
|
case JS_WEAK_REF_KIND_MAP: {
|
||||||
|
mr = wr->u.map_record;
|
||||||
|
JS_FreeValueRT(rt, mr->value);
|
||||||
|
js_free_rt(rt, mr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
js_free_rt(rt, wr);
|
||||||
}
|
}
|
||||||
|
|
||||||
*first_weak_ref = NULL; /* fail safe */
|
*first_weak_ref = NULL; /* fail safe */
|
||||||
|
@ -44149,7 +44187,7 @@ static void js_map_finalizer(JSRuntime *rt, JSValue val)
|
||||||
mr = list_entry(el, JSMapRecord, link);
|
mr = list_entry(el, JSMapRecord, link);
|
||||||
if (!mr->empty) {
|
if (!mr->empty) {
|
||||||
if (s->is_weak)
|
if (s->is_weak)
|
||||||
delete_weak_ref(rt, mr);
|
delete_map_weak_ref(rt, mr);
|
||||||
else
|
else
|
||||||
JS_FreeValueRT(rt, mr->key);
|
JS_FreeValueRT(rt, mr->key);
|
||||||
JS_FreeValueRT(rt, mr->value);
|
JS_FreeValueRT(rt, mr->value);
|
||||||
|
|
Loading…
Reference in a new issue