aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Pall <mike>2012-07-20 18:54:52 +0200
committerMike Pall <mike>2012-07-20 18:54:52 +0200
commit3636a720a57adefb84c7ac70b68f640caf47f27f (patch)
tree26959ea44d123b9a2361b8cd7fe5962acbd88502 /src
parent834ff6d36d85f75d1c11c4d83dc6f56f726b7419 (diff)
downloadluajit-3636a720a57adefb84c7ac70b68f640caf47f27f.tar.gz
luajit-3636a720a57adefb84c7ac70b68f640caf47f27f.tar.bz2
luajit-3636a720a57adefb84c7ac70b68f640caf47f27f.zip
Turn loads from immutable upvalues into constants.
Diffstat (limited to 'src')
-rw-r--r--src/lj_crecord.c12
-rw-r--r--src/lj_func.c3
-rw-r--r--src/lj_obj.h6
-rw-r--r--src/lj_parse.c39
-rw-r--r--src/lj_record.c35
-rw-r--r--src/lj_record.h1
6 files changed, 72 insertions, 24 deletions
diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index 49b2341a..2a475035 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -483,16 +483,8 @@ static void crec_index_meta(jit_State *J, CTState *cts, CType *ct,
483 } else if (rd->data == 0 && tvistab(tv) && tref_isstr(J->base[1])) { 483 } else if (rd->data == 0 && tvistab(tv) && tref_isstr(J->base[1])) {
484 /* Specialize to result of __index lookup. */ 484 /* Specialize to result of __index lookup. */
485 cTValue *o = lj_tab_get(J->L, tabV(tv), &rd->argv[1]); 485 cTValue *o = lj_tab_get(J->L, tabV(tv), &rd->argv[1]);
486 IRType t = itype2irt(o); 486 J->base[0] = lj_record_constify(J, o);
487 if (tvisgcv(o)) 487 if (!J->base[0])
488 J->base[0] = lj_ir_kgc(J, gcV(o), t);
489 else if (tvisint(o))
490 J->base[0] = lj_ir_kint(J, intV(o));
491 else if (tvisnum(o))
492 J->base[0] = lj_ir_knumint(J, numV(o));
493 else if (tvisbool(o))
494 J->base[0] = TREF_PRI(t);
495 else
496 lj_trace_err(J, LJ_TRERR_BADTYPE); 488 lj_trace_err(J, LJ_TRERR_BADTYPE);
497 /* Always specialize to the key. */ 489 /* Always specialize to the key. */
498 emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1]))); 490 emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1])));
diff --git a/src/lj_func.c b/src/lj_func.c
index 0c0b9014..0af53cc4 100644
--- a/src/lj_func.c
+++ b/src/lj_func.c
@@ -163,8 +163,9 @@ GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
163 for (i = 0; i < nuv; i++) { 163 for (i = 0; i < nuv; i++) {
164 uint32_t v = proto_uv(pt)[i]; 164 uint32_t v = proto_uv(pt)[i];
165 GCupval *uv; 165 GCupval *uv;
166 if ((v & 0x8000)) { 166 if ((v & PROTO_UV_LOCAL)) {
167 uv = func_finduv(L, base + (v & 0xff)); 167 uv = func_finduv(L, base + (v & 0xff));
168 uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1);
168 uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24); 169 uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24);
169 } else { 170 } else {
170 uv = &gcref(puv[v])->uv; 171 uv = &gcref(puv[v])->uv;
diff --git a/src/lj_obj.h b/src/lj_obj.h
index 137a04b2..7890e54b 100644
--- a/src/lj_obj.h
+++ b/src/lj_obj.h
@@ -321,6 +321,10 @@ typedef struct GCproto {
321/* Top bits used for counting created closures. */ 321/* Top bits used for counting created closures. */
322#define PROTO_CLCOUNT 0x20 /* Base of saturating 3 bit counter. */ 322#define PROTO_CLCOUNT 0x20 /* Base of saturating 3 bit counter. */
323#define PROTO_CLC_BITS 3 323#define PROTO_CLC_BITS 3
324#define PROTO_CLC_POLY (3*PROTO_CLCOUNT) /* Polymorphic threshold. */
325
326#define PROTO_UV_LOCAL 0x8000 /* Upvalue for local slot. */
327#define PROTO_UV_IMMUTABLE 0x4000 /* Immutable upvalue. */
324 328
325#define proto_kgc(pt, idx) \ 329#define proto_kgc(pt, idx) \
326 check_exp((uintptr_t)(intptr_t)(idx) >= (uintptr_t)-(intptr_t)(pt)->sizekgc, \ 330 check_exp((uintptr_t)(intptr_t)(idx) >= (uintptr_t)-(intptr_t)(pt)->sizekgc, \
@@ -342,7 +346,7 @@ typedef struct GCproto {
342typedef struct GCupval { 346typedef struct GCupval {
343 GCHeader; 347 GCHeader;
344 uint8_t closed; /* Set if closed (i.e. uv->v == &uv->u.value). */ 348 uint8_t closed; /* Set if closed (i.e. uv->v == &uv->u.value). */
345 uint8_t unused; 349 uint8_t immutable; /* Immutable value. */
346 union { 350 union {
347 TValue tv; /* If closed: the value itself. */ 351 TValue tv; /* If closed: the value itself. */
348 struct { /* If open: double linked list, anchored at thread. */ 352 struct { /* If open: double linked list, anchored at thread. */
diff --git a/src/lj_parse.c b/src/lj_parse.c
index 2cbfbe56..c5129ad5 100644
--- a/src/lj_parse.c
+++ b/src/lj_parse.c
@@ -39,8 +39,8 @@ typedef enum {
39 VKLAST = VKNUM, 39 VKLAST = VKNUM,
40 VKCDATA, /* nval = cdata value, not treated as a constant expression */ 40 VKCDATA, /* nval = cdata value, not treated as a constant expression */
41 /* Non-constant expressions follow: */ 41 /* Non-constant expressions follow: */
42 VLOCAL, /* info = local register */ 42 VLOCAL, /* info = local register, aux = vstack index */
43 VUPVAL, /* info = upvalue index */ 43 VUPVAL, /* info = upvalue index, aux = vstack index */
44 VGLOBAL, /* sval = string value */ 44 VGLOBAL, /* sval = string value */
45 VINDEXED, /* info = table register, aux = index reg/byte/string const */ 45 VINDEXED, /* info = table register, aux = index reg/byte/string const */
46 VJMP, /* info = instruction PC */ 46 VJMP, /* info = instruction PC */
@@ -105,6 +105,8 @@ typedef struct FuncScope {
105typedef uint16_t VarIndex; 105typedef uint16_t VarIndex;
106#define LJ_MAX_VSTACK 65536 106#define LJ_MAX_VSTACK 65536
107 107
108#define VSTACK_VAR_RW 0x80000000 /* In endpc: R/W variable. */
109
108/* Upvalue map. */ 110/* Upvalue map. */
109typedef struct UVMap { 111typedef struct UVMap {
110 VarIndex vidx; /* Varinfo index. */ 112 VarIndex vidx; /* Varinfo index. */
@@ -608,10 +610,12 @@ static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e)
608{ 610{
609 BCIns ins; 611 BCIns ins;
610 if (var->k == VLOCAL) { 612 if (var->k == VLOCAL) {
613 fs->ls->vstack[var->u.s.aux].endpc |= VSTACK_VAR_RW;
611 expr_free(fs, e); 614 expr_free(fs, e);
612 expr_toreg(fs, e, var->u.s.info); 615 expr_toreg(fs, e, var->u.s.info);
613 return; 616 return;
614 } else if (var->k == VUPVAL) { 617 } else if (var->k == VUPVAL) {
618 fs->ls->vstack[var->u.s.aux].endpc |= VSTACK_VAR_RW;
615 expr_toval(fs, e); 619 expr_toval(fs, e);
616 if (e->k <= VKTRUE) 620 if (e->k <= VKTRUE)
617 ins = BCINS_AD(BC_USETP, var->u.s.info, const_pri(e)); 621 ins = BCINS_AD(BC_USETP, var->u.s.info, const_pri(e));
@@ -1046,8 +1050,11 @@ static void var_add(LexState *ls, BCReg nvars)
1046{ 1050{
1047 FuncState *fs = ls->fs; 1051 FuncState *fs = ls->fs;
1048 fs->nactvar = (uint8_t)(fs->nactvar + nvars); 1052 fs->nactvar = (uint8_t)(fs->nactvar + nvars);
1049 for (; nvars; nvars--) 1053 for (; nvars; nvars--) {
1050 var_get(ls, fs, fs->nactvar - nvars).startpc = fs->pc; 1054 VarInfo *v = &var_get(ls, fs, fs->nactvar - nvars);
1055 v->startpc = fs->pc;
1056 v->endpc = 0;
1057 }
1051} 1058}
1052 1059
1053/* Remove local variables. */ 1060/* Remove local variables. */
@@ -1055,7 +1062,7 @@ static void var_remove(LexState *ls, BCReg tolevel)
1055{ 1062{
1056 FuncState *fs = ls->fs; 1063 FuncState *fs = ls->fs;
1057 while (fs->nactvar > tolevel) 1064 while (fs->nactvar > tolevel)
1058 var_get(ls, fs, --fs->nactvar).endpc = fs->pc; 1065 var_get(ls, fs, --fs->nactvar).endpc |= fs->pc;
1059} 1066}
1060 1067
1061/* Lookup local variable name. */ 1068/* Lookup local variable name. */
@@ -1080,7 +1087,8 @@ static MSize var_lookup_uv(FuncState *fs, MSize vidx, ExpDesc *e)
1080 checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues"); 1087 checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues");
1081 lua_assert(e->k == VLOCAL || e->k == VUPVAL); 1088 lua_assert(e->k == VLOCAL || e->k == VUPVAL);
1082 fs->uvloc[n].vidx = (uint16_t)vidx; 1089 fs->uvloc[n].vidx = (uint16_t)vidx;
1083 fs->uvloc[n].slot = (uint16_t)(e->u.s.info | (e->k == VLOCAL ? 0x8000 : 0)); 1090 fs->uvloc[n].slot = (uint16_t)(e->u.s.info |
1091 (e->k == VLOCAL ? PROTO_UV_LOCAL : 0));
1084 fs->nuv = n+1; 1092 fs->nuv = n+1;
1085 return n; 1093 return n;
1086} 1094}
@@ -1097,7 +1105,7 @@ static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first)
1097 expr_init(e, VLOCAL, reg); 1105 expr_init(e, VLOCAL, reg);
1098 if (!first) 1106 if (!first)
1099 scope_uvmark(fs, reg); /* Scope now has an upvalue. */ 1107 scope_uvmark(fs, reg); /* Scope now has an upvalue. */
1100 return (MSize)fs->varmap[reg]; 1108 return (MSize)(e->u.s.aux = (uint32_t)fs->varmap[reg]);
1101 } else { 1109 } else {
1102 MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */ 1110 MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */
1103 if ((int32_t)vidx >= 0) { /* Yes, make it an upvalue here. */ 1111 if ((int32_t)vidx >= 0) { /* Yes, make it an upvalue here. */
@@ -1185,11 +1193,20 @@ static void fs_fixup_k(FuncState *fs, GCproto *pt, void *kptr)
1185/* Fixup upvalues for prototype. */ 1193/* Fixup upvalues for prototype. */
1186static void fs_fixup_uv(FuncState *fs, GCproto *pt, uint16_t *uv) 1194static void fs_fixup_uv(FuncState *fs, GCproto *pt, uint16_t *uv)
1187{ 1195{
1196 VarInfo *vstack;
1197 UVMap *uvloc;
1188 MSize i, n = fs->nuv; 1198 MSize i, n = fs->nuv;
1189 setmref(pt->uv, uv); 1199 setmref(pt->uv, uv);
1190 pt->sizeuv = n; 1200 pt->sizeuv = n;
1191 for (i = 0; i < n; i++) 1201 vstack = fs->ls->vstack;
1192 uv[i] = fs->uvloc[i].slot; 1202 uvloc = fs->uvloc;
1203 for (i = 0; i < n; i++) {
1204 uint16_t slot = uvloc[i].slot;
1205 uint16_t vidx = uvloc[i].vidx;
1206 if ((slot & PROTO_UV_LOCAL) && !(vstack[vidx].endpc & VSTACK_VAR_RW))
1207 slot |= PROTO_UV_IMMUTABLE;
1208 uv[i] = slot;
1209 }
1193} 1210}
1194 1211
1195#ifndef LUAJIT_DISABLE_DEBUGINFO 1212#ifndef LUAJIT_DISABLE_DEBUGINFO
@@ -1287,7 +1304,8 @@ static size_t fs_prep_var(LexState *ls, FuncState *fs, size_t *ofsvar)
1287 /* Store local variable names and compressed ranges. */ 1304 /* Store local variable names and compressed ranges. */
1288 for (i = 0, n = ls->vtop - fs->vbase; i < n; i++) { 1305 for (i = 0, n = ls->vtop - fs->vbase; i < n; i++) {
1289 GCstr *s = strref(vstack[i].name); 1306 GCstr *s = strref(vstack[i].name);
1290 BCPos startpc = vstack[i].startpc, endpc = vstack[i].endpc; 1307 BCPos startpc = vstack[i].startpc;
1308 BCPos endpc = vstack[i].endpc & ~VSTACK_VAR_RW;
1291 if ((uintptr_t)s < VARNAME__MAX) { 1309 if ((uintptr_t)s < VARNAME__MAX) {
1292 fs_buf_need(ls, 1 + 2*5); 1310 fs_buf_need(ls, 1 + 2*5);
1293 ls->sb.buf[ls->sb.n++] = (uint8_t)(uintptr_t)s; 1311 ls->sb.buf[ls->sb.n++] = (uint8_t)(uintptr_t)s;
@@ -2180,6 +2198,7 @@ static void parse_local(LexState *ls)
2180 FuncState *fs = ls->fs; 2198 FuncState *fs = ls->fs;
2181 var_new(ls, 0, lex_str(ls)); 2199 var_new(ls, 0, lex_str(ls));
2182 expr_init(&v, VLOCAL, fs->freereg); 2200 expr_init(&v, VLOCAL, fs->freereg);
2201 v.u.s.aux = fs->varmap[fs->freereg];
2183 bcreg_reserve(fs, 1); 2202 bcreg_reserve(fs, 1);
2184 var_add(ls, 1); 2203 var_add(ls, 1);
2185 parse_body(ls, &b, 0, ls->linenumber); 2204 parse_body(ls, &b, 0, ls->linenumber);
diff --git a/src/lj_record.c b/src/lj_record.c
index be5c618f..a593af99 100644
--- a/src/lj_record.c
+++ b/src/lj_record.c
@@ -187,6 +187,21 @@ int lj_record_objcmp(jit_State *J, TRef a, TRef b, cTValue *av, cTValue *bv)
187 return diff; 187 return diff;
188} 188}
189 189
190/* Constify a value. Returns 0 for non-representable object types. */
191TRef lj_record_constify(jit_State *J, cTValue *o)
192{
193 if (tvisgcv(o))
194 return lj_ir_kgc(J, gcV(o), itype2irt(o));
195 else if (tvisint(o))
196 return lj_ir_kint(J, intV(o));
197 else if (tvisnum(o))
198 return lj_ir_knumint(J, numV(o));
199 else if (tvisbool(o))
200 return TREF_PRI(itype2irt(o));
201 else
202 return 0; /* Can't represent lightuserdata (pointless). */
203}
204
190/* -- Record loop ops ----------------------------------------------------- */ 205/* -- Record loop ops ----------------------------------------------------- */
191 206
192/* Loop event. */ 207/* Loop event. */
@@ -569,8 +584,8 @@ static TRef rec_call_specialize(jit_State *J, GCfunc *fn, TRef tr)
569 TRef kfunc; 584 TRef kfunc;
570 if (isluafunc(fn)) { 585 if (isluafunc(fn)) {
571 GCproto *pt = funcproto(fn); 586 GCproto *pt = funcproto(fn);
572 /* 3 or more closures created? Probably not a monomorphic function. */ 587 /* Too many closures created? Probably not a monomorphic function. */
573 if (pt->flags >= 3*PROTO_CLCOUNT) { /* Specialize to prototype instead. */ 588 if (pt->flags >= PROTO_CLC_POLY) { /* Specialize to prototype instead. */
574 TRef trpt = emitir(IRT(IR_FLOAD, IRT_P32), tr, IRFL_FUNC_PC); 589 TRef trpt = emitir(IRT(IR_FLOAD, IRT_P32), tr, IRFL_FUNC_PC);
575 emitir(IRTG(IR_EQ, IRT_P32), trpt, lj_ir_kptr(J, proto_bc(pt))); 590 emitir(IRTG(IR_EQ, IRT_P32), trpt, lj_ir_kptr(J, proto_bc(pt)));
576 (void)lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); /* Prevent GC of proto. */ 591 (void)lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); /* Prevent GC of proto. */
@@ -1267,6 +1282,22 @@ static TRef rec_upvalue(jit_State *J, uint32_t uv, TRef val)
1267 TRef fn = getcurrf(J); 1282 TRef fn = getcurrf(J);
1268 IRRef uref; 1283 IRRef uref;
1269 int needbarrier = 0; 1284 int needbarrier = 0;
1285 if (uvp->immutable) { /* Try to constify immutable upvalue. */
1286 TRef tr, kfunc;
1287 lua_assert(val == 0);
1288 if (!tref_isk(fn)) { /* Late specialization of current function. */
1289 if (J->pt->flags >= PROTO_CLC_POLY)
1290 goto noconstify;
1291 kfunc = lj_ir_kfunc(J, J->fn);
1292 emitir(IRTG(IR_EQ, IRT_FUNC), fn, kfunc);
1293 J->base[-1] = TREF_FRAME | kfunc;
1294 fn = kfunc;
1295 }
1296 tr = lj_record_constify(J, uvval(uvp));
1297 if (tr)
1298 return tr;
1299 }
1300noconstify:
1270 /* Note: this effectively limits LJ_MAX_UPVAL to 127. */ 1301 /* Note: this effectively limits LJ_MAX_UPVAL to 127. */
1271 uv = (uv << 8) | (hashrot(uvp->dhash, uvp->dhash + HASH_BIAS) & 0xff); 1302 uv = (uv << 8) | (hashrot(uvp->dhash, uvp->dhash + HASH_BIAS) & 0xff);
1272 if (!uvp->closed) { 1303 if (!uvp->closed) {
diff --git a/src/lj_record.h b/src/lj_record.h
index 40ffcb97..357392d8 100644
--- a/src/lj_record.h
+++ b/src/lj_record.h
@@ -28,6 +28,7 @@ typedef struct RecordIndex {
28 28
29LJ_FUNC int lj_record_objcmp(jit_State *J, TRef a, TRef b, 29LJ_FUNC int lj_record_objcmp(jit_State *J, TRef a, TRef b,
30 cTValue *av, cTValue *bv); 30 cTValue *av, cTValue *bv);
31LJ_FUNC TRef lj_record_constify(jit_State *J, cTValue *o);
31 32
32LJ_FUNC void lj_record_call(jit_State *J, BCReg func, ptrdiff_t nargs); 33LJ_FUNC void lj_record_call(jit_State *J, BCReg func, ptrdiff_t nargs);
33LJ_FUNC void lj_record_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs); 34LJ_FUNC void lj_record_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs);