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 */