shithub: libmujs

Download patch

ref: c067e1299c83e7df24a89cbea36679aefad43bb0
parent: 0e611cdc0c81a90dabfcb2ab96992acca95b886d
author: Tor Andersson <tor.andersson@artifex.com>
date: Tue Nov 1 09:34:29 EDT 2022

Avoid using the string interning table.

Make a copy of the property name in the same allocation as the property slot.
Make a copy of the internal string value of String objects.

--- a/jsgc.c
+++ b/jsgc.c
@@ -42,6 +42,10 @@
 		js_free(J, obj->u.r.source);
 		js_regfreex(J->alloc, J->actx, obj->u.r.prog);
 	}
+	if (obj->type == JS_CSTRING) {
+		if (obj->u.s.string != obj->u.s.shrstr)
+			js_free(J, obj->u.s.string);
+	}
 	if (obj->type == JS_CARRAY && obj->u.a.simple)
 		js_free(J, obj->u.a.array);
 	if (obj->type == JS_CITERATOR)
--- a/jsobject.c
+++ b/jsobject.c
@@ -160,7 +160,7 @@
 {
 	if (ref->left->level)
 		i = O_getOwnPropertyNames_walk(J, ref->left, i);
-	js_pushliteral(J, ref->name);
+	js_pushstring(J, ref->name);
 	js_setindex(J, -2, i++);
 	if (ref->right->level)
 		i = O_getOwnPropertyNames_walk(J, ref->right, i);
@@ -352,7 +352,7 @@
 	if (ref->left->level)
 		i = O_keys_walk(J, ref->left, i);
 	if (!(ref->atts & JS_DONTENUM)) {
-		js_pushliteral(J, ref->name);
+		js_pushstring(J, ref->name);
 		js_setindex(J, -2, i++);
 	}
 	if (ref->right->level)
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -21,17 +21,16 @@
 */
 
 static js_Property sentinel = {
-	"",
 	&sentinel, &sentinel,
 	0, 0,
 	{ {0}, {0}, JS_TUNDEFINED },
-	NULL, NULL
+	NULL, NULL, ""
 };
 
 static js_Property *newproperty(js_State *J, js_Object *obj, const char *name)
 {
-	js_Property *node = js_malloc(J, sizeof *node);
-	node->name = js_intern(J, name);
+	int n = strlen(name) + 1;
+	js_Property *node = js_malloc(J, offsetof(js_Property, name) + n);
 	node->left = node->right = &sentinel;
 	node->level = 1;
 	node->atts = 0;
@@ -39,6 +38,7 @@
 	node->value.u.number = 0;
 	node->getter = NULL;
 	node->setter = NULL;
+	memcpy(node->name, name, n);
 	++obj->count;
 	++J->gccounter;
 	return node;
@@ -104,7 +104,7 @@
 	--obj->count;
 }
 
-static js_Property *delete(js_State *J, js_Object *obj, js_Property *node, const char *name)
+static js_Property *unlink(js_State *J, js_Object *obj, js_Property *node, const char *name, js_Property **garbage)
 {
 	js_Property *temp, *succ;
 
@@ -111,26 +111,24 @@
 	if (node != &sentinel) {
 		int c = strcmp(name, node->name);
 		if (c < 0) {
-			node->left = delete(J, obj, node->left, name);
+			node->left = unlink(J, obj, node->left, name, garbage);
 		} else if (c > 0) {
-			node->right = delete(J, obj, node->right, name);
+			node->right = unlink(J, obj, node->right, name, garbage);
 		} else {
 			if (node->left == &sentinel) {
-				temp = node;
+				*garbage = node;
 				node = node->right;
-				freeproperty(J, obj, temp);
 			} else if (node->right == &sentinel) {
-				temp = node;
+				*garbage = node;
 				node = node->left;
-				freeproperty(J, obj, temp);
 			} else {
+				*garbage = node;
 				succ = node->right;
 				while (succ->left != &sentinel)
 					succ = succ->left;
-				node->name = succ->name;
-				node->atts = succ->atts;
-				node->value = succ->value;
-				node->right = delete(J, obj, node->right, succ->name);
+				succ->right = unlink(J, obj, node->right, succ->name, &temp);
+				succ->left = node->left;
+				node = succ;
 			}
 		}
 
@@ -149,6 +147,15 @@
 	return node;
 }
 
+static js_Property *delete(js_State *J, js_Object *obj, js_Property *tree, const char *name)
+{
+	js_Property *garbage = NULL;
+	tree = unlink(J, obj, tree, name, &garbage);
+	if (garbage != NULL)
+		freeproperty(J, obj, garbage);
+	return tree;
+}
+
 js_Object *jsV_newobject(js_State *J, enum js_Class type, js_Object *prototype)
 {
 	js_Object *obj = js_malloc(J, sizeof *obj);
@@ -229,9 +236,10 @@
 /* Flatten hierarchy of enumerable properties into an iterator object */
 
 static js_Iterator *itnewnode(js_State *J, const char *name, js_Iterator *next) {
-	js_Iterator *node = js_malloc(J, sizeof(js_Iterator));
-	node->name = name;
+	int n = strlen(name) + 1;
+	js_Iterator *node = js_malloc(J, offsetof(js_Iterator, name) + n);
 	node->next = next;
+	memcpy(node->name, name, n);
 	return node;
 }
 
@@ -272,6 +280,7 @@
 	} else {
 		io->u.iter.head = itflatten(J, obj);
 	}
+	io->u.iter.current = io->u.iter.head;
 
 	if (obj->type == JS_CSTRING)
 		io->u.iter.n = obj->u.s.length;
@@ -284,7 +293,6 @@
 
 const char *jsV_nextiterator(js_State *J, js_Object *io)
 {
-	int k;
 	if (io->type != JS_CITERATOR)
 		js_typeerror(J, "not an iterator");
 	if (io->u.iter.i < io->u.iter.n) {
@@ -292,19 +300,11 @@
 		io->u.iter.i++;
 		return J->scratch;
 	}
-	while (io->u.iter.head) {
-		js_Iterator *next = io->u.iter.head->next;
-		const char *name = io->u.iter.head->name;
-		js_free(J, io->u.iter.head);
-		io->u.iter.head = next;
+	while (io->u.iter.current) {
+		const char *name = io->u.iter.current->name;
+		io->u.iter.current = io->u.iter.current->next;
 		if (jsV_getproperty(J, io->u.iter.target, name))
 			return name;
-		if (io->u.iter.target->type == JS_CSTRING)
-			if (js_isarrayindex(J, name, &k) && k < io->u.iter.target->u.s.length)
-				return name;
-		if (io->u.iter.target->type == JS_CARRAY && io->u.iter.target->u.a.simple)
-			if (js_isarrayindex(J, name, &k) && k < io->u.iter.target->u.a.length)
-				return name;
 	}
 	return NULL;
 }
--- a/jsrun.c
+++ b/jsrun.c
@@ -1736,7 +1736,7 @@
 				obj = js_toobject(J, -1);
 				str = jsV_nextiterator(J, obj);
 				if (str) {
-					js_pushliteral(J, str);
+					js_pushstring(J, str);
 					js_pushboolean(J, 1);
 				} else {
 					js_pop(J, 1);
--- a/jsstring.c
+++ b/jsstring.c
@@ -77,7 +77,7 @@
 {
 	js_Object *self = js_toobject(J, 0);
 	if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
-	js_pushliteral(J, self->u.s.string);
+	js_pushstring(J, self->u.s.string);
 }
 
 static void Sp_valueOf(js_State *J)
@@ -84,7 +84,7 @@
 {
 	js_Object *self = js_toobject(J, 0);
 	if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
-	js_pushliteral(J, self->u.s.string);
+	js_pushstring(J, self->u.s.string);
 }
 
 static void Sp_charAt(js_State *J)
@@ -688,7 +688,8 @@
 
 void jsB_initstring(js_State *J)
 {
-	J->String_prototype->u.s.string = "";
+	J->String_prototype->u.s.shrstr[0] = 0;
+	J->String_prototype->u.s.string = J->String_prototype->u.s.shrstr;
 	J->String_prototype->u.s.length = 0;
 
 	js_pushobject(J, J->String_prototype);
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -377,7 +377,13 @@
 static js_Object *jsV_newstring(js_State *J, const char *v)
 {
 	js_Object *obj = jsV_newobject(J, JS_CSTRING, J->String_prototype);
-	obj->u.s.string = js_intern(J, v); /* TODO: js_String */
+	size_t n = strlen(v);
+	if (n < sizeof(obj->u.s.shrstr) - 1) {
+		obj->u.s.string = obj->u.s.shrstr;
+		memcpy(obj->u.s.shrstr, v, n + 1);
+	} else {
+		obj->u.s.string = js_strdup(J, v);
+	}
 	obj->u.s.length = utflen(v);
 	return obj;
 }
--- a/jsvalue.h
+++ b/jsvalue.h
@@ -88,8 +88,9 @@
 		int boolean;
 		double number;
 		struct {
-			const char *string;
 			int length;
+			char *string;
+			char shrstr[16];
 		} s;
 		struct {
 			int length;
@@ -113,7 +114,7 @@
 		struct {
 			js_Object *target;
 			int i, n; /* for array part */
-			js_Iterator *head; /* for object part */
+			js_Iterator *head, *current; /* for object part */
 		} iter;
 		struct {
 			const char *tag;
@@ -131,7 +132,6 @@
 
 struct js_Property
 {
-	const char *name;
 	js_Property *left, *right;
 	int level;
 	int atts;
@@ -138,12 +138,13 @@
 	js_Value value;
 	js_Object *getter;
 	js_Object *setter;
+	char name[1];
 };
 
 struct js_Iterator
 {
-	const char *name;
 	js_Iterator *next;
+	char name[1];
 };
 
 /* jsrun.c */