Implement WeakRef
This commit is contained in:
parent
1df9615638
commit
5c136edbcf
4 changed files with 129 additions and 5 deletions
|
@ -210,6 +210,7 @@ DEF(Float32Array, "Float32Array")
|
||||||
DEF(Float64Array, "Float64Array")
|
DEF(Float64Array, "Float64Array")
|
||||||
DEF(DataView, "DataView")
|
DEF(DataView, "DataView")
|
||||||
DEF(BigInt, "BigInt")
|
DEF(BigInt, "BigInt")
|
||||||
|
DEF(WeakRef, "WeakRef")
|
||||||
DEF(Map, "Map")
|
DEF(Map, "Map")
|
||||||
DEF(Set, "Set") /* Map + 1 */
|
DEF(Set, "Set") /* Map + 1 */
|
||||||
DEF(WeakMap, "WeakMap") /* Map + 2 */
|
DEF(WeakMap, "WeakMap") /* Map + 2 */
|
||||||
|
|
130
quickjs.c
130
quickjs.c
|
@ -175,6 +175,7 @@ enum {
|
||||||
JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */
|
JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */
|
||||||
JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */
|
JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */
|
||||||
JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */
|
JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */
|
||||||
|
JS_CLASS_WEAK_REF,
|
||||||
|
|
||||||
JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
|
JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
|
||||||
};
|
};
|
||||||
|
@ -419,8 +420,14 @@ typedef union JSFloat64Union {
|
||||||
uint32_t u32[2];
|
uint32_t u32[2];
|
||||||
} JSFloat64Union;
|
} JSFloat64Union;
|
||||||
|
|
||||||
|
typedef struct JSWeakRefData {
|
||||||
|
JSValue target;
|
||||||
|
JSValue obj;
|
||||||
|
} JSWeakRefData;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
JS_WEAK_REF_KIND_MAP,
|
JS_WEAK_REF_KIND_MAP,
|
||||||
|
JS_WEAK_REF_KIND_WEAK_REF,
|
||||||
} JSWeakRefKindEnum;
|
} JSWeakRefKindEnum;
|
||||||
|
|
||||||
typedef struct JSWeakRefRecord {
|
typedef struct JSWeakRefRecord {
|
||||||
|
@ -428,6 +435,7 @@ typedef struct JSWeakRefRecord {
|
||||||
struct JSWeakRefRecord *next_weak_ref;
|
struct JSWeakRefRecord *next_weak_ref;
|
||||||
union {
|
union {
|
||||||
struct JSMapRecord *map_record;
|
struct JSMapRecord *map_record;
|
||||||
|
JSWeakRefData *weak_ref_data;
|
||||||
} u;
|
} u;
|
||||||
} JSWeakRefRecord;
|
} JSWeakRefRecord;
|
||||||
|
|
||||||
|
@ -1009,6 +1017,8 @@ static void js_promise_mark(JSRuntime *rt, JSValueConst val,
|
||||||
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
|
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
|
||||||
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
|
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
|
||||||
JS_MarkFunc *mark_func);
|
JS_MarkFunc *mark_func);
|
||||||
|
static void js_weakref_finalizer(JSRuntime *rt, JSValue val);
|
||||||
|
|
||||||
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
|
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
|
||||||
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
|
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
|
||||||
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
|
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
|
||||||
|
@ -2004,6 +2014,7 @@ JSContext *JS_NewContext(JSRuntime *rt)
|
||||||
JS_AddIntrinsicTypedArrays(ctx);
|
JS_AddIntrinsicTypedArrays(ctx);
|
||||||
JS_AddIntrinsicPromise(ctx);
|
JS_AddIntrinsicPromise(ctx);
|
||||||
JS_AddIntrinsicBigInt(ctx);
|
JS_AddIntrinsicBigInt(ctx);
|
||||||
|
JS_AddIntrinsicWeakRef(ctx);
|
||||||
|
|
||||||
JS_AddPerformance(ctx);
|
JS_AddPerformance(ctx);
|
||||||
|
|
||||||
|
@ -43880,6 +43891,7 @@ static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
|
||||||
static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
|
static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
|
||||||
{
|
{
|
||||||
JSWeakRefRecord *wr, *wr_next;
|
JSWeakRefRecord *wr, *wr_next;
|
||||||
|
JSWeakRefData *wrd;
|
||||||
JSMapRecord *mr;
|
JSMapRecord *mr;
|
||||||
JSMapState *s;
|
JSMapState *s;
|
||||||
|
|
||||||
|
@ -43887,7 +43899,7 @@ static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
|
||||||
lists */
|
lists */
|
||||||
for(wr = *first_weak_ref; wr != NULL; wr = wr->next_weak_ref) {
|
for(wr = *first_weak_ref; wr != NULL; wr = wr->next_weak_ref) {
|
||||||
switch(wr->kind) {
|
switch(wr->kind) {
|
||||||
case JS_WEAK_REF_KIND_MAP: {
|
case JS_WEAK_REF_KIND_MAP:
|
||||||
mr = wr->u.map_record;
|
mr = wr->u.map_record;
|
||||||
s = mr->map;
|
s = mr->map;
|
||||||
assert(s->is_weak);
|
assert(s->is_weak);
|
||||||
|
@ -43895,7 +43907,10 @@ static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
|
||||||
list_del(&mr->hash_link);
|
list_del(&mr->hash_link);
|
||||||
list_del(&mr->link);
|
list_del(&mr->link);
|
||||||
break;
|
break;
|
||||||
}
|
case JS_WEAK_REF_KIND_WEAK_REF:
|
||||||
|
wrd = wr->u.weak_ref_data;
|
||||||
|
wrd->target = JS_UNDEFINED;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -43906,12 +43921,16 @@ static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
|
||||||
for(wr = *first_weak_ref; wr != NULL; wr = wr_next) {
|
for(wr = *first_weak_ref; wr != NULL; wr = wr_next) {
|
||||||
wr_next = wr->next_weak_ref;
|
wr_next = wr->next_weak_ref;
|
||||||
switch(wr->kind) {
|
switch(wr->kind) {
|
||||||
case JS_WEAK_REF_KIND_MAP: {
|
case JS_WEAK_REF_KIND_MAP:
|
||||||
mr = wr->u.map_record;
|
mr = wr->u.map_record;
|
||||||
JS_FreeValueRT(rt, mr->value);
|
JS_FreeValueRT(rt, mr->value);
|
||||||
js_free_rt(rt, mr);
|
js_free_rt(rt, mr);
|
||||||
break;
|
break;
|
||||||
}
|
case JS_WEAK_REF_KIND_WEAK_REF:
|
||||||
|
wrd = wr->u.weak_ref_data;
|
||||||
|
JS_SetOpaque(wrd->obj, NULL);
|
||||||
|
js_free_rt(rt, wrd);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -50542,3 +50561,106 @@ void JS_AddPerformance(JSContext *ctx)
|
||||||
JS_PROP_ENUMERABLE);
|
JS_PROP_ENUMERABLE);
|
||||||
JS_FreeValue(ctx, performance);
|
JS_FreeValue(ctx, performance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* WeakRef */
|
||||||
|
|
||||||
|
static void js_weakref_finalizer(JSRuntime *rt, JSValue val)
|
||||||
|
{
|
||||||
|
JSWeakRefData *wrd = JS_GetOpaque(val, JS_CLASS_WEAK_REF);
|
||||||
|
if (!wrd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Delete weak ref */
|
||||||
|
JSWeakRefRecord **pwr, *wr;
|
||||||
|
|
||||||
|
pwr = get_first_weak_ref(wrd->target);
|
||||||
|
for(;;) {
|
||||||
|
wr = *pwr;
|
||||||
|
assert(wr != NULL);
|
||||||
|
if (wr->kind == JS_WEAK_REF_KIND_WEAK_REF && wr->u.weak_ref_data == wrd)
|
||||||
|
break;
|
||||||
|
pwr = &wr->next_weak_ref;
|
||||||
|
}
|
||||||
|
*pwr = wr->next_weak_ref;
|
||||||
|
js_free_rt(rt, wrd);
|
||||||
|
js_free_rt(rt, wr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSValue js_weakref_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv)
|
||||||
|
{
|
||||||
|
if (JS_IsUndefined(new_target))
|
||||||
|
return JS_ThrowTypeError(ctx, "constructor requires 'new'");
|
||||||
|
JSValue arg = argv[0];
|
||||||
|
switch (JS_VALUE_GET_TAG(arg)) {
|
||||||
|
case JS_TAG_OBJECT:
|
||||||
|
break;
|
||||||
|
case JS_TAG_SYMBOL: {
|
||||||
|
// Per spec: prohibit symbols registered with Symbol.for()
|
||||||
|
JSAtomStruct *p = JS_VALUE_GET_PTR(arg);
|
||||||
|
if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
|
||||||
|
break;
|
||||||
|
// fallthru
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return JS_ThrowTypeError(ctx, "invalid target");
|
||||||
|
}
|
||||||
|
// TODO(saghul): short-circuit if the refcount is 1?
|
||||||
|
JSValue obj = js_create_from_ctor(ctx, new_target, JS_CLASS_WEAK_REF);
|
||||||
|
if (JS_IsException(obj))
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
JSWeakRefData *wrd = js_malloc(ctx, sizeof(*wrd));
|
||||||
|
if (!wrd) {
|
||||||
|
JS_FreeValue(ctx, obj);
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
JSWeakRefRecord *wr, **pwr;
|
||||||
|
wr = js_malloc(ctx, sizeof(*wr));
|
||||||
|
if (!wr) {
|
||||||
|
JS_FreeValue(ctx, obj);
|
||||||
|
js_free(ctx, wrd);
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
wrd->target = arg;
|
||||||
|
wrd->obj = obj;
|
||||||
|
wr->kind = JS_WEAK_REF_KIND_WEAK_REF;
|
||||||
|
wr->u.weak_ref_data = wrd;
|
||||||
|
pwr = get_first_weak_ref(arg);
|
||||||
|
/* Add the weak reference */
|
||||||
|
wr->next_weak_ref = *pwr;
|
||||||
|
*pwr = wr;
|
||||||
|
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;
|
||||||
|
return JS_DupValue(ctx, wrd->target);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
|
};
|
||||||
|
|
||||||
|
void JS_AddIntrinsicWeakRef(JSContext *ctx)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = ctx->rt;
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
|
@ -364,6 +364,7 @@ JS_EXTERN void JS_AddIntrinsicMapSet(JSContext *ctx);
|
||||||
JS_EXTERN void JS_AddIntrinsicTypedArrays(JSContext *ctx);
|
JS_EXTERN void JS_AddIntrinsicTypedArrays(JSContext *ctx);
|
||||||
JS_EXTERN void JS_AddIntrinsicPromise(JSContext *ctx);
|
JS_EXTERN void JS_AddIntrinsicPromise(JSContext *ctx);
|
||||||
JS_EXTERN void JS_AddIntrinsicBigInt(JSContext *ctx);
|
JS_EXTERN void JS_AddIntrinsicBigInt(JSContext *ctx);
|
||||||
|
JS_EXTERN void JS_AddIntrinsicWeakRef(JSContext *ctx);
|
||||||
JS_EXTERN void JS_AddPerformance(JSContext *ctx);
|
JS_EXTERN void JS_AddPerformance(JSContext *ctx);
|
||||||
|
|
||||||
/* Only used for running 262 tests. TODO(saghul) add build time flag. */
|
/* Only used for running 262 tests. TODO(saghul) add build time flag. */
|
||||||
|
|
|
@ -204,7 +204,7 @@ Uint32Array
|
||||||
Uint8Array
|
Uint8Array
|
||||||
Uint8ClampedArray
|
Uint8ClampedArray
|
||||||
WeakMap
|
WeakMap
|
||||||
WeakRef=skip
|
WeakRef
|
||||||
WeakSet
|
WeakSet
|
||||||
well-formed-json-stringify
|
well-formed-json-stringify
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue