uint16_t binary_object_count;
int binary_object_size;
- /* TRUE if the array prototype is "normal":
- - no small index properties which are get/set or non writable
- - its prototype is Object.prototype
- - Object.prototype has no small index properties which are get/set or non writable
- - the prototype of Object.prototype is null (always true as it is immutable)
- */
- uint8_t std_array_prototype;
JSShape *array_shape; /* initial shape for Array objects */
JSShape *arguments_shape; /* shape for arguments objects */
struct {
int __gc_ref_count; /* corresponds to header.ref_count */
uint8_t __gc_mark : 7; /* corresponds to header.mark/gc_obj_type */
- uint8_t is_prototype : 1; /* object may be used as prototype */
+ /* TRUE if the array prototype is "normal":
+ - no small index properties which are get/set or non writable
+ - its prototype is Object.prototype
+ - Object.prototype has no small index properties which are get/set or non writable
+ - the prototype of Object.prototype is null (always true as it is immutable)
+ */
+ uint8_t is_std_array_prototype : 1;
uint8_t extensible : 1;
uint8_t free_mark : 1; /* only used when freeing objects with cycles */
if (unlikely(!p))
goto fail;
p->class_id = class_id;
- p->is_prototype = 0;
+ p->is_std_array_prototype = 0;
p->extensible = TRUE;
p->free_mark = 0;
p->is_exotic = 0;
if (sh->proto)
JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
sh->proto = proto;
- if (proto)
- proto->is_prototype = TRUE;
- if (p->is_prototype) {
- /* track modification of Array.prototype */
- if (unlikely(p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]))) {
- ctx->std_array_prototype = FALSE;
- }
- }
+ p->is_std_array_prototype = FALSE;
return TRUE;
}
{
JSShape *sh, *new_sh;
- if (unlikely(p->is_prototype)) {
- /* track addition of small integer properties to Array.prototype and Object.prototype */
- if (unlikely((p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]) ||
- p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_OBJECT])) &&
- __JS_AtomIsTaggedInt(prop))) {
- ctx->std_array_prototype = FALSE;
+ if (unlikely(__JS_AtomIsTaggedInt(prop))) {
+ /* update is_std_array_prototype */
+ if (unlikely(p->is_std_array_prototype)) {
+ p->is_std_array_prototype = FALSE;
+ } else if (unlikely(p->has_immutable_prototype)) {
+ struct list_head *el;
+
+ /* modifying Object.prototype : reset the corresponding is_std_array_prototype */
+ list_for_each(el, &ctx->rt->context_list) {
+ JSContext *ctx1 = list_entry(el, JSContext, link);
+ if (JS_IsObject(ctx1->class_proto[JS_CLASS_OBJECT]) &&
+ JS_VALUE_GET_OBJ(ctx1->class_proto[JS_CLASS_OBJECT]) == p) {
+ if (JS_IsObject(ctx1->class_proto[JS_CLASS_ARRAY])) {
+ JSObject *p1 = JS_VALUE_GET_OBJ(ctx1->class_proto[JS_CLASS_ARRAY]);
+ p1->is_std_array_prototype = FALSE;
+ }
+ break;
+ }
+ }
}
}
sh = p->shape;
p->u.array.u.values = NULL; /* fail safe */
p->u.array.u1.size = 0;
p->fast_array = 0;
-
- /* track modification of Array.prototype */
- if (unlikely(p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]))) {
- ctx->std_array_prototype = FALSE;
- }
+ p->is_std_array_prototype = FALSE;
return 0;
}
}
}
+/* return true if an element can be added to a fast array without further tests */
+static force_inline BOOL can_extend_fast_array(JSObject *p)
+{
+ JSObject *proto;
+ if (!p->extensible)
+ return FALSE;
+ proto = p->shape->proto;
+ if (!proto)
+ return TRUE;
+ return proto->is_std_array_prototype;
+}
+
/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
JSValue prop, JSValue val, int flags)
/* fast path to add an element to the array */
if (unlikely(idx != (uint32_t)p->u.array.count ||
!p->fast_array ||
- !p->extensible ||
- p->shape->proto != JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]) ||
- !ctx->std_array_prototype)) {
+ !can_extend_fast_array(p))) {
goto slow_path;
}
/* add element */
uint32_t new_len, array_len;
if (unlikely(idx != (uint32_t)p->u.array.count ||
!p->fast_array ||
- !p->extensible ||
- p->shape->proto != JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]) ||
- !ctx->std_array_prototype)) {
+ !can_extend_fast_array(p))) {
goto put_array_el_slow_path;
}
if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT))
if (likely(JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT && !unshift)) {
JSObject *p = JS_VALUE_GET_OBJ(this_val);
if (likely(p->class_id == JS_CLASS_ARRAY && p->fast_array &&
- p->extensible &&
- p->shape->proto == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]) &&
- ctx->std_array_prototype &&
+ can_extend_fast_array(p) &&
JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT &&
JS_VALUE_GET_INT(p->prop[0].u.value) == p->u.array.count &&
(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE) != 0)) {
return -1;
ctx->array_ctor = obj;
+ {
+ JSObject *p = JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]);
+ p->is_std_array_prototype = TRUE;
+ }
+
ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
JS_PROP_INITIAL_HASH_SIZE, 1);
if (!ctx->array_shape)
if (add_shape_property(ctx, &ctx->array_shape, NULL,
JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH))
return -1;
- ctx->std_array_prototype = TRUE;
ctx->arguments_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_OBJECT]),
JS_PROP_INITIAL_HASH_SIZE, 3);