diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-01-28 14:40:29 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-01-28 14:40:29 -0300 |
commit | 949187b049ce329c93d6639b91e244f2b208c807 (patch) | |
tree | e758128392692fe349087e457fc743ea4f56e4bb /ldebug.c | |
parent | 58aa09a0b91cf81779d6710d7f9d855bb9d3712f (diff) | |
download | lua-949187b049ce329c93d6639b91e244f2b208c807.tar.gz lua-949187b049ce329c93d6639b91e244f2b208c807.tar.bz2 lua-949187b049ce329c93d6639b91e244f2b208c807.zip |
Optimizations for line hook
The function 'changedline' tries harder to avoid calling
'luaG_getfuncline' plus small changes in the use of 'L->oldpc'.
Diffstat (limited to 'ldebug.c')
-rw-r--r-- | ldebug.c | 52 |
1 files changed, 32 insertions, 20 deletions
@@ -33,8 +33,6 @@ | |||
33 | 33 | ||
34 | #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) | 34 | #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) |
35 | 35 | ||
36 | /* inverse of 'pcRel' */ | ||
37 | #define invpcRel(pc, p) ((p)->code + (pc) + 1) | ||
38 | 36 | ||
39 | static const char *funcnamefromcode (lua_State *L, CallInfo *ci, | 37 | static const char *funcnamefromcode (lua_State *L, CallInfo *ci, |
40 | const char **name); | 38 | const char **name); |
@@ -791,16 +789,30 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { | |||
791 | 789 | ||
792 | /* | 790 | /* |
793 | ** Check whether new instruction 'newpc' is in a different line from | 791 | ** Check whether new instruction 'newpc' is in a different line from |
794 | ** previous instruction 'oldpc'. | 792 | ** previous instruction 'oldpc'. More often than not, 'newpc' is only |
793 | ** one or a few instructions after 'oldpc' (it must be after, see | ||
794 | ** caller), so try to avoid calling 'luaG_getfuncline'. If they are | ||
795 | ** too far apart, there is a good chance of a ABSLINEINFO in the way, | ||
796 | ** so it goes directly to 'luaG_getfuncline'. | ||
795 | */ | 797 | */ |
796 | static int changedline (const Proto *p, int oldpc, int newpc) { | 798 | static int changedline (const Proto *p, int oldpc, int newpc) { |
797 | if (p->lineinfo == NULL) /* no debug information? */ | 799 | if (p->lineinfo == NULL) /* no debug information? */ |
798 | return 0; | 800 | return 0; |
799 | while (oldpc++ < newpc) { | 801 | if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ |
800 | if (p->lineinfo[oldpc] != 0) | 802 | int delta = 0; /* line diference */ |
801 | return (luaG_getfuncline(p, oldpc - 1) != luaG_getfuncline(p, newpc)); | 803 | int pc = oldpc; |
804 | for (;;) { | ||
805 | int lineinfo = p->lineinfo[++pc]; | ||
806 | if (lineinfo == ABSLINEINFO) | ||
807 | break; /* cannot compute delta; fall through */ | ||
808 | delta += lineinfo; | ||
809 | if (pc == newpc) | ||
810 | return (delta != 0); /* delta computed successfully */ | ||
811 | } | ||
802 | } | 812 | } |
803 | return 0; /* no line changes between positions */ | 813 | /* either instructions are too far apart or there is an absolute line |
814 | info in the way; compute line difference explicitly */ | ||
815 | return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc)); | ||
804 | } | 816 | } |
805 | 817 | ||
806 | 818 | ||
@@ -808,20 +820,19 @@ static int changedline (const Proto *p, int oldpc, int newpc) { | |||
808 | ** Traces the execution of a Lua function. Called before the execution | 820 | ** Traces the execution of a Lua function. Called before the execution |
809 | ** of each opcode, when debug is on. 'L->oldpc' stores the last | 821 | ** of each opcode, when debug is on. 'L->oldpc' stores the last |
810 | ** instruction traced, to detect line changes. When entering a new | 822 | ** instruction traced, to detect line changes. When entering a new |
811 | ** function, 'npci' will be zero and will test as a new line without | 823 | ** function, 'npci' will be zero and will test as a new line whatever |
812 | ** the need for 'oldpc'; so, 'oldpc' does not need to be initialized | 824 | ** the value of 'oldpc'. Some exceptional conditions may return to |
813 | ** before. Some exceptional conditions may return to a function without | 825 | ** a function without setting 'oldpc'. In that case, 'oldpc' may be |
814 | ** updating 'oldpc'. In that case, 'oldpc' may be invalid; if so, it is | 826 | ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' |
815 | ** reset to zero. (A wrong but valid 'oldpc' at most causes an extra | 827 | ** at most causes an extra call to a line hook.) |
816 | ** call to a line hook.) | 828 | ** This function is not "Protected" when called, so it should correct |
829 | ** 'L->top' before calling anything that can run the GC. | ||
817 | */ | 830 | */ |
818 | int luaG_traceexec (lua_State *L, const Instruction *pc) { | 831 | int luaG_traceexec (lua_State *L, const Instruction *pc) { |
819 | CallInfo *ci = L->ci; | 832 | CallInfo *ci = L->ci; |
820 | lu_byte mask = L->hookmask; | 833 | lu_byte mask = L->hookmask; |
821 | const Proto *p = ci_func(ci)->p; | 834 | const Proto *p = ci_func(ci)->p; |
822 | int counthook; | 835 | int counthook; |
823 | /* 'L->oldpc' may be invalid; reset it in this case */ | ||
824 | int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; | ||
825 | if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ | 836 | if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ |
826 | ci->u.l.trap = 0; /* don't need to stop again */ | 837 | ci->u.l.trap = 0; /* don't need to stop again */ |
827 | return 0; /* turn off 'trap' */ | 838 | return 0; /* turn off 'trap' */ |
@@ -837,15 +848,16 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { | |||
837 | ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ | 848 | ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ |
838 | return 1; /* do not call hook again (VM yielded, so it did not move) */ | 849 | return 1; /* do not call hook again (VM yielded, so it did not move) */ |
839 | } | 850 | } |
840 | if (!isIT(*(ci->u.l.savedpc - 1))) | 851 | if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ |
841 | L->top = ci->top; /* prepare top */ | 852 | L->top = ci->top; /* correct top */ |
842 | if (counthook) | 853 | if (counthook) |
843 | luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ | 854 | luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ |
844 | if (mask & LUA_MASKLINE) { | 855 | if (mask & LUA_MASKLINE) { |
856 | /* 'L->oldpc' may be invalid; use zero in this case */ | ||
857 | int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; | ||
845 | int npci = pcRel(pc, p); | 858 | int npci = pcRel(pc, p); |
846 | if (npci == 0 || /* call linehook when enter a new function, */ | 859 | if (npci <= oldpc || /* call hook when jump back (loop), */ |
847 | pc <= invpcRel(oldpc, p) || /* when jump back (loop), or when */ | 860 | changedline(p, oldpc, npci)) { /* or when enter new line */ |
848 | changedline(p, oldpc, npci)) { /* enter new line */ | ||
849 | int newline = luaG_getfuncline(p, npci); | 861 | int newline = luaG_getfuncline(p, npci); |
850 | luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ | 862 | luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ |
851 | } | 863 | } |