mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-31 07:23:06 +08:00
Skip NULL children and key-cache walks when disposing dynamic values (#2201)
This commit is contained in:
@@ -480,7 +480,12 @@ struct ScrDyn {
|
|||||||
* exits, and those clear it before release; reuse of a freed object
|
* exits, and those clear it before release; reuse of a freed object
|
||||||
* resets it (scr_dyn_alloc). */
|
* resets it (scr_dyn_alloc). */
|
||||||
const char *class_name;
|
const char *class_name;
|
||||||
struct ScrDynRegion *region; /* see ScrDynRegion */
|
union {
|
||||||
|
struct ScrDynRegion *region; /* see ScrDynRegion */
|
||||||
|
/* While the node is pooled: the key bytes it keeps for reuse,
|
||||||
|
* counted in the pool's key budget (scr_dyn_obj_drop_keys). */
|
||||||
|
size_t cached_key_bytes;
|
||||||
|
};
|
||||||
/* The dynamic tier's hidden class (scr_js_object.c): the transition
|
/* The dynamic tier's hidden class (scr_js_object.c): the transition
|
||||||
* tree node naming this object's key sequence, or NULL while it has
|
* tree node naming this object's key sequence, or NULL while it has
|
||||||
* none. Only programs with dynamic-tier code read or maintain it:
|
* none. Only programs with dynamic-tier code read or maintain it:
|
||||||
|
|||||||
@@ -846,15 +846,21 @@ static SCR_TL size_t scr_dyn_cached_key_bytes;
|
|||||||
#define SCR_DYN_KEY_CACHE_LENGTH 64
|
#define SCR_DYN_KEY_CACHE_LENGTH 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void scr_dyn_obj_drop_keys(ScrDyn *d, bool cache) {
|
/* Returns the key bytes it kept for reuse, which it added to the budget;
|
||||||
|
* the pooled node records them (v.obj.cached_key_bytes) so its reuse takes
|
||||||
|
* them back without walking its slots. */
|
||||||
|
static size_t scr_dyn_obj_drop_keys(ScrDyn *d, bool cache) {
|
||||||
|
size_t kept = 0;
|
||||||
for (size_t i = 0; i < d->v.obj.cap; i++) {
|
for (size_t i = 0; i < d->v.obj.cap; i++) {
|
||||||
ScrDynEntry *entry = &d->v.obj.entries[i];
|
ScrDynEntry *entry = &d->v.obj.entries[i];
|
||||||
if (!entry->key) continue;
|
if (!entry->key) continue;
|
||||||
#ifndef SCR_RC_AUDIT
|
#ifndef SCR_RC_AUDIT
|
||||||
|
size_t bytes = sizeof(ScrDynKey) + entry->key_len + 1;
|
||||||
if (cache && d->v.obj.cap <= SCR_DYN_KEY_CACHE_SLOTS &&
|
if (cache && d->v.obj.cap <= SCR_DYN_KEY_CACHE_SLOTS &&
|
||||||
entry->key_len <= SCR_DYN_KEY_CACHE_LENGTH &&
|
entry->key_len <= SCR_DYN_KEY_CACHE_LENGTH &&
|
||||||
sizeof(ScrDynKey) + entry->key_len + 1 <= SCR_DYN_KEY_CACHE_MAX - scr_dyn_cached_key_bytes) {
|
bytes <= SCR_DYN_KEY_CACHE_MAX - scr_dyn_cached_key_bytes) {
|
||||||
scr_dyn_cached_key_bytes += sizeof(ScrDynKey) + entry->key_len + 1;
|
scr_dyn_cached_key_bytes += bytes;
|
||||||
|
kept += bytes;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -864,6 +870,7 @@ static void scr_dyn_obj_drop_keys(ScrDyn *d, bool cache) {
|
|||||||
entry->key = NULL;
|
entry->key = NULL;
|
||||||
entry->key_len = 0;
|
entry->key_len = 0;
|
||||||
}
|
}
|
||||||
|
return kept;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Primitive kinds cannot acquire properties or change kind while live, so
|
/* Primitive kinds cannot acquire properties or change kind while live, so
|
||||||
@@ -1054,15 +1061,11 @@ static ScrDyn *scr_dyn_alloc(ScrDynKind kind) {
|
|||||||
d->v.arr.region = NULL;
|
d->v.arr.region = NULL;
|
||||||
} else if (kind == SCR_DYN_OBJ) {
|
} else if (kind == SCR_DYN_OBJ) {
|
||||||
d->v.obj.len = 0; /* cap/entries preserved */
|
d->v.obj.len = 0; /* cap/entries preserved */
|
||||||
|
/* The kept keys leave the pool's budget with the node. */
|
||||||
|
scr_dyn_cached_key_bytes -= d->v.obj.cached_key_bytes;
|
||||||
d->v.obj.region = NULL;
|
d->v.obj.region = NULL;
|
||||||
d->v.obj.class_name = NULL; /* a released class prototype's name */
|
d->v.obj.class_name = NULL; /* a released class prototype's name */
|
||||||
SCR_JS_SHAPE_RESET(d);
|
SCR_JS_SHAPE_RESET(d);
|
||||||
if (d->v.obj.cap <= SCR_DYN_KEY_CACHE_SLOTS) {
|
|
||||||
for (size_t i = 0; i < d->v.obj.cap; i++) {
|
|
||||||
ScrDynEntry *entry = &d->v.obj.entries[i];
|
|
||||||
if (entry->key) scr_dyn_cached_key_bytes -= sizeof(ScrDynKey) + entry->key_len + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d->v.obj.source_identity = NULL;
|
d->v.obj.source_identity = NULL;
|
||||||
d->v.obj.source_access = NULL;
|
d->v.obj.source_access = NULL;
|
||||||
} else if (kind != SCR_DYN_NUM && kind != SCR_DYN_STR) {
|
} else if (kind != SCR_DYN_NUM && kind != SCR_DYN_STR) {
|
||||||
@@ -1128,6 +1131,12 @@ static inline void scr_dyn_weak_dispose(ScrDyn *d) {
|
|||||||
if (scr_weak_observing) scr_weak_disposed(d);
|
if (scr_weak_observing) scr_weak_disposed(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A disposed node's child: most getters, setters, prototypes and symbol
|
||||||
|
* tables are NULL, and the test costs less than the call. */
|
||||||
|
static inline void scr_dyn_release_child(ScrDyn *child) {
|
||||||
|
if (child) scr_dyn_release(child);
|
||||||
|
}
|
||||||
|
|
||||||
static void scr_dyn_dispose(ScrDyn *d, bool collected) {
|
static void scr_dyn_dispose(ScrDyn *d, bool collected) {
|
||||||
#ifndef SCR_RC_AUDIT
|
#ifndef SCR_RC_AUDIT
|
||||||
/* A capsule with nothing but its referent and adapters: the common end
|
/* A capsule with nothing but its referent and adapters: the common end
|
||||||
@@ -1149,9 +1158,9 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) {
|
|||||||
d->v.obj.index = NULL;
|
d->v.obj.index = NULL;
|
||||||
}
|
}
|
||||||
if (d->kind == SCR_DYN_ARR || d->kind == SCR_DYN_OBJ) scr_dyn_region_leave(d);
|
if (d->kind == SCR_DYN_ARR || d->kind == SCR_DYN_OBJ) scr_dyn_region_leave(d);
|
||||||
if (!collected) scr_dyn_release(d->prototype);
|
if (!collected) scr_dyn_release_child(d->prototype);
|
||||||
if (!collected) scr_dyn_release(d->symbol_properties);
|
if (!collected) scr_dyn_release_child(d->symbol_properties);
|
||||||
if (!collected) scr_dyn_release(d->symbol_keys);
|
if (!collected) scr_dyn_release_child(d->symbol_keys);
|
||||||
/* Pooled nodes keep all three NULL (scr_dyn_leaf_alloc relies on it). */
|
/* Pooled nodes keep all three NULL (scr_dyn_leaf_alloc relies on it). */
|
||||||
d->prototype = d->symbol_properties = d->symbol_keys = NULL;
|
d->prototype = d->symbol_properties = d->symbol_keys = NULL;
|
||||||
switch (d->kind) {
|
switch (d->kind) {
|
||||||
@@ -1171,17 +1180,17 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) {
|
|||||||
free(d->v.arr.presence);
|
free(d->v.arr.presence);
|
||||||
d->v.arr.presence = NULL;
|
d->v.arr.presence = NULL;
|
||||||
if (!collected) {
|
if (!collected) {
|
||||||
for (size_t i = 0; i < d->v.arr.len; i++) scr_dyn_release(d->v.arr.items[i]);
|
for (size_t i = 0; i < d->v.arr.len; i++) scr_dyn_release_child(d->v.arr.items[i]);
|
||||||
scr_dyn_release(d->v.arr.properties);
|
scr_dyn_release_child(d->v.arr.properties);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SCR_DYN_OBJ:
|
case SCR_DYN_OBJ:
|
||||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||||
ScrDyn *value = d->v.obj.entries[i].value;
|
ScrDyn *value = d->v.obj.entries[i].value;
|
||||||
if (!collected || !d->v.obj.entries[i].value_traced) scr_dyn_release(value);
|
if (!collected || !d->v.obj.entries[i].value_traced) scr_dyn_release_child(value);
|
||||||
if (!collected) {
|
if (!collected) {
|
||||||
scr_dyn_release(d->v.obj.entries[i].getter);
|
scr_dyn_release_child(d->v.obj.entries[i].getter);
|
||||||
scr_dyn_release(d->v.obj.entries[i].setter);
|
scr_dyn_release_child(d->v.obj.entries[i].setter);
|
||||||
}
|
}
|
||||||
d->v.obj.entries[i].value = NULL;
|
d->v.obj.entries[i].value = NULL;
|
||||||
d->v.obj.entries[i].getter = NULL;
|
d->v.obj.entries[i].getter = NULL;
|
||||||
@@ -1207,7 +1216,7 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) {
|
|||||||
|
|
||||||
case SCR_DYN_TYPED_REF:
|
case SCR_DYN_TYPED_REF:
|
||||||
scr_typed_ref_forget(d);
|
scr_typed_ref_forget(d);
|
||||||
if (!collected) scr_dyn_release(d->v.typed_ref.materialized);
|
if (!collected) scr_dyn_release_child(d->v.typed_ref.materialized);
|
||||||
while (d->v.typed_ref.casts) {
|
while (d->v.typed_ref.casts) {
|
||||||
ScrDynTypedCast *cast = d->v.typed_ref.casts;
|
ScrDynTypedCast *cast = d->v.typed_ref.casts;
|
||||||
d->v.typed_ref.casts = cast->next;
|
d->v.typed_ref.casts = cast->next;
|
||||||
@@ -1218,8 +1227,8 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) {
|
|||||||
break;
|
break;
|
||||||
case SCR_DYN_PROXY:
|
case SCR_DYN_PROXY:
|
||||||
if (!collected) {
|
if (!collected) {
|
||||||
scr_dyn_release(d->v.proxy.target);
|
scr_dyn_release_child(d->v.proxy.target);
|
||||||
scr_dyn_release(d->v.proxy.handler);
|
scr_dyn_release_child(d->v.proxy.handler);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1230,7 +1239,7 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) {
|
|||||||
#endif
|
#endif
|
||||||
#ifndef SCR_RC_AUDIT
|
#ifndef SCR_RC_AUDIT
|
||||||
if (!collected && scr_dyn_free_count < SCR_DYN_FREE_MAX) {
|
if (!collected && scr_dyn_free_count < SCR_DYN_FREE_MAX) {
|
||||||
if (d->kind == SCR_DYN_OBJ) scr_dyn_obj_drop_keys(d, true);
|
if (d->kind == SCR_DYN_OBJ) d->v.obj.cached_key_bytes = scr_dyn_obj_drop_keys(d, true);
|
||||||
/* Pooled blocks retain their headers and count toward the bounded
|
/* Pooled blocks retain their headers and count toward the bounded
|
||||||
* allocated heap, but never remain in a candidate buffer. */
|
* allocated heap, but never remain in a candidate buffer. */
|
||||||
scr_dyn_weak_dispose(d);
|
scr_dyn_weak_dispose(d);
|
||||||
|
|||||||
Reference in New Issue
Block a user