aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2016-05-22 23:25:28 +0200
committerMike Pall <mike>2016-05-22 23:25:28 +0200
commita657fa01869e63508afce88cc8088c3d2e2fb47c (patch)
tree1a98114d87e4deaf3f2e72a2f95da7559e49d15c
parent513587656a36362e08fb99a28a280a9d412ef1bc (diff)
downloadluajit-a657fa01869e63508afce88cc8088c3d2e2fb47c.tar.gz
luajit-a657fa01869e63508afce88cc8088c3d2e2fb47c.tar.bz2
luajit-a657fa01869e63508afce88cc8088c3d2e2fb47c.zip
Make the IR immovable after assembly.
This allows embedding pointers to IR constants in the machine code. Contributed by Peter Cawley.
-rw-r--r--src/lj_asm.c95
-rw-r--r--src/lj_jit.h1
-rw-r--r--src/lj_trace.c33
-rw-r--r--src/lj_trace.h1
4 files changed, 97 insertions, 33 deletions
diff --git a/src/lj_asm.c b/src/lj_asm.c
index 5e38d254..5235dd00 100644
--- a/src/lj_asm.c
+++ b/src/lj_asm.c
@@ -625,9 +625,8 @@ static void ra_addrename(ASMState *as, Reg down, IRRef ref, SnapNo snapno)
625 IRRef ren; 625 IRRef ren;
626 lj_ir_set(as->J, IRT(IR_RENAME, IRT_NIL), ref, snapno); 626 lj_ir_set(as->J, IRT(IR_RENAME, IRT_NIL), ref, snapno);
627 ren = tref_ref(lj_ir_emit(as->J)); 627 ren = tref_ref(lj_ir_emit(as->J));
628 as->ir = as->T->ir; /* The IR may have been reallocated. */ 628 as->J->cur.ir[ren].r = (uint8_t)down;
629 IR(ren)->r = (uint8_t)down; 629 as->J->cur.ir[ren].s = SPS_NONE;
630 IR(ren)->s = SPS_NONE;
631} 630}
632 631
633/* Rename register allocation and emit move. */ 632/* Rename register allocation and emit move. */
@@ -948,7 +947,7 @@ static void asm_snap_prep(ASMState *as)
948 } else { 947 } else {
949 /* Process any renames above the highwater mark. */ 948 /* Process any renames above the highwater mark. */
950 for (; as->snaprename < as->T->nins; as->snaprename++) { 949 for (; as->snaprename < as->T->nins; as->snaprename++) {
951 IRIns *ir = IR(as->snaprename); 950 IRIns *ir = &as->T->ir[as->snaprename];
952 if (asm_snap_checkrename(as, ir->op1)) 951 if (asm_snap_checkrename(as, ir->op1))
953 ir->op2 = REF_BIAS-1; /* Kill rename. */ 952 ir->op2 = REF_BIAS-1; /* Kill rename. */
954 } 953 }
@@ -1967,8 +1966,9 @@ static void asm_setup_regsp(ASMState *as)
1967 1966
1968 ir = IR(nins-1); 1967 ir = IR(nins-1);
1969 if (ir->o == IR_RENAME) { 1968 if (ir->o == IR_RENAME) {
1969 /* Remove any renames left over from ASM restart due to LJ_TRERR_MCODELM. */
1970 do { ir--; nins--; } while (ir->o == IR_RENAME); 1970 do { ir--; nins--; } while (ir->o == IR_RENAME);
1971 T->nins = nins; /* Remove any renames left over from ASM restart. */ 1971 T->nins = nins;
1972 } 1972 }
1973 as->snaprename = nins; 1973 as->snaprename = nins;
1974 as->snapref = nins; 1974 as->snapref = nins;
@@ -2202,13 +2202,14 @@ void lj_asm_trace(jit_State *J, GCtrace *T)
2202 MCode *origtop; 2202 MCode *origtop;
2203 2203
2204 /* Ensure an initialized instruction beyond the last one for HIOP checks. */ 2204 /* Ensure an initialized instruction beyond the last one for HIOP checks. */
2205 J->cur.nins = lj_ir_nextins(J); 2205 /* This also allows one RENAME to be added without reallocating curfinal. */
2206 J->cur.ir[J->cur.nins].o = IR_NOP; 2206 as->orignins = lj_ir_nextins(J);
2207 J->cur.ir[as->orignins].o = IR_NOP;
2207 2208
2208 /* Setup initial state. Copy some fields to reduce indirections. */ 2209 /* Setup initial state. Copy some fields to reduce indirections. */
2209 as->J = J; 2210 as->J = J;
2210 as->T = T; 2211 as->T = T;
2211 as->ir = T->ir; 2212 J->curfinal = lj_trace_alloc(J->L, T); /* This copies the IR, too. */
2212 as->flags = J->flags; 2213 as->flags = J->flags;
2213 as->loopref = J->loopref; 2214 as->loopref = J->loopref;
2214 as->realign = NULL; 2215 as->realign = NULL;
@@ -2221,12 +2222,41 @@ void lj_asm_trace(jit_State *J, GCtrace *T)
2221 as->mclim = as->mcbot + MCLIM_REDZONE; 2222 as->mclim = as->mcbot + MCLIM_REDZONE;
2222 asm_setup_target(as); 2223 asm_setup_target(as);
2223 2224
2224 do { 2225 /*
2226 ** This is a loop, because the MCode may have to be (re-)assembled
2227 ** multiple times:
2228 **
2229 ** 1. as->realign is set (and the assembly aborted), if the arch-specific
2230 ** backend wants the MCode to be aligned differently.
2231 **
2232 ** This is currently only the case on x86/x64, where small loops get
2233 ** an aligned loop body plus a short branch. Not much effort is wasted,
2234 ** because the abort happens very quickly and only once.
2235 **
2236 ** 2. The IR is immovable, since the MCode embeds pointers to various
2237 ** constants inside the IR. But RENAMEs may need to be added to the IR
2238 ** during assembly, which might grow and reallocate the IR. We check
2239 ** at the end if the IR (in J->cur.ir) has actually grown, resize the
2240 ** copy (in J->curfinal.ir) and try again.
2241 **
2242 ** 95% of all traces have zero RENAMEs, 3% have one RENAME, 1.5% have
2243 ** 2 RENAMEs and only 0.5% have more than that. That's why we opt to
2244 ** always have one spare slot in the IR (see above), which means we
2245 ** have to redo the assembly for only ~2% of all traces.
2246 **
2247 ** Very, very rarely, this needs to be done repeatedly, since the
2248 ** location of constants inside the IR (actually, reachability from
2249 ** a global pointer) may affect register allocation and thus the
2250 ** number of RENAMEs.
2251 */
2252 for (;;) {
2225 as->mcp = as->mctop; 2253 as->mcp = as->mctop;
2226#ifdef LUA_USE_ASSERT 2254#ifdef LUA_USE_ASSERT
2227 as->mcp_prev = as->mcp; 2255 as->mcp_prev = as->mcp;
2228#endif 2256#endif
2229 as->curins = T->nins; 2257 as->ir = J->curfinal->ir; /* Use the copied IR. */
2258 as->curins = J->cur.nins = as->orignins;
2259
2230 RA_DBG_START(); 2260 RA_DBG_START();
2231 RA_DBGX((as, "===== STOP =====")); 2261 RA_DBGX((as, "===== STOP ====="));
2232 2262
@@ -2254,22 +2284,39 @@ void lj_asm_trace(jit_State *J, GCtrace *T)
2254 checkmclim(as); 2284 checkmclim(as);
2255 asm_ir(as, ir); 2285 asm_ir(as, ir);
2256 } 2286 }
2257 } while (as->realign); /* Retry in case the MCode needs to be realigned. */
2258 2287
2259 /* Emit head of trace. */ 2288 if (as->realign && J->curfinal->nins >= T->nins)
2260 RA_DBG_REF(); 2289 continue; /* Retry in case only the MCode needs to be realigned. */
2261 checkmclim(as); 2290
2262 if (as->gcsteps > 0) { 2291 /* Emit head of trace. */
2263 as->curins = as->T->snap[0].ref; 2292 RA_DBG_REF();
2264 asm_snap_prep(as); /* The GC check is a guard. */ 2293 checkmclim(as);
2265 asm_gc_check(as); 2294 if (as->gcsteps > 0) {
2295 as->curins = as->T->snap[0].ref;
2296 asm_snap_prep(as); /* The GC check is a guard. */
2297 asm_gc_check(as);
2298 }
2299 ra_evictk(as);
2300 if (as->parent)
2301 asm_head_side(as);
2302 else
2303 asm_head_root(as);
2304 asm_phi_fixup(as);
2305
2306 if (J->curfinal->nins >= T->nins) { /* IR didn't grow? */
2307 lua_assert(J->curfinal->nk == T->nk);
2308 memcpy(J->curfinal->ir + as->orignins, T->ir + as->orignins,
2309 (T->nins - as->orignins) * sizeof(IRIns)); /* Copy RENAMEs. */
2310 T->nins = J->curfinal->nins;
2311 break; /* Done. */
2312 }
2313
2314 /* Otherwise try again with a bigger IR. */
2315 lj_trace_free(J2G(J), J->curfinal);
2316 J->curfinal = NULL; /* In case lj_trace_alloc() OOMs. */
2317 J->curfinal = lj_trace_alloc(J->L, T);
2318 as->realign = NULL;
2266 } 2319 }
2267 ra_evictk(as);
2268 if (as->parent)
2269 asm_head_side(as);
2270 else
2271 asm_head_root(as);
2272 asm_phi_fixup(as);
2273 2320
2274 RA_DBGX((as, "===== START ====")); 2321 RA_DBGX((as, "===== START ===="));
2275 RA_DBG_FLUSH(); 2322 RA_DBG_FLUSH();
diff --git a/src/lj_jit.h b/src/lj_jit.h
index 6a47961b..ad9d62af 100644
--- a/src/lj_jit.h
+++ b/src/lj_jit.h
@@ -362,6 +362,7 @@ typedef struct FoldState {
362/* JIT compiler state. */ 362/* JIT compiler state. */
363typedef struct jit_State { 363typedef struct jit_State {
364 GCtrace cur; /* Current trace. */ 364 GCtrace cur; /* Current trace. */
365 GCtrace *curfinal; /* Final address of current trace (set during asm). */
365 366
366 lua_State *L; /* Current Lua state. */ 367 lua_State *L; /* Current Lua state. */
367 const BCIns *pc; /* Current PC. */ 368 const BCIns *pc; /* Current PC. */
diff --git a/src/lj_trace.c b/src/lj_trace.c
index 0d54c0af..19ddba41 100644
--- a/src/lj_trace.c
+++ b/src/lj_trace.c
@@ -117,15 +117,26 @@ static void perftools_addtrace(GCtrace *T)
117} 117}
118#endif 118#endif
119 119
120/* Allocate space for copy of trace. */ 120/* Allocate space for copy of T. */
121static GCtrace *trace_save_alloc(jit_State *J) 121GCtrace * LJ_FASTCALL lj_trace_alloc(lua_State *L, GCtrace *T)
122{ 122{
123 size_t sztr = ((sizeof(GCtrace)+7)&~7); 123 size_t sztr = ((sizeof(GCtrace)+7)&~7);
124 size_t szins = (J->cur.nins-J->cur.nk)*sizeof(IRIns); 124 size_t szins = (T->nins-T->nk)*sizeof(IRIns);
125 size_t sz = sztr + szins + 125 size_t sz = sztr + szins +
126 J->cur.nsnap*sizeof(SnapShot) + 126 T->nsnap*sizeof(SnapShot) +
127 J->cur.nsnapmap*sizeof(SnapEntry); 127 T->nsnapmap*sizeof(SnapEntry);
128 return lj_mem_newt(J->L, (MSize)sz, GCtrace); 128 GCtrace *T2 = lj_mem_newt(L, (MSize)sz, GCtrace);
129 char *p = (char *)T2 + sztr;
130 T2->gct = ~LJ_TTRACE;
131 T2->marked = 0;
132 T2->traceno = 0;
133 T2->ir = (IRIns *)p - T->nk;
134 T2->nins = T->nins;
135 T2->nk = T->nk;
136 T2->nsnap = T->nsnap;
137 T2->nsnapmap = T->nsnapmap;
138 memcpy(p, T->ir + T->nk, szins);
139 return T2;
129} 140}
130 141
131/* Save current trace by copying and compacting it. */ 142/* Save current trace by copying and compacting it. */
@@ -139,12 +150,12 @@ static void trace_save(jit_State *J, GCtrace *T)
139 setgcrefp(J2G(J)->gc.root, T); 150 setgcrefp(J2G(J)->gc.root, T);
140 newwhite(J2G(J), T); 151 newwhite(J2G(J), T);
141 T->gct = ~LJ_TTRACE; 152 T->gct = ~LJ_TTRACE;
142 T->ir = (IRIns *)p - J->cur.nk; 153 T->ir = (IRIns *)p - J->cur.nk; /* The IR has already been copied above. */
143 memcpy(p, J->cur.ir+J->cur.nk, szins);
144 p += szins; 154 p += szins;
145 TRACE_APPENDVEC(snap, nsnap, SnapShot) 155 TRACE_APPENDVEC(snap, nsnap, SnapShot)
146 TRACE_APPENDVEC(snapmap, nsnapmap, SnapEntry) 156 TRACE_APPENDVEC(snapmap, nsnapmap, SnapEntry)
147 J->cur.traceno = 0; 157 J->cur.traceno = 0;
158 J->curfinal = NULL;
148 setgcrefp(J->trace[T->traceno], T); 159 setgcrefp(J->trace[T->traceno], T);
149 lj_gc_barriertrace(J2G(J), T->traceno); 160 lj_gc_barriertrace(J2G(J), T->traceno);
150 lj_gdbjit_addtrace(J, T); 161 lj_gdbjit_addtrace(J, T);
@@ -449,7 +460,7 @@ static void trace_stop(jit_State *J)
449 BCOp op = bc_op(J->cur.startins); 460 BCOp op = bc_op(J->cur.startins);
450 GCproto *pt = &gcref(J->cur.startpt)->pt; 461 GCproto *pt = &gcref(J->cur.startpt)->pt;
451 TraceNo traceno = J->cur.traceno; 462 TraceNo traceno = J->cur.traceno;
452 GCtrace *T = trace_save_alloc(J); /* Do this first. May throw OOM. */ 463 GCtrace *T = J->curfinal;
453 lua_State *L; 464 lua_State *L;
454 465
455 switch (op) { 466 switch (op) {
@@ -537,6 +548,10 @@ static int trace_abort(jit_State *J)
537 548
538 J->postproc = LJ_POST_NONE; 549 J->postproc = LJ_POST_NONE;
539 lj_mcode_abort(J); 550 lj_mcode_abort(J);
551 if (J->curfinal) {
552 lj_trace_free(J2G(J), J->curfinal);
553 J->curfinal = NULL;
554 }
540 if (tvisnumber(L->top-1)) 555 if (tvisnumber(L->top-1))
541 e = (TraceError)numberVint(L->top-1); 556 e = (TraceError)numberVint(L->top-1);
542 if (e == LJ_TRERR_MCODELM) { 557 if (e == LJ_TRERR_MCODELM) {
diff --git a/src/lj_trace.h b/src/lj_trace.h
index 6faa1aa3..5658d8a5 100644
--- a/src/lj_trace.h
+++ b/src/lj_trace.h
@@ -23,6 +23,7 @@ LJ_FUNC_NORET void lj_trace_err(jit_State *J, TraceError e);
23LJ_FUNC_NORET void lj_trace_err_info(jit_State *J, TraceError e); 23LJ_FUNC_NORET void lj_trace_err_info(jit_State *J, TraceError e);
24 24
25/* Trace management. */ 25/* Trace management. */
26LJ_FUNC GCtrace * LJ_FASTCALL lj_trace_alloc(lua_State *L, GCtrace *T);
26LJ_FUNC void LJ_FASTCALL lj_trace_free(global_State *g, GCtrace *T); 27LJ_FUNC void LJ_FASTCALL lj_trace_free(global_State *g, GCtrace *T);
27LJ_FUNC void lj_trace_reenableproto(GCproto *pt); 28LJ_FUNC void lj_trace_reenableproto(GCproto *pt);
28LJ_FUNC void lj_trace_flushproto(global_State *g, GCproto *pt); 29LJ_FUNC void lj_trace_flushproto(global_State *g, GCproto *pt);