shithub: libmujs

Download patch

ref: 33ffe6efebf477ee1f73c27670af460ffd6cc08d
parent: 06a6f9fb110fe02eb5c306a9c6c143a6cd8bd3bb
author: Tor Andersson <tor.andersson@artifex.com>
date: Fri Mar 26 08:58:34 EDT 2021

Inline doubles and interned string pointers in the byte code.

Avoid linearly searched per function string and number tables.

--- a/jscompile.c
+++ b/jscompile.c
@@ -110,34 +110,6 @@
 	return F->funlen++;
 }
 
-static int addnumber(JF, double value)
-{
-	int i;
-	for (i = 0; i < F->numlen; ++i)
-		if (F->numtab[i] == value)
-			return i;
-	if (F->numlen >= F->numcap) {
-		F->numcap = F->numcap ? F->numcap * 2 : 16;
-		F->numtab = js_realloc(J, F->numtab, F->numcap * sizeof *F->numtab);
-	}
-	F->numtab[F->numlen] = value;
-	return F->numlen++;
-}
-
-static int addstring(JF, const char *value)
-{
-	int i;
-	for (i = 0; i < F->strlen; ++i)
-		if (!strcmp(F->strtab[i], value))
-			return i;
-	if (F->strlen >= F->strcap) {
-		F->strcap = F->strcap ? F->strcap * 2 : 16;
-		F->strtab = js_realloc(J, F->strtab, F->strcap * sizeof *F->strtab);
-	}
-	F->strtab[F->strlen] = value;
-	return F->strlen++;
-}
-
 static int addlocal(JF, js_Ast *ident, int reuse)
 {
 	const char *name = ident->string;
@@ -196,15 +168,27 @@
 		emit(J, F, OP_INTEGER);
 		emitarg(J, F, num + 32768);
 	} else {
+#define N (sizeof(num) / sizeof(js_Instruction))
+		js_Instruction x[N];
+		size_t i;
 		emit(J, F, OP_NUMBER);
-		emitarg(J, F, addnumber(J, F, num));
+		memcpy(x, &num, sizeof(num));
+		for (i = 0; i < N; ++i)
+			emitarg(J, F, x[i]);
+#undef N
 	}
 }
 
 static void emitstring(JF, int opcode, const char *str)
 {
+#define N (sizeof(str) / sizeof(js_Instruction))
+	js_Instruction x[N];
+	size_t i;
 	emit(J, F, opcode);
-	emitarg(J, F, addstring(J, F, str));
+	memcpy(x, &str, sizeof(str));
+	for (i = 0; i < N; ++i)
+		emitarg(J, F, x[i]);
+#undef N
 }
 
 static void emitlocal(JF, int oploc, int opvar, js_Ast *ident)
@@ -623,8 +607,7 @@
 
 	case EXP_REGEXP:
 		emitline(J, F, exp);
-		emit(J, F, OP_NEWREGEXP);
-		emitarg(J, F, addstring(J, F, exp->string));
+		emitstring(J, F, OP_NEWREGEXP, exp->string);
 		emitarg(J, F, exp->number);
 		break;
 
--- a/jscompile.h
+++ b/jscompile.h
@@ -123,12 +123,6 @@
 	js_Function **funtab;
 	int funcap, funlen;
 
-	double *numtab;
-	int numcap, numlen;
-
-	const char **strtab;
-	int strcap, strlen;
-
 	const char **vartab;
 	int varcap, varlen;
 
