shithub: libmujs

Download patch

ref: 88b31f342d3b159c8f6b83c5f1c26b04060b6838
parent: 7d9888b739040b9d58f1d6d0e42df98975b86d92
author: Tor Andersson <tor.andersson@artifex.com>
date: Wed Nov 2 10:29:15 EDT 2022

Allow holes at the end of a simple array.

Don't unflatten when creating with a = new Array(10).
Don't unflatten when deleting the last element.

--- a/jsarray.c
+++ b/jsarray.c
@@ -318,7 +318,7 @@
 		js_pushvalue(J, array[i].v);
 		js_setindex(J, 0, i);
 	}
-	for (i = n; i < len; ++i) {
+	for (i = len-i; i >= n; --i) {
 		js_delindex(J, 0, i);
 	}
 
@@ -350,7 +350,6 @@
 		del = len - start;
 	if (del < 0)
 		del = 0;
-
 
 	js_newarray(J);
 
--- a/jsgc.c
+++ b/jsgc.c
@@ -108,7 +108,7 @@
 		jsG_markobject(J, mark, obj->prototype);
 	if (obj->type == JS_CARRAY && obj->u.a.simple) {
 		int i;
-		for (i = 0; i < obj->u.a.length; ++i) {
+		for (i = 0; i < obj->u.a.flat_length; ++i) {
 			js_Value *v = &obj->u.a.array[i];
 			if (v->type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
 				v->u.memstr->gcmark = mark;
--- a/jsobject.c
+++ b/jsobject.c
@@ -73,7 +73,7 @@
 	}
 
 	if (self->type == JS_CARRAY && self->u.a.simple) {
-		if (js_isarrayindex(J, name, &k) && k >= 0 && k < self->u.a.length) {
+		if (js_isarrayindex(J, name, &k) && k >= 0 && k < self->u.a.flat_length) {
 			js_pushboolean(J, 1);
 			return;
 		}
@@ -189,7 +189,7 @@
 		js_pushliteral(J, "length");
 		js_setindex(J, -2, i++);
 		if (obj->u.a.simple) {
-			for (k = 0; k < obj->u.a.length; ++k) {
+			for (k = 0; k < obj->u.a.flat_length; ++k) {
 				js_itoa(name, k);
 				js_pushstring(J, name);
 				js_setindex(J, -2, i++);
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -293,7 +293,7 @@
 		io->u.iter.n = obj->u.s.length;
 
 	if (obj->type == JS_CARRAY && obj->u.a.simple)
-		io->u.iter.n = obj->u.a.length;
+		io->u.iter.n = obj->u.a.flat_length;
 
 	return io;
 }
--- a/jsrun.c
+++ b/jsrun.c
@@ -528,7 +528,7 @@
 			obj->properties = NULL;
 			js_throw(J);
 		}
-		for (i = 0; i < obj->u.a.length; ++i) {
+		for (i = 0; i < obj->u.a.flat_length; ++i) {
 			js_itoa(name, i);
 			ref = jsV_setproperty(J, obj, name);
 			ref->value = obj->u.a.array[i];
@@ -535,7 +535,8 @@
 		}
 		js_free(J, obj->u.a.array);
 		obj->u.a.simple = 0;
-		obj->u.a.capacity = 0;
+		obj->u.a.flat_length = 0;
+		obj->u.a.flat_capacity = 0;
 		obj->u.a.array = NULL;
 		js_endtry(J);
 	}
@@ -553,10 +554,11 @@
 		}
 		if (obj->u.a.simple) {
 			if (js_isarrayindex(J, name, &k)) {
-				if (k >= 0 && k < obj->u.a.length) {
+				if (k >= 0 && k < obj->u.a.flat_length) {
 					js_pushvalue(J, obj->u.a.array[k]);
 					return 1;
 				}
+				return 0;
 			}
 		}
 	}
@@ -626,9 +628,12 @@
 static int jsR_hasindex(js_State *J, js_Object *obj, int k)
 {
 	char buf[32];
-	if (obj->type == JS_CARRAY && obj->u.a.simple && k >= 0 && k < obj->u.a.length) {
-		js_pushvalue(J, obj->u.a.array[k]);
-		return 1;
+	if (obj->type == JS_CARRAY && obj->u.a.simple) {
+		if (k >= 0 && k < obj->u.a.flat_length) {
+			js_pushvalue(J, obj->u.a.array[k]);
+			return 1;
+		}
+		return 0;
 	}
 	return jsR_hasproperty(J, obj, js_itoa(buf, k));
 }
@@ -646,19 +651,21 @@
 	assert(k >= 0);
 	if (newlen > JS_ARRAYLIMIT)
 		js_rangeerror(J, "array too large");
-	if (newlen > obj->u.a.length) {
-		assert(newlen == obj->u.a.length + 1);
-		if (newlen > obj->u.a.capacity) {
-			int newcap = obj->u.a.capacity;
+	if (newlen > obj->u.a.flat_length) {
+		assert(newlen == obj->u.a.flat_length + 1);
+		if (newlen > obj->u.a.flat_capacity) {
+			int newcap = obj->u.a.flat_capacity;
 			if (newcap == 0)
 				newcap = 8;
 			while (newcap < newlen)
 				newcap <<= 1;
 			obj->u.a.array = js_realloc(J, obj->u.a.array, newcap * sizeof(js_Value));
-			obj->u.a.capacity = newcap;
+			obj->u.a.flat_capacity = newcap;
 		}
-		obj->u.a.length = newlen;
+		obj->u.a.flat_length = newlen;
 	}
+	if (newlen > obj->u.a.length)
+		obj->u.a.length = newlen;
 	obj->u.a.array[k] = *value;
 }
 
@@ -678,26 +685,28 @@
 			if (newlen > JS_ARRAYLIMIT)
 				js_rangeerror(J, "array too large");
 			if (obj->u.a.simple) {
-				if (newlen <= obj->u.a.length) {
-					obj->u.a.length = newlen;
-					return;
-				}
-				jsR_unflattenarray(J, obj);
+				obj->u.a.length = newlen;
+				if (newlen <= obj->u.a.flat_length)
+					obj->u.a.flat_length = newlen;
+			} else  {
+				jsV_resizearray(J, obj, newlen);
 			}
-			jsV_resizearray(J, obj, newlen);
 			return;
 		}
 
 		if (js_isarrayindex(J, name, &k)) {
 			if (obj->u.a.simple) {
-				if (k >= 0 && k <= obj->u.a.length) {
+				if (k >= 0 && k <= obj->u.a.flat_length) {
 					jsR_setarrayindex(J, obj, k, value);
-					return;
+				} else {
+					jsR_unflattenarray(J, obj);
+					if (obj->u.a.length < k + 1)
+						obj->u.a.length = k + 1;
 				}
-				jsR_unflattenarray(J, obj);
+			} else {
+				if (obj->u.a.length < k + 1)
+					obj->u.a.length = k + 1;
 			}
-			if (k + 1 > obj->u.a.length)
-				obj->u.a.length = k + 1;
 		}
 	}
 
@@ -771,7 +780,7 @@
 static void jsR_setindex(js_State *J, js_Object *obj, int k, int transient)
 {
 	char buf[32];
-	if (obj->type == JS_CARRAY && obj->u.a.simple && k >= 0 && k <= obj->u.a.length) {
+	if (obj->type == JS_CARRAY && obj->u.a.simple && k >= 0 && k <= obj->u.a.flat_length) {
 		jsR_setarrayindex(J, obj, k, stackidx(J, -1));
 	} else {
 		jsR_setproperty(J, obj, js_itoa(buf, k), transient);
@@ -890,6 +899,16 @@
 	return 0;
 }
 
+static void jsR_delindex(js_State *J, js_Object *obj, int k)
+{
+	char buf[32];
+	/* Allow deleting last element of a simple array without unflattening */
+	if (obj->type == JS_CARRAY && obj->u.a.simple && k == obj->u.a.flat_length - 1)
+		obj->u.a.flat_length = k;
+	else
+		jsR_delproperty(J, obj, js_itoa(buf, k));
+}
+
 /* Registry, global and object property accessors */
 
 const char *js_ref(js_State *J)
@@ -1010,8 +1029,7 @@
 
 void js_delindex(js_State *J, int idx, int i)
 {
-	char buf[32];
-	js_delproperty(J, idx, js_itoa(buf, i));
+	jsR_delindex(J, js_toobject(J, idx), i);
 }
 
 /* Iterator */
--- a/jsvalue.h
+++ b/jsvalue.h
@@ -93,9 +93,10 @@
 			char shrstr[16];
 		} s;
 		struct {
-			int length;
+			int length; /* actual length */
 			int simple; /* true if array has only non-sparse array properties */
-			int capacity;
+			int flat_length; /* used length of simple array part */
+			int flat_capacity; /* allocated length of simple array part */
 			js_Value *array;
 		} a;
 		struct {