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);