@@ -451,13 +451,6 @@ struct JSContext {
451451
452452 uint16_t binary_object_count;
453453 int binary_object_size;
454- /* TRUE if the array prototype is "normal":
455- - no small index properties which are get/set or non writable
456- - its prototype is Object.prototype
457- - Object.prototype has no small index properties which are get/set or non writable
458- - the prototype of Object.prototype is null (always true as it is immutable)
459- */
460- uint8_t std_array_prototype;
461454
462455 JSShape *array_shape; /* initial shape for Array objects */
463456 JSShape *arguments_shape; /* shape for arguments objects */
@@ -936,7 +929,13 @@ struct JSObject {
936929 struct {
937930 int __gc_ref_count; /* corresponds to header.ref_count */
938931 uint8_t __gc_mark : 7; /* corresponds to header.mark/gc_obj_type */
939- uint8_t is_prototype : 1; /* object may be used as prototype */
932+ /* TRUE if the array prototype is "normal":
933+ - no small index properties which are get/set or non writable
934+ - its prototype is Object.prototype
935+ - Object.prototype has no small index properties which are get/set or non writable
936+ - the prototype of Object.prototype is null (always true as it is immutable)
937+ */
938+ uint8_t is_std_array_prototype : 1;
940939
941940 uint8_t extensible : 1;
942941 uint8_t free_mark : 1; /* only used when freeing objects with cycles */
@@ -5206,7 +5205,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
52065205 if (unlikely(!p))
52075206 goto fail;
52085207 p->class_id = class_id;
5209- p->is_prototype = 0;
5208+ p->is_std_array_prototype = 0;
52105209 p->extensible = TRUE;
52115210 p->free_mark = 0;
52125211 p->is_exotic = 0;
@@ -7566,14 +7565,7 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
75667565 if (sh->proto)
75677566 JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
75687567 sh->proto = proto;
7569- if (proto)
7570- proto->is_prototype = TRUE;
7571- if (p->is_prototype) {
7572- /* track modification of Array.prototype */
7573- if (unlikely(p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]))) {
7574- ctx->std_array_prototype = FALSE;
7575- }
7576- }
7568+ p->is_std_array_prototype = FALSE;
75777569 return TRUE;
75787570}
75797571
@@ -8773,12 +8765,25 @@ static JSProperty *add_property(JSContext *ctx,
87738765{
87748766 JSShape *sh, *new_sh;
87758767
8776- if (unlikely(p->is_prototype)) {
8777- /* track addition of small integer properties to Array.prototype and Object.prototype */
8778- if (unlikely((p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]) ||
8779- p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_OBJECT])) &&
8780- __JS_AtomIsTaggedInt(prop))) {
8781- ctx->std_array_prototype = FALSE;
8768+ if (unlikely(__JS_AtomIsTaggedInt(prop))) {
8769+ /* update is_std_array_prototype */
8770+ if (unlikely(p->is_std_array_prototype)) {
8771+ p->is_std_array_prototype = FALSE;
8772+ } else if (unlikely(p->has_immutable_prototype)) {
8773+ struct list_head *el;
8774+
8775+ /* modifying Object.prototype : reset the corresponding is_std_array_prototype */
8776+ list_for_each(el, &ctx->rt->context_list) {
8777+ JSContext *ctx1 = list_entry(el, JSContext, link);
8778+ if (JS_IsObject(ctx1->class_proto[JS_CLASS_OBJECT]) &&
8779+ JS_VALUE_GET_OBJ(ctx1->class_proto[JS_CLASS_OBJECT]) == p) {
8780+ if (JS_IsObject(ctx1->class_proto[JS_CLASS_ARRAY])) {
8781+ JSObject *p1 = JS_VALUE_GET_OBJ(ctx1->class_proto[JS_CLASS_ARRAY]);
8782+ p1->is_std_array_prototype = FALSE;
8783+ }
8784+ break;
8785+ }
8786+ }
87828787 }
87838788 }
87848789 sh = p->shape;
@@ -8860,11 +8865,7 @@ static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
88608865 p->u.array.u.values = NULL; /* fail safe */
88618866 p->u.array.u1.size = 0;
88628867 p->fast_array = 0;
8863-
8864- /* track modification of Array.prototype */
8865- if (unlikely(p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]))) {
8866- ctx->std_array_prototype = FALSE;
8867- }
8868+ p->is_std_array_prototype = FALSE;
88688869 return 0;
88698870}
88708871
@@ -9509,6 +9510,18 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
95099510 }
95109511}
95119512
9513+ /* return true if an element can be added to a fast array without further tests */
9514+ static force_inline BOOL can_extend_fast_array(JSObject *p)
9515+ {
9516+ JSObject *proto;
9517+ if (!p->extensible)
9518+ return FALSE;
9519+ proto = p->shape->proto;
9520+ if (!proto)
9521+ return TRUE;
9522+ return proto->is_std_array_prototype;
9523+ }
9524+
95129525/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
95139526static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
95149527 JSValue prop, JSValue val, int flags)
@@ -9529,9 +9542,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
95299542 /* fast path to add an element to the array */
95309543 if (unlikely(idx != (uint32_t)p->u.array.count ||
95319544 !p->fast_array ||
9532- !p->extensible ||
9533- p->shape->proto != JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]) ||
9534- !ctx->std_array_prototype)) {
9545+ !can_extend_fast_array(p))) {
95359546 goto slow_path;
95369547 }
95379548 /* add element */
@@ -19142,9 +19153,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
1914219153 uint32_t new_len, array_len;
1914319154 if (unlikely(idx != (uint32_t)p->u.array.count ||
1914419155 !p->fast_array ||
19145- !p->extensible ||
19146- p->shape->proto != JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]) ||
19147- !ctx->std_array_prototype)) {
19156+ !can_extend_fast_array(p))) {
1914819157 goto put_array_el_slow_path;
1914919158 }
1915019159 if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT))
@@ -42117,9 +42126,7 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
4211742126 if (likely(JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT && !unshift)) {
4211842127 JSObject *p = JS_VALUE_GET_OBJ(this_val);
4211942128 if (likely(p->class_id == JS_CLASS_ARRAY && p->fast_array &&
42120- p->extensible &&
42121- p->shape->proto == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]) &&
42122- ctx->std_array_prototype &&
42129+ can_extend_fast_array(p) &&
4212342130 JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT &&
4212442131 JS_VALUE_GET_INT(p->prop[0].u.value) == p->u.array.count &&
4212542132 (get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE) != 0)) {
@@ -55408,14 +55415,18 @@ static int JS_AddIntrinsicBasicObjects(JSContext *ctx)
5540855415 return -1;
5540955416 ctx->array_ctor = obj;
5541055417
55418+ {
55419+ JSObject *p = JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]);
55420+ p->is_std_array_prototype = TRUE;
55421+ }
55422+
5541155423 ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
5541255424 JS_PROP_INITIAL_HASH_SIZE, 1);
5541355425 if (!ctx->array_shape)
5541455426 return -1;
5541555427 if (add_shape_property(ctx, &ctx->array_shape, NULL,
5541655428 JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH))
5541755429 return -1;
55418- ctx->std_array_prototype = TRUE;
5541955430
5542055431 ctx->arguments_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_OBJECT]),
5542155432 JS_PROP_INITIAL_HASH_SIZE, 3);
0 commit comments