--- a/jsdump.c
+++ b/jsdump.c
@@ -781,6 +781,8 @@
 {
 	js_Instruction *p = F->code;
 	js_Instruction *end = F->code + F->codelen;
+	char *s;
+	double n;
 	int i;
 
 	minify = 0;
@@ -807,16 +809,21 @@
 			printf(" %ld", (long)((*p++) - 32768));
 			break;
 		case OP_NUMBER:
-			printf(" %.9g", F->numtab[*p++]);
+			memcpy(&n, p, sizeof(n));
+			p += sizeof(n) / sizeof(*p);
+			printf(" %.9g", n);
 			break;
 		case OP_STRING:
+			memcpy(&s, p, sizeof(s));
+			p += sizeof(s) / sizeof(*p);
 			pc(' ');
-			pstr(F->strtab[*p++]);
+			pstr(s);
 			break;
 		case OP_NEWREGEXP:
 			pc(' ');
-			pregexp(F->strtab[p[0]], p[1]);
-			p += 2;
+			memcpy(&s, p, sizeof(s));
+			p += sizeof(s) / sizeof(*p);
+			pregexp(s, *p++);
 			break;
 
 		case OP_GETVAR:
@@ -827,8 +834,10 @@
 		case OP_SETPROP_S:
 		case OP_DELPROP_S:
 		case OP_CATCH:
+			memcpy(&s, p, sizeof(s));
+			p += sizeof(s) / sizeof(*p);
 			pc(' ');
-			ps(F->strtab[*p++]);
+			ps(s);
 			break;
 
 		case OP_GETLOCAL:
--- a/jsgc.c
+++ b/jsgc.c
@@ -13,8 +13,6 @@
 static void jsG_freefunction(js_State *J, js_Function *fun)
 {
 	js_free(J, fun->funtab);
-	js_free(J, fun->numtab);
-	js_free(J, fun->strtab);
 	js_free(J, fun->vartab);
 	js_free(J, fun->code);
 	js_free(J, fun);
--- a/jsrun.c
+++ b/jsrun.c
@@ -1314,8 +1314,6 @@
 static void jsR_run(js_State *J, js_Function *F)
 {
 	js_Function **FT = F->funtab;
-	double *NT = F->numtab;
-	const char **ST = F->strtab;
 	const char **VT = F->vartab-1;
 	int lightweight = F->lightweight;
 	js_Instruction *pcstart = F->code;
@@ -1335,6 +1333,10 @@
 	savestrict = J->strict;
 	J->strict = F->strict;
 
+#define READSTRING() \
+	memcpy(&str, pc, sizeof(str)); \
+	pc += sizeof(str) / sizeof(*pc)
+
 	while (1) {
 		if (J->gccounter > J->gcthresh)
 			js_gc(J, 0);
@@ -1351,14 +1353,28 @@
 		case OP_ROT3: js_rot3(J); break;
 		case OP_ROT4: js_rot4(J); break;
 
-		case OP_INTEGER: js_pushnumber(J, *pc++ - 32768); break;
-		case OP_NUMBER: js_pushnumber(J, NT[*pc++]); break;
-		case OP_STRING: js_pushliteral(J, ST[*pc++]); break;
+		case OP_INTEGER:
+			js_pushnumber(J, *pc++ - 32768);
+			break;
 
+		case OP_NUMBER:
+			memcpy(&x, pc, sizeof(x));
+			pc += sizeof(x) / sizeof(*pc);
+			js_pushnumber(J, x);
+			break;
+
+		case OP_STRING:
+			READSTRING();
+			js_pushliteral(J, str);
+			break;
+
 		case OP_CLOSURE: js_newfunction(J, FT[*pc++], J->E); break;
 		case OP_NEWOBJECT: js_newobject(J); break;
 		case OP_NEWARRAY: js_newarray(J); break;
-		case OP_NEWREGEXP: js_newregexp(J, ST[pc[0]], pc[1]); pc += 2; break;
+		case OP_NEWREGEXP:
+			READSTRING();
+			js_newregexp(J, str, *pc++);
+			break;
 
 		case OP_UNDEF: js_pushundefined(J); break;
 		case OP_NULL: js_pushnull(J); break;
@@ -1410,22 +1426,25 @@
 			break;
 
 		case OP_GETVAR:
-			str = ST[*pc++];
+			READSTRING();
 			if (!js_hasvar(J, str))
 				js_referenceerror(J, "'%s' is not defined", str);
 			break;
 
 		case OP_HASVAR:
-			if (!js_hasvar(J, ST[*pc++]))
+			READSTRING();
+			if (!js_hasvar(J, str))
 				js_pushundefined(J);
 			break;
 
 		case OP_SETVAR:
-			js_setvar(J, ST[*pc++]);
+			READSTRING();
+			js_setvar(J, str);
 			break;
 
 		case OP_DELVAR:
-			b = js_delvar(J, ST[*pc++]);
+			READSTRING();
+			b = js_delvar(J, str);
 			js_pushboolean(J, b);
 			break;
 
@@ -1471,7 +1490,7 @@
 			break;
 
 		case OP_GETPROP_S:
-			str = ST[*pc++];
+			READSTRING();
 			obj = js_toobject(J, -1);
 			jsR_getproperty(J, obj, str);
 			js_rot2pop1(J);
@@ -1486,7 +1505,7 @@
 			break;
 
 		case OP_SETPROP_S:
-			str = ST[*pc++];
+			READSTRING();
 			obj = js_toobject(J, -2);
 			transient = !js_isobject(J, -2);
 			jsR_setproperty(J, obj, str, transient);
@@ -1502,7 +1521,7 @@
 			break;
 
 		case OP_DELPROP_S:
-			str = ST[*pc++];
+			READSTRING();
 			obj = js_toobject(J, -1);
 			b = jsR_delproperty(J, obj, str);
 			js_pop(J, 1);
@@ -1738,7 +1757,7 @@
 			break;
 
 		case OP_CATCH:
-			str = ST[*pc++];
+			READSTRING();
 			obj = jsV_newobject(J, JS_COBJECT, NULL);
 			js_pushobject(J, obj);
 			js_rot2(J);