From 51b90ba3a7ba6f6a2d0e3ad6ec78ceca09b0a065 Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Wed, 25 Sep 2024 15:40:29 +0800 Subject: [PATCH 1/9] feat: add prototype inline cache for basic get/set op --- quickjs.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 226 insertions(+), 19 deletions(-) diff --git a/quickjs.c b/quickjs.c index 1086202cf..6780fcaf9 100644 --- a/quickjs.c +++ b/quickjs.c @@ -571,10 +571,24 @@ typedef enum JSFunctionKindEnum { #define IC_CACHE_ITEM_CAPACITY 4 +typedef int watchpoint_delete_callback(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom, intptr_t target); +typedef int watchpoint_free_callback(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom); + +typedef struct JSInlineCacheWatchpoint { + watchpoint_delete_callback *delete_callback; + watchpoint_free_callback *free_callback; + struct list_head link; + intptr_t ref; + uint32_t offset; + JSAtom atom; +} JSInlineCacheWatchpoint; + typedef struct JSInlineCacheRingSlot { - /* SoA for space optimization: 56 bytes */ + /* SoA for space optimization: 120 bytes */ JSShape* shape[IC_CACHE_ITEM_CAPACITY]; uint32_t prop_offset[IC_CACHE_ITEM_CAPACITY]; + JSObject* proto[IC_CACHE_ITEM_CAPACITY]; + JSInlineCacheWatchpoint* watchpoint_ref[IC_CACHE_ITEM_CAPACITY]; JSAtom atom; uint8_t index; } JSInlineCacheRingSlot; @@ -600,10 +614,22 @@ static int rebuild_ic(JSContext *ctx, JSInlineCache *ic); static int resize_ic_hash(JSContext *ctx, JSInlineCache *ic); static int free_ic(JSRuntime *rt, JSInlineCache *ic); static uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *object, - uint32_t prop_offset); + uint32_t prop_offset, JSObject* prototype); + +static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom); +static int ic_free_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape); + +static int ic_watchpoint_delete_handler(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom, intptr_t target); +static int ic_watchpoint_free_handler(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom); + +static int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, intptr_t target); +static int js_shape_free_watchpoints(JSRuntime *rt, JSShape *shape); +static JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, intptr_t ptr, uint8_t offset, JSAtom atom, + watchpoint_delete_callback *delete_callback, + watchpoint_free_callback *free_callback); static int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, - JSShape *shape) + JSShape *shape, JSObject **prototype) { uint32_t i; JSInlineCacheRingSlot *cr; @@ -615,6 +641,7 @@ static int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, shape_slot = *(cr->shape + i); if (likely(shape_slot == shape)) { cr->index = i; + *prototype = cr->proto[i]; return cr->prop_offset[i]; } @@ -623,7 +650,8 @@ static int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, break; } } - + + *prototype = NULL; return -1; } @@ -882,6 +910,7 @@ struct JSShape { int deleted_prop_count; JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */ JSObject *proto; + struct list_head *watchpoint; /* watchpoint for prototype inline cache */ JSShapeProperty prop[]; /* prop_size elements */ }; @@ -4428,6 +4457,7 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, sh->hash = shape_initial_hash(proto); sh->is_hashed = TRUE; sh->has_small_array_index = FALSE; + sh->watchpoint = NULL; js_shape_hash_link(ctx->rt, sh); return sh; } @@ -4459,6 +4489,7 @@ static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1) sh->header.ref_count = 1; add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); sh->is_hashed = FALSE; + sh->watchpoint = NULL; if (sh->proto) { js_dup(JS_MKPTR(JS_TAG_OBJECT, sh->proto)); } @@ -4485,6 +4516,7 @@ static void js_free_shape0(JSRuntime *rt, JSShape *sh) if (sh->proto != NULL) { JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); } + js_shape_free_watchpoints(rt, sh); pr = get_shape_prop(sh); for(i = 0; i < sh->prop_count; i++) { JS_FreeAtomRT(rt, pr->atom); @@ -5680,6 +5712,7 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, /* the template objects can be part of a cycle */ { JSShape **shape, *(*shapes)[IC_CACHE_ITEM_CAPACITY]; + JSObject **proto, *(*protos)[IC_CACHE_ITEM_CAPACITY]; JSFunctionBytecode *b = (JSFunctionBytecode *)gp; int i; for(i = 0; i < b->cpool_count; i++) { @@ -5693,6 +5726,10 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, for (shape = *shapes; shape != endof(*shapes); shape++) if (*shape) mark_func(rt, &(*shape)->header); + protos = &b->ic->cache[i].proto; + for (proto = *protos; proto != endof(*protos); proto++) + if (*proto) + mark_func(rt, &(*proto)->header); } } } @@ -7018,6 +7055,7 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValue obj, if (js_shape_prepare_update(ctx, p, NULL)) return -1; sh = p->shape; + ic_free_shape_proto_watchpoints(ctx->rt, sh); if (sh->proto) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); sh->proto = proto; @@ -7234,7 +7272,7 @@ static JSValue JS_GetPropertyInternal2(JSContext *ctx, JSValue obj, JSAtom prop, JSValue this_obj, JSInlineCache* ic, BOOL throw_ref_error) { - JSObject *p; + JSObject *p, *p1; JSProperty *pr; JSShapeProperty *prs; uint32_t tag, offset, proto_depth; @@ -7275,6 +7313,7 @@ static JSValue JS_GetPropertyInternal2(JSContext *ctx, JSValue obj, p = JS_VALUE_GET_OBJ(obj); } + p1 = p; for(;;) { prs = find_own_property_ic(&pr, p, prop, &offset); if (prs) { @@ -7301,9 +7340,9 @@ static JSValue JS_GetPropertyInternal2(JSContext *ctx, JSValue obj, continue; } } else { - if (ic && proto_depth == 0 && p->shape->is_hashed) { + if (ic && p1->shape->is_hashed && p->shape->is_hashed) { ic->updated = TRUE; - ic->updated_offset = add_ic_slot(ctx, ic, prop, p, offset); + ic->updated_offset = add_ic_slot(ctx, ic, prop, p1, offset, proto_depth > 0 ? p : NULL); } return js_dup(pr->u.value); } @@ -7397,14 +7436,17 @@ static JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValue obj, BOOL throw_ref_error) { uint32_t tag; - JSObject *p; + JSObject *p, *proto; tag = JS_VALUE_GET_TAG(obj); if (unlikely(tag != JS_TAG_OBJECT)) goto slow_path; p = JS_VALUE_GET_OBJ(obj); - offset = get_ic_prop_offset(ic, offset, p->shape); - if (likely(offset >= 0)) - return js_dup(p->prop[offset].u.value); + offset = get_ic_prop_offset(ic, offset, p->shape, &proto); + if (likely(offset >= 0)) { + if (proto) + p = proto; + return JS_DupValue(ctx, p->prop[offset].u.value); + } slow_path: return JS_GetPropertyInternal2(ctx, obj, prop, this_obj, ic, throw_ref_error); } @@ -8327,7 +8369,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) pr->flags = 0; pr->atom = JS_ATOM_NULL; pr1->u.value = JS_UNDEFINED; - + ic_delete_shape_proto_watchpoints(ctx->rt, sh, atom); /* compact the properties if too many deleted properties */ if (sh->deleted_prop_count >= 8 && sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { @@ -8588,7 +8630,7 @@ static int JS_SetPropertyInternal2(JSContext *ctx, JSValue obj, /* fast case */ if (ic && p->shape->is_hashed) { ic->updated = TRUE; - ic->updated_offset = add_ic_slot(ctx, ic, prop, p, offset); + ic->updated_offset = add_ic_slot(ctx, ic, prop, p, offset, NULL); } set_value(ctx, &pr->u.value, val); return TRUE; @@ -8751,10 +8793,16 @@ static int JS_SetPropertyInternal2(JSContext *ctx, JSValue obj, } goto generic_create_prop; } else { + ic_delete_shape_proto_watchpoints(ctx->rt, p->shape, prop); pr = add_property(ctx, p, prop, JS_PROP_C_W_E); - if (!pr) + if (unlikely(!pr)) goto fail; pr->u.value = val; + /* fast case */ + if (ic && p->shape->is_hashed) { + ic->updated = TRUE; + ic->updated_offset = add_ic_slot(ctx, ic, prop, p, p->shape->prop_count - 1, NULL); + } return TRUE; } } @@ -8817,13 +8865,15 @@ static int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValue this_obj, JSAtom prop, JSValue val, int flags, JSInlineCache *ic, int32_t offset) { uint32_t tag; - JSObject *p; + JSObject *p, *proto; tag = JS_VALUE_GET_TAG(this_obj); if (unlikely(tag != JS_TAG_OBJECT)) goto slow_path; p = JS_VALUE_GET_OBJ(this_obj); - offset = get_ic_prop_offset(ic, offset, p->shape); + offset = get_ic_prop_offset(ic, offset, p->shape, &proto); if (likely(offset >= 0)) { + if (proto) + goto slow_path; set_value(ctx, &p->prop[offset].u.value, val); return TRUE; } @@ -9201,6 +9251,62 @@ static int js_shape_prepare_update(JSContext *ctx, JSObject *p, return 0; } +int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, intptr_t target) { + struct list_head *el, *el1; + if (unlikely(!shape || !shape->watchpoint)) + goto end; + list_for_each_safe(el, el1, shape->watchpoint) { + JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); + if (o->delete_callback) + if (!o->delete_callback(rt, (intptr_t)o->ref, o->offset, o->atom, target)) { + list_del(el); + js_free_rt(rt, o); + break; + } + } +end: + return 0; +} + +int js_shape_free_watchpoints(JSRuntime *rt, JSShape *shape) { + struct list_head *el, *el1; + if (unlikely(!shape || !shape->watchpoint)) + goto end; + list_for_each_safe(el, el1, shape->watchpoint) { + JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); + if (o->free_callback) + o->free_callback(rt, (intptr_t)o->ref, o->offset, o->atom); + list_del(el); + js_free_rt(rt, o); + } + list_empty(shape->watchpoint); + js_free_rt(rt, shape->watchpoint); +end: + return 0; +} + +JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, intptr_t ptr, uint8_t offset, JSAtom atom, + watchpoint_delete_callback *delete_callback, + watchpoint_free_callback *free_callback) +{ + JSInlineCacheWatchpoint *o; + o = (JSInlineCacheWatchpoint *)js_malloc_rt(rt, sizeof(JSInlineCacheWatchpoint)); + if (unlikely(!o)) + return NULL; + o->ref = ptr; + o->atom = atom; + o->offset = offset; + o->delete_callback = delete_callback; + o->free_callback = free_callback; + if (!shape->watchpoint) { + shape->watchpoint = (struct list_head *)js_malloc_rt(rt, sizeof(struct list_head)); + init_list_head(shape->watchpoint); + } + init_list_head(&o->link); + list_add_tail(&o->link, shape->watchpoint); + return o; +} + static int js_update_property_flags(JSContext *ctx, JSObject *p, JSShapeProperty **pprs, int flags) { @@ -54013,12 +54119,23 @@ int free_ic(JSRuntime* rt, JSInlineCache *ic) uint32_t i; JSInlineCacheHashSlot *ch, *ch_next; JSShape **shape, *(*shapes)[IC_CACHE_ITEM_CAPACITY]; + JSInlineCacheWatchpoint **ref, *(*refs)[IC_CACHE_ITEM_CAPACITY], *o; if (ic->cache) { for (i = 0; i < ic->count; i++) { shapes = &ic->cache[i].shape; JS_FreeAtomRT(rt, ic->cache[i].atom); for (shape = *shapes; shape != endof(*shapes); shape++) js_free_shape_null(rt, *shape); + refs = &ic->cache[i].watchpoint_ref; + for (ref = *refs; ref != endof(*refs); ref++) { + o = *ref; + if (o) { + if (o->free_callback) + o->free_callback(rt, (intptr_t)o->ref ,o->offset, o->atom); + list_del(&o->link); + js_free_rt(rt, o); + } + } } } for (i = 0; i < ic->capacity; i++) { @@ -54036,9 +54153,9 @@ int free_ic(JSRuntime* rt, JSInlineCache *ic) } uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *object, - uint32_t prop_offset) + uint32_t prop_offset, JSObject* prototype) { - int32_t i; + uint8_t i; uint32_t h; JSInlineCacheHashSlot *ch; JSInlineCacheRingSlot *cr; @@ -54055,7 +54172,7 @@ uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *o assert(cr != NULL); i = cr->index; for (;;) { - if (object->shape == cr->shape[i]) { + if (object->shape == cr->shape[i] && prototype == cr->proto[i]) { cr->prop_offset[i] = prop_offset; goto end; } @@ -54064,13 +54181,103 @@ uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *o break; } sh = cr->shape[i]; + if (cr->watchpoint_ref[i]) + js_shape_delete_watchpoints(ctx->rt, sh, (intptr_t)cr); cr->shape[i] = js_dup_shape(object->shape); js_free_shape_null(ctx->rt, sh); cr->prop_offset[i] = prop_offset; + if (prototype) { + JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, prototype)); + cr->proto[i] = prototype; + cr->watchpoint_ref[i] = js_shape_create_watchpoint(ctx->rt, cr->shape[i], (intptr_t)cr, i, + JS_DupAtom(ctx, atom), + ic_watchpoint_delete_handler, + ic_watchpoint_free_handler); + } + end: return ch->index; } +int ic_watchpoint_delete_handler(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom, intptr_t target) { + JSInlineCacheRingSlot *cr; + cr = (JSInlineCacheRingSlot *) ref; + if(ref != target) + return 1; + assert(cr->proto[offset] != NULL); + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, cr->proto[offset])); + JS_FreeAtomRT(rt, atom); + cr->watchpoint_ref[offset] = NULL; + cr->proto[offset] = NULL; + cr->prop_offset[offset] = 0; + cr->shape[offset] = NULL; + return 0; +} + +int ic_watchpoint_free_handler(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom) { + JSInlineCacheRingSlot *cr; + cr = (JSInlineCacheRingSlot *) ref; + assert(cr->watchpoint_ref[offset] != NULL); + assert(cr->proto[offset] != NULL); + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, cr->proto[offset])); + JS_FreeAtomRT(rt, atom); + cr->watchpoint_ref[offset] = NULL; + cr->proto[offset] = NULL; + cr->prop_offset[offset] = 0; + cr->shape[offset] = NULL; + return 0; +} + +int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom) { + struct list_head *el, *el1; + JSObject *p; + JSInlineCacheRingSlot *cr; + JSShape *sh; + p = shape->proto; + while(likely(p)) { + if (p->shape->watchpoint) + list_for_each_safe(el, el1, p->shape->watchpoint) { + JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); + if (o->atom == atom) { + cr = (JSInlineCacheRingSlot *)o->ref; + sh = cr->shape[o->offset]; + o->delete_callback = NULL; + o->free_callback = NULL; + ic_watchpoint_free_handler(rt, (intptr_t)cr, o->offset, o->atom); + js_free_shape_null(rt, shape); + list_del(el); + js_free_rt(rt, o); + } + } + p = p->shape->proto; + } + return 0; +} + +int ic_free_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape) { + struct list_head *el, *el1; + JSObject *p; + JSInlineCacheRingSlot *cr; + JSShape *sh; + p = shape->proto; + while(likely(p)) { + if (p->shape->watchpoint) + list_for_each_safe(el, el1, p->shape->watchpoint) { + JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); + cr = (JSInlineCacheRingSlot *)o->ref; + sh = cr->shape[o->offset]; + o->delete_callback = NULL; + o->free_callback = NULL; + ic_watchpoint_free_handler(rt, (intptr_t)cr, o->offset, o->atom); + js_free_shape_null(rt, shape); + list_del(el); + js_free_rt(rt, o); + } + p = p->shape->proto; + } + return 0; +} + /* CallSite */ static void js_callsite_finalizer(JSRuntime *rt, JSValue val) From 25df15503099c798ed2c3d9387d3db3a21d76c02 Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Wed, 25 Sep 2024 16:05:30 +0800 Subject: [PATCH 2/9] fix: cr->index should be changed when ic missing --- quickjs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/quickjs.c b/quickjs.c index cc0454458..582da45f1 100644 --- a/quickjs.c +++ b/quickjs.c @@ -54420,8 +54420,10 @@ uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *o goto end; } i = (i + 1) % countof(cr->shape); - if (unlikely(i == cr->index)) + if (unlikely(i == cr->index)) { + cr->index = (cr->index + 1) % countof(cr->shape); break; + } } sh = cr->shape[i]; if (cr->watchpoint_ref[i]) From 2ed62d958f99c9898a1c141f64f4f9c6e6b97de8 Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Wed, 25 Sep 2024 16:35:01 +0800 Subject: [PATCH 3/9] feat: enable ic for OP_get_field2 and force_inline ic get/set methods --- quickjs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/quickjs.c b/quickjs.c index 582da45f1..56462fe95 100644 --- a/quickjs.c +++ b/quickjs.c @@ -630,7 +630,7 @@ static JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShap watchpoint_delete_callback *delete_callback, watchpoint_free_callback *free_callback); -static int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, +static force_inline int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, JSShape *shape, JSObject **prototype) { uint32_t i; @@ -7427,7 +7427,7 @@ JSValue JS_GetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop) return JS_GetPropertyInternal2(ctx, this_obj, prop, this_obj, NULL, FALSE); } -static JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValue obj, +static force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValue obj, JSAtom prop, JSValue this_obj, JSInlineCache *ic, int32_t offset, BOOL throw_ref_error) @@ -8858,7 +8858,7 @@ int JS_SetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop, JSValue val) return JS_SetPropertyInternal2(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW, NULL); } -static int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValue this_obj, +static force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValue this_obj, JSAtom prop, JSValue val, int flags, JSInlineCache *ic, int32_t offset) { uint32_t tag; @@ -16210,7 +16210,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj, atom = get_u32(pc); pc += 4; sf->cur_pc = pc; - val = JS_GetPropertyInternal2(ctx, sp[-1], atom, sp[-1], NULL, FALSE); + val = JS_GetPropertyInternal2(ctx, sp[-1], atom, sp[-1], ic, FALSE); if (unlikely(JS_IsException(val))) goto exception; if (ic != NULL && ic->updated == TRUE) { @@ -54428,9 +54428,9 @@ uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *o sh = cr->shape[i]; if (cr->watchpoint_ref[i]) js_shape_delete_watchpoints(ctx->rt, sh, (intptr_t)cr); + cr->prop_offset[i] = prop_offset; cr->shape[i] = js_dup_shape(object->shape); js_free_shape_null(ctx->rt, sh); - cr->prop_offset[i] = prop_offset; if (prototype) { JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, prototype)); cr->proto[i] = prototype; From d43f4ef6c497751dd7048516da34086ea82d9458 Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Wed, 9 Oct 2024 12:17:25 +0800 Subject: [PATCH 4/9] feat: prototype ICs code modifications and optimizations --- quickjs.c | 90 ++++++++++++++++++++----------------------------------- 1 file changed, 33 insertions(+), 57 deletions(-) diff --git a/quickjs.c b/quickjs.c index 72e55dfb2..ac2370c67 100644 --- a/quickjs.c +++ b/quickjs.c @@ -584,14 +584,9 @@ typedef enum JSFunctionKindEnum { #define IC_CACHE_ITEM_CAPACITY 4 -typedef int watchpoint_delete_callback(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom, intptr_t target); -typedef int watchpoint_free_callback(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom); - typedef struct JSInlineCacheWatchpoint { - watchpoint_delete_callback *delete_callback; - watchpoint_free_callback *free_callback; struct list_head link; - intptr_t ref; + struct JSInlineCacheRingSlot *ref; uint32_t offset; JSAtom atom; } JSInlineCacheWatchpoint; @@ -632,14 +627,12 @@ static uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSOb static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom); static int ic_free_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape); -static int ic_watchpoint_delete_handler(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom, intptr_t target); -static int ic_watchpoint_free_handler(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom); +static int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom, JSInlineCacheRingSlot *target); +static int ic_watchpoint_free_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom); -static int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, intptr_t target); +static int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *target); static int js_shape_free_watchpoints(JSRuntime *rt, JSShape *shape); -static JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, intptr_t ptr, uint8_t offset, JSAtom atom, - watchpoint_delete_callback *delete_callback, - watchpoint_free_callback *free_callback); +static JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *ptr, uint8_t offset, JSAtom atom); static force_inline int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, JSShape *shape, JSObject **prototype) @@ -9311,14 +9304,13 @@ static int js_shape_prepare_update(JSContext *ctx, JSObject *p, return 0; } -int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, intptr_t target) { +int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *target) { struct list_head *el, *el1; if (unlikely(!shape || !shape->watchpoint)) goto end; list_for_each_safe(el, el1, shape->watchpoint) { JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); - if (o->delete_callback) - if (!o->delete_callback(rt, (intptr_t)o->ref, o->offset, o->atom, target)) { + if (!ic_watchpoint_delete_handler(rt, o->ref, o->offset, o->atom, target)) { list_del(el); js_free_rt(rt, o); break; @@ -9334,8 +9326,7 @@ int js_shape_free_watchpoints(JSRuntime *rt, JSShape *shape) { goto end; list_for_each_safe(el, el1, shape->watchpoint) { JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); - if (o->free_callback) - o->free_callback(rt, (intptr_t)o->ref, o->offset, o->atom); + ic_watchpoint_free_handler(rt, o->ref, o->offset, o->atom); list_del(el); js_free_rt(rt, o); } @@ -9345,21 +9336,17 @@ int js_shape_free_watchpoints(JSRuntime *rt, JSShape *shape) { return 0; } -JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, intptr_t ptr, uint8_t offset, JSAtom atom, - watchpoint_delete_callback *delete_callback, - watchpoint_free_callback *free_callback) +JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *ptr, uint8_t offset, JSAtom atom) { JSInlineCacheWatchpoint *o; - o = (JSInlineCacheWatchpoint *)js_malloc_rt(rt, sizeof(JSInlineCacheWatchpoint)); + o = js_malloc_rt(rt, sizeof(*o)); if (unlikely(!o)) return NULL; o->ref = ptr; o->atom = atom; o->offset = offset; - o->delete_callback = delete_callback; - o->free_callback = free_callback; if (!shape->watchpoint) { - shape->watchpoint = (struct list_head *)js_malloc_rt(rt, sizeof(struct list_head)); + shape->watchpoint = js_malloc_rt(rt, sizeof(*shape->watchpoint)); init_list_head(shape->watchpoint); } init_list_head(&o->link); @@ -54570,8 +54557,7 @@ int free_ic(JSRuntime* rt, JSInlineCache *ic) for (ref = *refs; ref != endof(*refs); ref++) { o = *ref; if (o) { - if (o->free_callback) - o->free_callback(rt, (intptr_t)o->ref ,o->offset, o->atom); + ic_watchpoint_free_handler(rt, o->ref ,o->offset, o->atom); list_del(&o->link); js_free_rt(rt, o); } @@ -54624,49 +54610,43 @@ uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *o } sh = cr->shape[i]; if (cr->watchpoint_ref[i]) - js_shape_delete_watchpoints(ctx->rt, sh, (intptr_t)cr); + js_shape_delete_watchpoints(ctx->rt, sh, cr); cr->prop_offset[i] = prop_offset; cr->shape[i] = js_dup_shape(object->shape); js_free_shape_null(ctx->rt, sh); if (prototype) { JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, prototype)); cr->proto[i] = prototype; - cr->watchpoint_ref[i] = js_shape_create_watchpoint(ctx->rt, cr->shape[i], (intptr_t)cr, i, - JS_DupAtom(ctx, atom), - ic_watchpoint_delete_handler, - ic_watchpoint_free_handler); + cr->watchpoint_ref[i] = js_shape_create_watchpoint(ctx->rt, cr->shape[i], cr, i, + JS_DupAtom(ctx, atom)); } end: return ch->index; } -int ic_watchpoint_delete_handler(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom, intptr_t target) { - JSInlineCacheRingSlot *cr; - cr = (JSInlineCacheRingSlot *) ref; - if(ref != target) +int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom, JSInlineCacheRingSlot *target) { + if (ref != target) return 1; - assert(cr->proto[offset] != NULL); - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, cr->proto[offset])); + assert(ref->proto[offset] != NULL); + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ref->proto[offset])); JS_FreeAtomRT(rt, atom); - cr->watchpoint_ref[offset] = NULL; - cr->proto[offset] = NULL; - cr->prop_offset[offset] = 0; - cr->shape[offset] = NULL; + ref->watchpoint_ref[offset] = NULL; + ref->proto[offset] = NULL; + ref->prop_offset[offset] = 0; + ref->shape[offset] = NULL; return 0; } -int ic_watchpoint_free_handler(JSRuntime* rt, intptr_t ref, uint8_t offset, JSAtom atom) { - JSInlineCacheRingSlot *cr; - cr = (JSInlineCacheRingSlot *) ref; - assert(cr->watchpoint_ref[offset] != NULL); - assert(cr->proto[offset] != NULL); - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, cr->proto[offset])); +int ic_watchpoint_free_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom) { + assert(ref->watchpoint_ref[offset] != NULL); + assert(ref->proto[offset] != NULL); + JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ref->proto[offset])); JS_FreeAtomRT(rt, atom); - cr->watchpoint_ref[offset] = NULL; - cr->proto[offset] = NULL; - cr->prop_offset[offset] = 0; - cr->shape[offset] = NULL; + ref->watchpoint_ref[offset] = NULL; + ref->proto[offset] = NULL; + ref->prop_offset[offset] = 0; + ref->shape[offset] = NULL; return 0; } @@ -54683,9 +54663,7 @@ int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom if (o->atom == atom) { cr = (JSInlineCacheRingSlot *)o->ref; sh = cr->shape[o->offset]; - o->delete_callback = NULL; - o->free_callback = NULL; - ic_watchpoint_free_handler(rt, (intptr_t)cr, o->offset, o->atom); + ic_watchpoint_free_handler(rt, cr, o->offset, o->atom); js_free_shape_null(rt, shape); list_del(el); js_free_rt(rt, o); @@ -54708,9 +54686,7 @@ int ic_free_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape) { JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); cr = (JSInlineCacheRingSlot *)o->ref; sh = cr->shape[o->offset]; - o->delete_callback = NULL; - o->free_callback = NULL; - ic_watchpoint_free_handler(rt, (intptr_t)cr, o->offset, o->atom); + ic_watchpoint_free_handler(rt, cr, o->offset, o->atom); js_free_shape_null(rt, shape); list_del(el); js_free_rt(rt, o); From e2ec966716e81be645808787c005d3f5c402d154 Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Fri, 29 Nov 2024 00:31:22 +0800 Subject: [PATCH 5/9] fix: repair the ref_count release issue caused by add_ic_slot --- quickjs.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/quickjs.c b/quickjs.c index 906960e76..8a2ba9092 100644 --- a/quickjs.c +++ b/quickjs.c @@ -7447,8 +7447,7 @@ static JSValue JS_GetPropertyInternal2(JSContext *ctx, JSValue obj, continue; } } else { - if (p1->shape->is_hashed && p->shape->is_hashed) - add_ic_slot(ctx, icu, prop, p, offset, proto_depth > 0 ? p : NULL); + add_ic_slot(ctx, icu, prop, p1, offset, proto_depth > 0 ? p : NULL); return js_dup(pr->u.value); } } @@ -8744,8 +8743,7 @@ static int JS_SetPropertyInternal2(JSContext *ctx, JSValue obj, JSAtom prop, if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) { /* fast case */ - if (p->shape->is_hashed) - add_ic_slot(ctx, icu, prop, p, offset, NULL); + add_ic_slot(ctx, icu, prop, p, offset, NULL); set_value(ctx, &pr->u.value, val); return TRUE; } else if (prs->flags & JS_PROP_LENGTH) { @@ -8913,8 +8911,7 @@ static int JS_SetPropertyInternal2(JSContext *ctx, JSValue obj, JSAtom prop, goto fail; pr->u.value = val; /* fast case */ - if (p->shape->is_hashed) - add_ic_slot(ctx, icu, prop, p, p->shape->prop_count - 1, NULL); + add_ic_slot(ctx, icu, prop, p, p->shape->prop_count - 1, NULL); return TRUE; } } @@ -55948,7 +55945,7 @@ static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, JSInlineCacheHashSlot *ch; JSInlineCacheRingSlot *cr; JSInlineCache *ic; - JSShape *sh; + JSShape *sh, *psh; if (!icu) return; @@ -55958,6 +55955,10 @@ static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, sh = object->shape; if (!sh->is_hashed) return; + psh = prototype ? prototype->shape : NULL; + if (psh && !psh->is_hashed) { + return; + } cr = NULL; h = get_index_hash(atom, ic->hash_bits); for (ch = ic->hash[h]; ch != NULL; ch = ch->next) { @@ -55981,7 +55982,7 @@ static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, } while (i != cr->index); sh = cr->shape[i]; if (cr->watchpoint_ref[i]) - js_shape_delete_watchpoints(ctx->rt, sh, cr); + js_shape_delete_watchpoints(ctx->rt, cr->shape[i], cr); cr->prop_offset[i] = prop_offset; cr->shape[i] = js_dup_shape(object->shape); js_free_shape_null(ctx->rt, sh); From db482eea39a95a622fca53622daa045c84f550af Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Fri, 29 Nov 2024 01:43:37 +0800 Subject: [PATCH 6/9] fix: remove ic watchpoints free function call --- quickjs.c | 50 +++++++++++--------------------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/quickjs.c b/quickjs.c index 8a2ba9092..d787b8ca6 100644 --- a/quickjs.c +++ b/quickjs.c @@ -637,10 +637,8 @@ static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAt static int ic_free_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape); static int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom, JSInlineCacheRingSlot *target); -static int ic_watchpoint_free_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom); static int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *target); -static int js_shape_free_watchpoints(JSRuntime *rt, JSShape *shape); static JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *ptr, uint8_t offset, JSAtom atom); static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, JSAtom atom, JSObject *object, uint32_t prop_offset, JSObject* prototype); @@ -4596,7 +4594,7 @@ static void js_free_shape0(JSRuntime *rt, JSShape *sh) if (sh->proto != NULL) { JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); } - js_shape_free_watchpoints(rt, sh); + js_shape_delete_watchpoints(rt, sh, NULL); pr = get_shape_prop(sh); for(i = 0; i < sh->prop_count; i++) { JS_FreeAtomRT(rt, pr->atom); @@ -9372,22 +9370,10 @@ int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, JSInlineCacheRing break; } } -end: - return 0; -} - -int js_shape_free_watchpoints(JSRuntime *rt, JSShape *shape) { - struct list_head *el, *el1; - if (unlikely(!shape || !shape->watchpoint)) - goto end; - list_for_each_safe(el, el1, shape->watchpoint) { - JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); - ic_watchpoint_free_handler(rt, o->ref, o->offset, o->atom); - list_del(el); - js_free_rt(rt, o); + if (!target) { + list_empty(shape->watchpoint); + js_free_rt(rt, shape->watchpoint); } - list_empty(shape->watchpoint); - js_free_rt(rt, shape->watchpoint); end: return 0; } @@ -55916,7 +55902,7 @@ int free_ic(JSRuntime* rt, JSInlineCache *ic) for (ref = *refs; ref != endof(*refs); ref++) { o = *ref; if (o) { - ic_watchpoint_free_handler(rt, o->ref ,o->offset, o->atom); + ic_watchpoint_delete_handler(rt, o->ref ,o->offset, o->atom, NULL); list_del(&o->link); js_free_rt(rt, o); } @@ -55945,7 +55931,7 @@ static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, JSInlineCacheHashSlot *ch; JSInlineCacheRingSlot *cr; JSInlineCache *ic; - JSShape *sh, *psh; + JSShape *sh; if (!icu) return; @@ -55955,10 +55941,8 @@ static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, sh = object->shape; if (!sh->is_hashed) return; - psh = prototype ? prototype->shape : NULL; - if (psh && !psh->is_hashed) { + if (prototype && !prototype->shape->is_hashed) return; - } cr = NULL; h = get_index_hash(atom, ic->hash_bits); for (ch = ic->hash[h]; ch != NULL; ch = ch->next) { @@ -55982,7 +55966,7 @@ static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, } while (i != cr->index); sh = cr->shape[i]; if (cr->watchpoint_ref[i]) - js_shape_delete_watchpoints(ctx->rt, cr->shape[i], cr); + js_shape_delete_watchpoints(ctx->rt, sh, cr); cr->prop_offset[i] = prop_offset; cr->shape[i] = js_dup_shape(object->shape); js_free_shape_null(ctx->rt, sh); @@ -55996,7 +55980,7 @@ static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, } int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom, JSInlineCacheRingSlot *target) { - if (ref != target) + if (target && ref != target) return 1; assert(ref->proto[offset] != NULL); JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ref->proto[offset])); @@ -56008,18 +55992,6 @@ int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint return 0; } -int ic_watchpoint_free_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom) { - assert(ref->watchpoint_ref[offset] != NULL); - assert(ref->proto[offset] != NULL); - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ref->proto[offset])); - JS_FreeAtomRT(rt, atom); - ref->watchpoint_ref[offset] = NULL; - ref->proto[offset] = NULL; - ref->prop_offset[offset] = 0; - ref->shape[offset] = NULL; - return 0; -} - int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom) { struct list_head *el, *el1; JSObject *p; @@ -56033,7 +56005,7 @@ int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom if (o->atom == atom) { cr = (JSInlineCacheRingSlot *)o->ref; sh = cr->shape[o->offset]; - ic_watchpoint_free_handler(rt, cr, o->offset, o->atom); + ic_watchpoint_delete_handler(rt, cr, o->offset, o->atom, NULL); js_free_shape_null(rt, shape); list_del(el); js_free_rt(rt, o); @@ -56056,7 +56028,7 @@ int ic_free_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape) { JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); cr = (JSInlineCacheRingSlot *)o->ref; sh = cr->shape[o->offset]; - ic_watchpoint_free_handler(rt, cr, o->offset, o->atom); + ic_watchpoint_delete_handler(rt, cr, o->offset, o->atom, NULL); js_free_shape_null(rt, shape); list_del(el); js_free_rt(rt, o); From 9f1ce566016a1d46c7a9c5236e645f1945c56033 Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Fri, 29 Nov 2024 18:31:57 +0800 Subject: [PATCH 7/9] fix: remove force_inline and watchpoint free function call --- quickjs.c | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/quickjs.c b/quickjs.c index d787b8ca6..ae8e16ad8 100644 --- a/quickjs.c +++ b/quickjs.c @@ -633,17 +633,14 @@ static JSInlineCache *init_ic(JSContext *ctx); static int rebuild_ic(JSContext *ctx, JSInlineCache *ic); static int resize_ic_hash(JSContext *ctx, JSInlineCache *ic); static int free_ic(JSRuntime *rt, JSInlineCache *ic); -static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom); -static int ic_free_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape); - +static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, bool force); static int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom, JSInlineCacheRingSlot *target); - static int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *target); static JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *ptr, uint8_t offset, JSAtom atom); static void add_ic_slot(JSContext *ctx, JSInlineCacheUpdate *icu, JSAtom atom, JSObject *object, uint32_t prop_offset, JSObject* prototype); -static force_inline uint32_t get_ic_prop_offset(const JSInlineCacheUpdate *icu, +static uint32_t get_ic_prop_offset(const JSInlineCacheUpdate *icu, JSShape *shape, JSObject **prototype) { uint32_t i, cache_offset = icu->offset; @@ -7159,7 +7156,7 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValue obj, if (js_shape_prepare_update(ctx, p, NULL)) return -1; sh = p->shape; - ic_free_shape_proto_watchpoints(ctx->rt, sh); + ic_delete_shape_proto_watchpoints(ctx->rt, sh, JS_ATOM_NULL, TRUE); if (sh->proto) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); sh->proto = proto; @@ -7532,7 +7529,7 @@ JSValue JS_GetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop) return JS_GetPropertyInternal2(ctx, this_obj, prop, this_obj, NULL, FALSE); } -static force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValue obj, +static inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValue obj, JSAtom prop, JSValue this_obj, JSInlineCacheUpdate *icu, BOOL throw_ref_error) @@ -8482,7 +8479,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) pr->flags = 0; pr->atom = JS_ATOM_NULL; pr1->u.value = JS_UNDEFINED; - ic_delete_shape_proto_watchpoints(ctx->rt, sh, atom); + ic_delete_shape_proto_watchpoints(ctx->rt, sh, atom, FALSE); /* compact the properties if too many deleted properties */ if (sh->deleted_prop_count >= 8 && sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { @@ -8903,7 +8900,7 @@ static int JS_SetPropertyInternal2(JSContext *ctx, JSValue obj, JSAtom prop, } goto generic_create_prop; } else { - ic_delete_shape_proto_watchpoints(ctx->rt, p->shape, prop); + ic_delete_shape_proto_watchpoints(ctx->rt, p->shape, prop, FALSE); pr = add_property(ctx, p, prop, JS_PROP_C_W_E); if (unlikely(!pr)) goto fail; @@ -8969,7 +8966,7 @@ int JS_SetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop, JSValue val) } // XXX(bnoordhuis) only used by OP_put_field_ic, maybe inline at call site -static force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValue this_obj, +static inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValue this_obj, JSAtom prop, JSValue val, int flags, JSInlineCacheUpdate *icu) { uint32_t tag, offset; @@ -55992,7 +55989,7 @@ int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint return 0; } -int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom) { +int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, bool force) { struct list_head *el, *el1; JSObject *p; JSInlineCacheRingSlot *cr; @@ -56002,7 +55999,7 @@ int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom if (p->shape->watchpoint) list_for_each_safe(el, el1, p->shape->watchpoint) { JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); - if (o->atom == atom) { + if (force || o->atom == atom) { cr = (JSInlineCacheRingSlot *)o->ref; sh = cr->shape[o->offset]; ic_watchpoint_delete_handler(rt, cr, o->offset, o->atom, NULL); @@ -56016,28 +56013,6 @@ int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom return 0; } -int ic_free_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape) { - struct list_head *el, *el1; - JSObject *p; - JSInlineCacheRingSlot *cr; - JSShape *sh; - p = shape->proto; - while(likely(p)) { - if (p->shape->watchpoint) - list_for_each_safe(el, el1, p->shape->watchpoint) { - JSInlineCacheWatchpoint *o = list_entry(el, JSInlineCacheWatchpoint, link); - cr = (JSInlineCacheRingSlot *)o->ref; - sh = cr->shape[o->offset]; - ic_watchpoint_delete_handler(rt, cr, o->offset, o->atom, NULL); - js_free_shape_null(rt, shape); - list_del(el); - js_free_rt(rt, o); - } - p = p->shape->proto; - } - return 0; -} - /* CallSite */ static void js_callsite_finalizer(JSRuntime *rt, JSValue val) From 7826ad88a50948a5c4398d89f1f9c03e5e3ca3d9 Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Fri, 29 Nov 2024 18:37:56 +0800 Subject: [PATCH 8/9] fix: should use BOOL instead of bool at ic_delete_shape_proto_watchpoints --- quickjs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickjs.c b/quickjs.c index ae8e16ad8..aa2ae7931 100644 --- a/quickjs.c +++ b/quickjs.c @@ -633,7 +633,7 @@ static JSInlineCache *init_ic(JSContext *ctx); static int rebuild_ic(JSContext *ctx, JSInlineCache *ic); static int resize_ic_hash(JSContext *ctx, JSInlineCache *ic); static int free_ic(JSRuntime *rt, JSInlineCache *ic); -static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, bool force); +static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, BOOL force); static int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom, JSInlineCacheRingSlot *target); static int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *target); static JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *ptr, uint8_t offset, JSAtom atom); @@ -55989,7 +55989,7 @@ int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint return 0; } -int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, bool force) { +int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, BOOL force) { struct list_head *el, *el1; JSObject *p; JSInlineCacheRingSlot *cr; From 617dbe0e92921f53bc1bac756e664e023146dca8 Mon Sep 17 00:00:00 2001 From: "yang.zhao2" Date: Tue, 21 Jan 2025 14:33:07 +0800 Subject: [PATCH 9/9] fix BOOL to bool type macro --- quickjs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/quickjs.c b/quickjs.c index 3aab01b67..39adf089c 100644 --- a/quickjs.c +++ b/quickjs.c @@ -634,7 +634,7 @@ static JSInlineCache *init_ic(JSContext *ctx); static int rebuild_ic(JSContext *ctx, JSInlineCache *ic); static int resize_ic_hash(JSContext *ctx, JSInlineCache *ic); static int free_ic(JSRuntime *rt, JSInlineCache *ic); -static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, BOOL force); +static int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, bool force); static int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint8_t offset, JSAtom atom, JSInlineCacheRingSlot *target); static int js_shape_delete_watchpoints(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *target); static JSInlineCacheWatchpoint *js_shape_create_watchpoint(JSRuntime *rt, JSShape *shape, JSInlineCacheRingSlot *ptr, uint8_t offset, JSAtom atom); @@ -7179,7 +7179,7 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValue obj, if (js_shape_prepare_update(ctx, p, NULL)) return -1; sh = p->shape; - ic_delete_shape_proto_watchpoints(ctx->rt, sh, JS_ATOM_NULL, TRUE); + ic_delete_shape_proto_watchpoints(ctx->rt, sh, JS_ATOM_NULL, true); if (sh->proto) JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); sh->proto = proto; @@ -8502,7 +8502,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) pr->flags = 0; pr->atom = JS_ATOM_NULL; pr1->u.value = JS_UNDEFINED; - ic_delete_shape_proto_watchpoints(ctx->rt, sh, atom, FALSE); + ic_delete_shape_proto_watchpoints(ctx->rt, sh, atom, false); /* compact the properties if too many deleted properties */ if (sh->deleted_prop_count >= 8 && sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { @@ -8923,7 +8923,7 @@ static int JS_SetPropertyInternal2(JSContext *ctx, JSValue obj, JSAtom prop, } goto generic_create_prop; } else { - ic_delete_shape_proto_watchpoints(ctx->rt, p->shape, prop, FALSE); + ic_delete_shape_proto_watchpoints(ctx->rt, p->shape, prop, false); pr = add_property(ctx, p, prop, JS_PROP_C_W_E); if (unlikely(!pr)) goto fail; @@ -56086,7 +56086,7 @@ int ic_watchpoint_delete_handler(JSRuntime* rt, JSInlineCacheRingSlot *ref, uint return 0; } -int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, BOOL force) { +int ic_delete_shape_proto_watchpoints(JSRuntime *rt, JSShape *shape, JSAtom atom, bool force) { struct list_head *el, *el1; JSObject *p; JSInlineCacheRingSlot *cr;