diff options
Diffstat (limited to 'src/lj_trace.c')
-rw-r--r-- | src/lj_trace.c | 62 |
1 files changed, 57 insertions, 5 deletions
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 | ||