diff options
author | Mike Pall <mike> | 2012-07-20 18:54:52 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2012-07-20 18:54:52 +0200 |
commit | 3636a720a57adefb84c7ac70b68f640caf47f27f (patch) | |
tree | 26959ea44d123b9a2361b8cd7fe5962acbd88502 /src | |
parent | 834ff6d36d85f75d1c11c4d83dc6f56f726b7419 (diff) | |
download | luajit-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.c | 12 | ||||
-rw-r--r-- | src/lj_func.c | 3 | ||||
-rw-r--r-- | src/lj_obj.h | 6 | ||||
-rw-r--r-- | src/lj_parse.c | 39 | ||||
-rw-r--r-- | src/lj_record.c | 35 | ||||
-rw-r--r-- | src/lj_record.h | 1 |
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 { | |||
342 | typedef struct GCupval { | 346 | typedef 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 { | |||
105 | typedef uint16_t VarIndex; | 105 | typedef 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. */ |
109 | typedef struct UVMap { | 111 | typedef 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. */ |
1186 | static void fs_fixup_uv(FuncState *fs, GCproto *pt, uint16_t *uv) | 1194 | static 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. */ | ||
191 | TRef 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 | } | ||
1300 | noconstify: | ||
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 | ||
29 | LJ_FUNC int lj_record_objcmp(jit_State *J, TRef a, TRef b, | 29 | LJ_FUNC int lj_record_objcmp(jit_State *J, TRef a, TRef b, |
30 | cTValue *av, cTValue *bv); | 30 | cTValue *av, cTValue *bv); |
31 | LJ_FUNC TRef lj_record_constify(jit_State *J, cTValue *o); | ||
31 | 32 | ||
32 | LJ_FUNC void lj_record_call(jit_State *J, BCReg func, ptrdiff_t nargs); | 33 | LJ_FUNC void lj_record_call(jit_State *J, BCReg func, ptrdiff_t nargs); |
33 | LJ_FUNC void lj_record_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs); | 34 | LJ_FUNC void lj_record_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs); |