diff options
author | Mike Pall <mike> | 2016-05-22 23:25:28 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2016-05-22 23:25:28 +0200 |
commit | a657fa01869e63508afce88cc8088c3d2e2fb47c (patch) | |
tree | 1a98114d87e4deaf3f2e72a2f95da7559e49d15c | |
parent | 513587656a36362e08fb99a28a280a9d412ef1bc (diff) | |
download | luajit-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.c | 95 | ||||
-rw-r--r-- | src/lj_jit.h | 1 | ||||
-rw-r--r-- | src/lj_trace.c | 33 | ||||
-rw-r--r-- | src/lj_trace.h | 1 |
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. */ |
363 | typedef struct jit_State { | 363 | typedef 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. */ |
121 | static GCtrace *trace_save_alloc(jit_State *J) | 121 | GCtrace * 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); | |||
23 | LJ_FUNC_NORET void lj_trace_err_info(jit_State *J, TraceError e); | 23 | LJ_FUNC_NORET void lj_trace_err_info(jit_State *J, TraceError e); |
24 | 24 | ||
25 | /* Trace management. */ | 25 | /* Trace management. */ |
26 | LJ_FUNC GCtrace * LJ_FASTCALL lj_trace_alloc(lua_State *L, GCtrace *T); | ||
26 | LJ_FUNC void LJ_FASTCALL lj_trace_free(global_State *g, GCtrace *T); | 27 | LJ_FUNC void LJ_FASTCALL lj_trace_free(global_State *g, GCtrace *T); |
27 | LJ_FUNC void lj_trace_reenableproto(GCproto *pt); | 28 | LJ_FUNC void lj_trace_reenableproto(GCproto *pt); |
28 | LJ_FUNC void lj_trace_flushproto(global_State *g, GCproto *pt); | 29 | LJ_FUNC void lj_trace_flushproto(global_State *g, GCproto *pt); |