diff options
author | Mike Pall <mike> | 2010-03-01 06:45:30 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2010-03-01 06:45:30 +0100 |
commit | e7b737aa1202b06950b4ca4ec206b04bdd5a3681 (patch) | |
tree | 464258d534bfb05c1b8ee7d13cadc1422f689e4a /src | |
parent | 69ea553024155638c89bc12dca648c87a625ab5f (diff) | |
download | luajit-e7b737aa1202b06950b4ca4ec206b04bdd5a3681.tar.gz luajit-e7b737aa1202b06950b4ca4ec206b04bdd5a3681.tar.bz2 luajit-e7b737aa1202b06950b4ca4ec206b04bdd5a3681.zip |
Implement down-recursion.
Diffstat (limited to 'src')
-rw-r--r-- | src/lj_asm.c | 8 | ||||
-rw-r--r-- | src/lj_bc.h | 5 | ||||
-rw-r--r-- | src/lj_dispatch.c | 7 | ||||
-rw-r--r-- | src/lj_jit.h | 3 | ||||
-rw-r--r-- | src/lj_record.c | 41 | ||||
-rw-r--r-- | src/lj_trace.c | 62 | ||||
-rw-r--r-- | src/lj_traceerr.h | 1 |
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 | ||
248 | static LJ_AINLINE int bc_isret(BCOp op) | ||
249 | { | ||
250 | return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1); | ||
251 | } | ||
252 | |||
248 | LJ_DATA const uint16_t lj_bc_mode[]; | 253 | LJ_DATA const uint16_t lj_bc_mode[]; |
249 | LJ_DATA const uint16_t lj_bc_ofs[]; | 254 | LJ_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. */ | ||
526 | static 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. */ |
526 | static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) | 549 | static 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. */ | ||
462 | static 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. */ |
454 | static int trace_abort(jit_State *J) | 477 | static 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. */ | ||
527 | static 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. */ |
502 | static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud) | 536 | static 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") | |||
22 | TREDEF(BADTYPE, "bad argument type") | 22 | TREDEF(BADTYPE, "bad argument type") |
23 | TREDEF(CJITOFF, "call to JIT-disabled function") | 23 | TREDEF(CJITOFF, "call to JIT-disabled function") |
24 | TREDEF(CUNROLL, "call unroll limit reached") | 24 | TREDEF(CUNROLL, "call unroll limit reached") |
25 | TREDEF(DOWNREC, "down-recursion, restarting") | ||
25 | TREDEF(NYIVF, "NYI: vararg function") | 26 | TREDEF(NYIVF, "NYI: vararg function") |
26 | TREDEF(NYICF, "NYI: C function %p") | 27 | TREDEF(NYICF, "NYI: C function %p") |
27 | TREDEF(NYIFF, "NYI: FastFunc %s") | 28 | TREDEF(NYIFF, "NYI: FastFunc %s") |