aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Pall <mike>2010-03-01 06:45:30 +0100
committerMike Pall <mike>2010-03-01 06:45:30 +0100
commite7b737aa1202b06950b4ca4ec206b04bdd5a3681 (patch)
tree464258d534bfb05c1b8ee7d13cadc1422f689e4a /src
parent69ea553024155638c89bc12dca648c87a625ab5f (diff)
downloadluajit-e7b737aa1202b06950b4ca4ec206b04bdd5a3681.tar.gz
luajit-e7b737aa1202b06950b4ca4ec206b04bdd5a3681.tar.bz2
luajit-e7b737aa1202b06950b4ca4ec206b04bdd5a3681.zip
Implement down-recursion.
Diffstat (limited to 'src')
-rw-r--r--src/lj_asm.c8
-rw-r--r--src/lj_bc.h5
-rw-r--r--src/lj_dispatch.c7
-rw-r--r--src/lj_jit.h3
-rw-r--r--src/lj_record.c41
-rw-r--r--src/lj_trace.c62
-rw-r--r--src/lj_traceerr.h1
7 files changed, 114 insertions, 13 deletions
diff --git a/src/lj_asm.c b/src/lj_asm.c
index f38ceaef..34357e95 100644
--- a/src/lj_asm.c
+++ b/src/lj_asm.c
@@ -3212,8 +3212,14 @@ static void asm_tail_link(ASMState *as)
3212 3212
3213 if (as->T->link == TRACE_INTERP) { 3213 if (as->T->link == TRACE_INTERP) {
3214 /* Setup fixed registers for exit to interpreter. */ 3214 /* Setup fixed registers for exit to interpreter. */
3215 const BCIns *pc = snap_pc(as->T->snapmap[snap->mapofs + snap->nent]);
3216 if (bc_op(*pc) == BC_JLOOP) { /* NYI: find a better way to do this. */
3217 BCIns *retpc = &as->J->trace[bc_d(*pc)]->startins;
3218 if (bc_isret(bc_op(*retpc)))
3219 pc = retpc;
3220 }
3215 emit_loada(as, RID_DISPATCH, J2GG(as->J)->dispatch); 3221 emit_loada(as, RID_DISPATCH, J2GG(as->J)->dispatch);
3216 emit_loada(as, RID_PC, snap_pc(as->T->snapmap[snap->mapofs + snap->nent])); 3222 emit_loada(as, RID_PC, pc);
3217 } else if (baseslot) { 3223 } else if (baseslot) {
3218 /* Save modified BASE for linking to trace with higher start frame. */ 3224 /* Save modified BASE for linking to trace with higher start frame. */
3219 emit_setgl(as, RID_BASE, jit_base); 3225 emit_setgl(as, RID_BASE, jit_base);
diff --git a/src/lj_bc.h b/src/lj_bc.h
index e1284916..74b11698 100644
--- a/src/lj_bc.h
+++ b/src/lj_bc.h
@@ -245,6 +245,11 @@ typedef enum {
245 (BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)), 245 (BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)),
246#define BCMODE_FF 0 246#define BCMODE_FF 0
247 247
248static LJ_AINLINE int bc_isret(BCOp op)
249{
250 return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
251}
252
248LJ_DATA const uint16_t lj_bc_mode[]; 253LJ_DATA const uint16_t lj_bc_mode[];
249LJ_DATA const uint16_t lj_bc_ofs[]; 254LJ_DATA const uint16_t lj_bc_ofs[];
250 255
diff --git a/src/lj_dispatch.c b/src/lj_dispatch.c
index 83bb4fd8..f956aa1b 100644
--- a/src/lj_dispatch.c
+++ b/src/lj_dispatch.c
@@ -380,11 +380,8 @@ void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc)
380 L->top = L->base + slots; /* Fix top again. */ 380 L->top = L->base + slots; /* Fix top again. */
381 } 381 }
382 } 382 }
383 if ((g->hookmask & LUA_MASKRET)) { 383 if ((g->hookmask & LUA_MASKRET) && bc_isret(bc_op(pc[-1])))
384 BCOp op = bc_op(pc[-1]); 384 callhook(L, LUA_HOOKRET, -1);
385 if (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1)
386 callhook(L, LUA_HOOKRET, -1);
387 }
388} 385}
389 386
390/* Initialize call. Ensure stack space and clear missing parameters. */ 387/* Initialize call. Ensure stack space and clear missing parameters. */
diff --git a/src/lj_jit.h b/src/lj_jit.h
index 69156218..3201baf0 100644
--- a/src/lj_jit.h
+++ b/src/lj_jit.h
@@ -287,6 +287,9 @@ typedef struct jit_State {
287 TraceNo parent; /* Parent of current side trace (0 for root traces). */ 287 TraceNo parent; /* Parent of current side trace (0 for root traces). */
288 ExitNo exitno; /* Exit number in parent of current side trace. */ 288 ExitNo exitno; /* Exit number in parent of current side trace. */
289 289
290 BCIns *patchpc; /* PC for pending re-patch. */
291 BCIns patchins; /* Instruction for pending re-patch. */
292
290 TValue errinfo; /* Additional info element for trace errors. */ 293 TValue errinfo; /* Additional info element for trace errors. */
291 294
292 MCode *mcarea; /* Base of current mcode area. */ 295 MCode *mcarea; /* Base of current mcode area. */
diff --git a/src/lj_record.c b/src/lj_record.c
index da9c221c..62f5c066 100644
--- a/src/lj_record.c
+++ b/src/lj_record.c
@@ -522,6 +522,29 @@ static void rec_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs)
522 lj_trace_err(J, LJ_TRERR_LUNROLL); 522 lj_trace_err(J, LJ_TRERR_LUNROLL);
523} 523}
524 524
525/* Check unroll limits for down-recursion. */
526static int check_downrec_unroll(jit_State *J, GCproto *pt)
527{
528 IRRef ptref;
529 for (ptref = J->chain[IR_KGC]; ptref; ptref = IR(ptref)->prev)
530 if (ir_kgc(IR(ptref)) == obj2gco(pt)) {
531 int count = 0;
532 IRRef ref;
533 for (ref = J->chain[IR_RETF]; ref; ref = IR(ref)->prev)
534 if (IR(ref)->op1 == ptref)
535 count++;
536 if (count) {
537 if (J->pc == J->startpc) {
538 if (count + J->tailcalled > J->param[JIT_P_recunroll])
539 return 1;
540 } else {
541 lj_trace_err(J, LJ_TRERR_DOWNREC);
542 }
543 }
544 }
545 return 0;
546}
547
525/* Record return. */ 548/* Record return. */
526static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) 549static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
527{ 550{
@@ -545,6 +568,15 @@ static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
545 BCIns callins = *(frame_pc(frame)-1); 568 BCIns callins = *(frame_pc(frame)-1);
546 ptrdiff_t nresults = bc_b(callins) ? (ptrdiff_t)bc_b(callins)-1 :gotresults; 569 ptrdiff_t nresults = bc_b(callins) ? (ptrdiff_t)bc_b(callins)-1 :gotresults;
547 BCReg cbase = bc_a(callins); 570 BCReg cbase = bc_a(callins);
571 GCproto *pt = funcproto(frame_func(frame - (cbase+1)));
572 if (J->pt && frame == J->L->base - 1) {
573 if (J->framedepth == 0 && check_downrec_unroll(J, pt)) {
574 J->maxslot = rbase + nresults;
575 rec_stop(J, J->curtrace); /* Down-recursion. */
576 return;
577 }
578 lj_snap_add(J);
579 }
548 for (i = 0; i < nresults; i++) /* Adjust results. */ 580 for (i = 0; i < nresults; i++) /* Adjust results. */
549 J->base[i-1] = i < gotresults ? J->base[rbase+i] : TREF_NIL; 581 J->base[i-1] = i < gotresults ? J->base[rbase+i] : TREF_NIL;
550 J->maxslot = cbase+(BCReg)nresults; 582 J->maxslot = cbase+(BCReg)nresults;
@@ -553,11 +585,10 @@ static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
553 lua_assert(J->baseslot > cbase+1); 585 lua_assert(J->baseslot > cbase+1);
554 J->baseslot -= cbase+1; 586 J->baseslot -= cbase+1;
555 J->base -= cbase+1; 587 J->base -= cbase+1;
556 } else if (J->parent == 0) { 588 } else if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) {
557 /* Return to lower frame would leave the loop in a root trace. */ 589 /* Return to lower frame would leave the loop in a root trace. */
558 lj_trace_err(J, LJ_TRERR_LLEAVE); 590 lj_trace_err(J, LJ_TRERR_LLEAVE);
559 } else { /* Return to lower frame. Guard for the target we return to. */ 591 } else { /* Return to lower frame. Guard for the target we return to. */
560 GCproto *pt = funcproto(frame_func(frame - (cbase+1)));
561 TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); 592 TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO);
562 TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame)); 593 TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame));
563 emitir(IRTG(IR_RETF, IRT_PTR), trpt, trpc); 594 emitir(IRTG(IR_RETF, IRT_PTR), trpt, trpc);
@@ -2285,6 +2316,12 @@ static const BCIns *rec_setup_root(jit_State *J)
2285 J->maxslot = ra; 2316 J->maxslot = ra;
2286 pc++; 2317 pc++;
2287 break; 2318 break;
2319 case BC_RET:
2320 case BC_RET0:
2321 case BC_RET1:
2322 /* No bytecode range check for down-recursive root traces. */
2323 J->maxslot = ra + bc_d(ins);
2324 break;
2288 case BC_FUNCF: 2325 case BC_FUNCF:
2289 /* No bytecode range check for root traces started by a hot call. */ 2326 /* No bytecode range check for root traces started by a hot call. */
2290 J->maxslot = J->pt->numparams; 2327 J->maxslot = J->pt->numparams;
diff --git a/src/lj_trace.c b/src/lj_trace.c
index 0b55f717..246dc03c 100644
--- a/src/lj_trace.c
+++ b/src/lj_trace.c
@@ -357,6 +357,8 @@ static void trace_start(jit_State *J)
357 if ((J->pt->flags & PROTO_NO_JIT)) { /* JIT disabled for this proto? */ 357 if ((J->pt->flags & PROTO_NO_JIT)) { /* JIT disabled for this proto? */
358 if (J->parent == 0) { 358 if (J->parent == 0) {
359 /* Lazy bytecode patching to disable hotcount events. */ 359 /* Lazy bytecode patching to disable hotcount events. */
360 lua_assert(bc_op(*J->pc) == BC_FORL || bc_op(*J->pc) == BC_ITERL ||
361 bc_op(*J->pc) == BC_LOOP || bc_op(*J->pc) == BC_FUNCF);
360 setbc_op(J->pc, (int)bc_op(*J->pc)+(int)BC_ILOOP-(int)BC_LOOP); 362 setbc_op(J->pc, (int)bc_op(*J->pc)+(int)BC_ILOOP-(int)BC_LOOP);
361 J->pt->flags |= PROTO_HAS_ILOOP; 363 J->pt->flags |= PROTO_HAS_ILOOP;
362 } 364 }
@@ -416,10 +418,16 @@ static void trace_stop(jit_State *J)
416 /* Patch bytecode of starting instruction in root trace. */ 418 /* Patch bytecode of starting instruction in root trace. */
417 setbc_op(pc, (int)op+(int)BC_JLOOP-(int)BC_LOOP); 419 setbc_op(pc, (int)op+(int)BC_JLOOP-(int)BC_LOOP);
418 setbc_d(pc, J->curtrace); 420 setbc_d(pc, J->curtrace);
421 addroot:
419 /* Add to root trace chain in prototype. */ 422 /* Add to root trace chain in prototype. */
420 J->cur.nextroot = pt->trace; 423 J->cur.nextroot = pt->trace;
421 pt->trace = (TraceNo1)J->curtrace; 424 pt->trace = (TraceNo1)J->curtrace;
422 break; 425 break;
426 case BC_RET:
427 case BC_RET0:
428 case BC_RET1:
429 *pc = BCINS_AD(BC_JLOOP, J->cur.snap[0].nslots, J->curtrace);
430 goto addroot;
423 case BC_JMP: 431 case BC_JMP:
424 /* Patch exit branch in parent to side trace entry. */ 432 /* Patch exit branch in parent to side trace entry. */
425 lua_assert(J->parent != 0 && J->cur.root != 0); 433 lua_assert(J->parent != 0 && J->cur.root != 0);
@@ -450,6 +458,21 @@ static void trace_stop(jit_State *J)
450 ); 458 );
451} 459}
452 460
461/* Start a new root trace for down-recursion. */
462static int trace_downrec(jit_State *J)
463{
464 /* Restart recording at the return instruction. */
465 lua_assert(J->pt != NULL);
466 lua_assert(bc_isret(bc_op(*J->pc)));
467 if (bc_op(*J->pc) == BC_RETM)
468 return 0; /* NYI: down-recursion with RETM. */
469 J->parent = 0;
470 J->exitno = 0;
471 J->state = LJ_TRACE_RECORD;
472 trace_start(J);
473 return 1;
474}
475
453/* Abort tracing. */ 476/* Abort tracing. */
454static int trace_abort(jit_State *J) 477static int trace_abort(jit_State *J)
455{ 478{
@@ -463,7 +486,7 @@ static int trace_abort(jit_State *J)
463 return 1; /* Retry ASM with new MCode area. */ 486 return 1; /* Retry ASM with new MCode area. */
464 } 487 }
465 /* Penalize or blacklist starting bytecode instruction. */ 488 /* Penalize or blacklist starting bytecode instruction. */
466 if (J->parent == 0) 489 if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins)))
467 penalty_pc(J, &gcref(J->cur.startpt)->pt, (BCIns *)J->startpc, e); 490 penalty_pc(J, &gcref(J->cur.startpt)->pt, (BCIns *)J->startpc, e);
468 if (J->curtrace) { /* Is there anything to abort? */ 491 if (J->curtrace) { /* Is there anything to abort? */
469 ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ 492 ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */
@@ -493,17 +516,29 @@ static int trace_abort(jit_State *J)
493 J->curtrace = 0; 516 J->curtrace = 0;
494 } 517 }
495 L->top--; /* Remove error object */ 518 L->top--; /* Remove error object */
496 if (e == LJ_TRERR_MCODEAL) 519 if (e == LJ_TRERR_DOWNREC)
520 return trace_downrec(J);
521 else if (e == LJ_TRERR_MCODEAL)
497 lj_trace_flushall(L); 522 lj_trace_flushall(L);
498 return 0; 523 return 0;
499} 524}
500 525
526/* Perform pending re-patch of a bytecode instruction. */
527static LJ_AINLINE void trace_pendpatch(jit_State *J, int force)
528{
529 if (LJ_UNLIKELY(J->patchpc) && (force || J->chain[IR_RETF])) {
530 *J->patchpc = J->patchins;
531 J->patchpc = NULL;
532 }
533}
534
501/* State machine for the trace compiler. Protected callback. */ 535/* State machine for the trace compiler. Protected callback. */
502static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud) 536static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud)
503{ 537{
504 jit_State *J = (jit_State *)ud; 538 jit_State *J = (jit_State *)ud;
505 UNUSED(dummy); 539 UNUSED(dummy);
506 do { 540 do {
541 retry:
507 switch (J->state) { 542 switch (J->state) {
508 case LJ_TRACE_START: 543 case LJ_TRACE_START:
509 J->state = LJ_TRACE_RECORD; /* trace_start() may change state. */ 544 J->state = LJ_TRACE_RECORD; /* trace_start() may change state. */
@@ -512,6 +547,7 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud)
512 break; 547 break;
513 548
514 case LJ_TRACE_RECORD: 549 case LJ_TRACE_RECORD:
550 trace_pendpatch(J, 0);
515 setvmstate(J2G(J), RECORD); 551 setvmstate(J2G(J), RECORD);
516 lj_vmevent_send(L, RECORD, 552 lj_vmevent_send(L, RECORD,
517 setintV(L->top++, J->curtrace); 553 setintV(L->top++, J->curtrace);
@@ -523,6 +559,7 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud)
523 break; 559 break;
524 560
525 case LJ_TRACE_END: 561 case LJ_TRACE_END:
562 trace_pendpatch(J, 1);
526 J->loopref = 0; 563 J->loopref = 0;
527 if ((J->flags & JIT_F_OPT_LOOP) && 564 if ((J->flags & JIT_F_OPT_LOOP) &&
528 J->cur.link == J->curtrace && J->framedepth + J->retdepth == 0) { 565 J->cur.link == J->curtrace && J->framedepth + J->retdepth == 0) {
@@ -551,8 +588,9 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud)
551 setintV(L->top++, (int32_t)LJ_TRERR_RECERR); 588 setintV(L->top++, (int32_t)LJ_TRERR_RECERR);
552 /* fallthrough */ 589 /* fallthrough */
553 case LJ_TRACE_ERR: 590 case LJ_TRACE_ERR:
591 trace_pendpatch(J, 1);
554 if (trace_abort(J)) 592 if (trace_abort(J))
555 break; /* Retry. */ 593 goto retry;
556 setvmstate(J2G(J), INTERP); 594 setvmstate(J2G(J), INTERP);
557 J->state = LJ_TRACE_IDLE; 595 J->state = LJ_TRACE_IDLE;
558 lj_dispatch_update(J2G(J)); 596 lj_dispatch_update(J2G(J));
@@ -627,6 +665,7 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
627 lua_State *L = J->L; 665 lua_State *L = J->L;
628 ExitDataCP exd; 666 ExitDataCP exd;
629 int errcode; 667 int errcode;
668 const BCIns *pc;
630 exd.J = J; 669 exd.J = J;
631 exd.exptr = exptr; 670 exd.exptr = exptr;
632 errcode = lj_vm_cpcall(L, NULL, &exd, trace_exit_cp); 671 errcode = lj_vm_cpcall(L, NULL, &exd, trace_exit_cp);
@@ -651,8 +690,21 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
651 } 690 }
652 ); 691 );
653 692
654 trace_hotside(J, exd.pc); 693 pc = exd.pc;
655 setcframe_pc(cframe_raw(L->cframe), exd.pc); 694 trace_hotside(J, pc);
695 if (bc_op(*pc) == BC_JLOOP) {
696 BCIns *retpc = &J->trace[bc_d(*pc)]->startins;
697 if (bc_isret(bc_op(*retpc))) {
698 if (J->state == LJ_TRACE_RECORD) {
699 J->patchins = *pc;
700 J->patchpc = (BCIns *)pc;
701 *J->patchpc = *retpc;
702 } else {
703 pc = retpc;
704 }
705 }
706 }
707 setcframe_pc(cframe_raw(L->cframe), pc);
656 return 0; 708 return 0;
657} 709}
658 710
diff --git a/src/lj_traceerr.h b/src/lj_traceerr.h
index db7668fe..7b0dd813 100644
--- a/src/lj_traceerr.h
+++ b/src/lj_traceerr.h
@@ -22,6 +22,7 @@ TREDEF(LUNROLL, "loop unroll limit reached")
22TREDEF(BADTYPE, "bad argument type") 22TREDEF(BADTYPE, "bad argument type")
23TREDEF(CJITOFF, "call to JIT-disabled function") 23TREDEF(CJITOFF, "call to JIT-disabled function")
24TREDEF(CUNROLL, "call unroll limit reached") 24TREDEF(CUNROLL, "call unroll limit reached")
25TREDEF(DOWNREC, "down-recursion, restarting")
25TREDEF(NYIVF, "NYI: vararg function") 26TREDEF(NYIVF, "NYI: vararg function")
26TREDEF(NYICF, "NYI: C function %p") 27TREDEF(NYICF, "NYI: C function %p")
27TREDEF(NYIFF, "NYI: FastFunc %s") 28TREDEF(NYIFF, "NYI: FastFunc %s")