aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2013-09-02 01:49:19 +0200
committerMike Pall <mike>2013-09-02 01:49:19 +0200
commit4dce22c40d38dd7dc3d05cc383ddf004fb1f92c4 (patch)
tree34800356c01e0a4f7f820d5affb131de8c091d89
parent19c2dd17dbaf66f1341efe2a71a26f0b5724f9e1 (diff)
downloadluajit-4dce22c40d38dd7dc3d05cc383ddf004fb1f92c4.tar.gz
luajit-4dce22c40d38dd7dc3d05cc383ddf004fb1f92c4.tar.bz2
luajit-4dce22c40d38dd7dc3d05cc383ddf004fb1f92c4.zip
Add low-overhead profiler. Part 1: interpreter, low-level C API.
-rw-r--r--src/Makefile2
-rw-r--r--src/Makefile.dep36
-rw-r--r--src/lj_arch.h12
-rw-r--r--src/lj_debug.c111
-rw-r--r--src/lj_debug.h6
-rw-r--r--src/lj_dispatch.c55
-rw-r--r--src/lj_dispatch.h6
-rw-r--r--src/lj_obj.h1
-rw-r--r--src/lj_profile.c274
-rw-r--r--src/lj_profile.h17
-rw-r--r--src/lj_state.c6
-rw-r--r--src/lj_vm.h1
-rw-r--r--src/ljamalg.c1
-rw-r--r--src/luajit.h9
-rw-r--r--src/vm_arm.dasc12
-rw-r--r--src/vm_mips.dasc14
-rw-r--r--src/vm_ppc.dasc13
-rw-r--r--src/vm_x86.dasc15
18 files changed, 558 insertions, 33 deletions
diff --git a/src/Makefile b/src/Makefile
index 441feffb..e7f48fdd 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -446,7 +446,7 @@ LJLIB_C= $(LJLIB_O:.o=.c)
446LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \ 446LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
447 lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \ 447 lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
448 lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \ 448 lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \
449 lj_strfmt.o lj_api.o \ 449 lj_strfmt.o lj_api.o lj_profile.o \
450 lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \ 450 lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
451 lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \ 451 lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
452 lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \ 452 lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \
diff --git a/src/Makefile.dep b/src/Makefile.dep
index 0ea0d98e..7991bd16 100644
--- a/src/Makefile.dep
+++ b/src/Makefile.dep
@@ -102,7 +102,7 @@ lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
102 lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_func.h lj_tab.h \ 102 lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_func.h lj_tab.h \
103 lj_meta.h lj_debug.h lj_state.h lj_frame.h lj_bc.h lj_ff.h lj_ffdef.h \ 103 lj_meta.h lj_debug.h lj_state.h lj_frame.h lj_bc.h lj_ff.h lj_ffdef.h \
104 lj_strfmt.h lj_jit.h lj_ir.h lj_ccallback.h lj_ctype.h lj_trace.h \ 104 lj_strfmt.h lj_jit.h lj_ir.h lj_ccallback.h lj_ctype.h lj_trace.h \
105 lj_dispatch.h lj_traceerr.h lj_vm.h luajit.h 105 lj_dispatch.h lj_traceerr.h lj_profile.h lj_vm.h luajit.h
106lj_err.o: lj_err.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_err.h \ 106lj_err.o: lj_err.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_err.h \
107 lj_errmsg.h lj_debug.h lj_str.h lj_func.h lj_state.h lj_frame.h lj_bc.h \ 107 lj_errmsg.h lj_debug.h lj_str.h lj_func.h lj_state.h lj_frame.h lj_bc.h \
108 lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \ 108 lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \
@@ -168,6 +168,9 @@ lj_parse.o: lj_parse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
168 lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_str.h lj_tab.h \ 168 lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_str.h lj_tab.h \
169 lj_func.h lj_state.h lj_bc.h lj_ctype.h lj_strfmt.h lj_lex.h lj_parse.h \ 169 lj_func.h lj_state.h lj_bc.h lj_ctype.h lj_strfmt.h lj_lex.h lj_parse.h \
170 lj_vm.h lj_vmevent.h 170 lj_vm.h lj_vmevent.h
171lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
172 lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \
173 lj_jit.h lj_ir.h lj_profile.h luajit.h
171lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 174lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
172 lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \ 175 lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
173 lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h \ 176 lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h \
@@ -180,7 +183,7 @@ lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
180lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 183lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
181 lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h \ 184 lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h \
182 lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_trace.h lj_jit.h \ 185 lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_trace.h lj_jit.h \
183 lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_alloc.h 186 lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_alloc.h luajit.h
184lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 187lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
185 lj_err.h lj_errmsg.h lj_str.h lj_char.h 188 lj_err.h lj_errmsg.h lj_str.h lj_char.h
186lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 189lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
@@ -208,20 +211,21 @@ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
208 lj_vm.h lj_err.c lj_debug.h lj_ff.h lj_ffdef.h lj_strfmt.h lj_char.c \ 211 lj_vm.h lj_err.c lj_debug.h lj_ff.h lj_ffdef.h lj_strfmt.h lj_char.c \
209 lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_buf.c lj_str.c lj_tab.c \ 212 lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_buf.c lj_str.c lj_tab.c \
210 lj_func.c lj_udata.c lj_meta.c lj_strscan.h lj_lib.h lj_debug.c \ 213 lj_func.c lj_udata.c lj_meta.c lj_strscan.h lj_lib.h lj_debug.c \
211 lj_state.c lj_lex.h lj_alloc.h lj_dispatch.c lj_ccallback.h luajit.h \ 214 lj_state.c lj_lex.h lj_alloc.h luajit.h lj_dispatch.c lj_ccallback.h \
212 lj_vmevent.c lj_vmevent.h lj_vmmath.c lj_strscan.c lj_strfmt.c lj_api.c \ 215 lj_profile.h lj_vmevent.c lj_vmevent.h lj_vmmath.c lj_strscan.c \
213 lj_lex.c lualib.h lj_parse.h lj_parse.c lj_bcread.c lj_bcdump.h \ 216 lj_strfmt.c lj_api.c lj_profile.c lj_lex.c lualib.h lj_parse.h \
214 lj_bcwrite.c lj_load.c lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c \ 217 lj_parse.c lj_bcread.c lj_bcdump.h lj_bcwrite.c lj_load.c lj_ctype.c \
215 lj_ccall.c lj_ccall.h lj_ccallback.c lj_target.h lj_target_*.h \ 218 lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_ccallback.c \
216 lj_mcode.h lj_carith.c lj_carith.h lj_clib.c lj_clib.h lj_cparse.c \ 219 lj_target.h lj_target_*.h lj_mcode.h lj_carith.c lj_carith.h lj_clib.c \
217 lj_cparse.h lj_lib.c lj_ir.c lj_ircall.h lj_iropt.h lj_opt_mem.c \ 220 lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c lj_ircall.h \
218 lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c \ 221 lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c \
219 lj_snap.h lj_opt_split.c lj_opt_sink.c lj_mcode.c lj_snap.c lj_record.c \ 222 lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c lj_opt_sink.c \
220 lj_record.h lj_ffrecord.h lj_crecord.c lj_crecord.h lj_ffrecord.c \ 223 lj_mcode.c lj_snap.c lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \
221 lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h lj_asm_*.h lj_trace.c \ 224 lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h \
222 lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c lj_libdef.h \ 225 lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c \
223 lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c \ 226 lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c lib_io.c \
224 lib_debug.c lib_bit.c lib_jit.c lib_ffi.c lib_init.c 227 lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c lib_ffi.c \
228 lib_init.c
225luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h 229luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h
226host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \ 230host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \
227 lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \ 231 lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \
diff --git a/src/lj_arch.h b/src/lj_arch.h
index c5f2fb3d..ccb54270 100644
--- a/src/lj_arch.h
+++ b/src/lj_arch.h
@@ -366,6 +366,18 @@
366#define LJ_HASFFI 1 366#define LJ_HASFFI 1
367#endif 367#endif
368 368
369#if defined(LUAJIT_DISABLE_PROFILE)
370#define LJ_HASPROFILE 0
371#elif LJ_TARGET_POSIX
372#define LJ_HASPROFILE 1
373#define LJ_PROFILE_SIGPROF 1
374#elif LJ_TARGET_WINDOWS
375#define LJ_HASPROFILE 1
376#define LJ_PROFILE_WTHREAD 1
377#else
378#define LJ_HASPROFILE 0
379#endif
380
369#ifndef LJ_ARCH_HASFPU 381#ifndef LJ_ARCH_HASFPU
370#define LJ_ARCH_HASFPU 1 382#define LJ_ARCH_HASFPU 1
371#endif 383#endif
diff --git a/src/lj_debug.c b/src/lj_debug.c
index 24efd2ff..8166fcc0 100644
--- a/src/lj_debug.c
+++ b/src/lj_debug.c
@@ -28,7 +28,7 @@ cTValue *lj_debug_frame(lua_State *L, int level, int *size)
28 /* Traverse frames backwards. */ 28 /* Traverse frames backwards. */
29 for (nextframe = frame = L->base-1; frame > bot; ) { 29 for (nextframe = frame = L->base-1; frame > bot; ) {
30 if (frame_gc(frame) == obj2gco(L)) 30 if (frame_gc(frame) == obj2gco(L))
31 level++; /* Skip dummy frames. See lj_meta_call(). */ 31 level++; /* Skip dummy frames. See lj_err_optype_call(). */
32 if (level-- == 0) { 32 if (level-- == 0) {
33 *size = (int)(nextframe - frame); 33 *size = (int)(nextframe - frame);
34 return frame; /* Level found. */ 34 return frame; /* Level found. */
@@ -278,9 +278,9 @@ restart:
278} 278}
279 279
280/* Deduce function name from caller of a frame. */ 280/* Deduce function name from caller of a frame. */
281const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) 281const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name)
282{ 282{
283 TValue *pframe; 283 cTValue *pframe;
284 GCfunc *fn; 284 GCfunc *fn;
285 BCPos pc; 285 BCPos pc;
286 if (frame <= tvref(L->stack)) 286 if (frame <= tvref(L->stack))
@@ -534,6 +534,111 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
534 } 534 }
535} 535}
536 536
537#if LJ_HASPROFILE
538/* Put the chunkname into a buffer. */
539static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip)
540{
541 GCstr *name = proto_chunkname(pt);
542 const char *p = strdata(name);
543 if (pt->firstline == ~(BCLine)0) {
544 lj_buf_putmem(sb, "[builtin:", 9);
545 lj_buf_putstr(sb, name);
546 lj_buf_putb(sb, ']');
547 return 0;
548 }
549 if (*p == '=' || *p == '@') {
550 MSize len = name->len-1;
551 p++;
552 if (pathstrip) {
553 int i;
554 for (i = len-1; i >= 0; i--)
555 if (p[i] == '/' || p[i] == '\\') {
556 len -= i+1;
557 p = p+i+1;
558 break;
559 }
560 }
561 lj_buf_putmem(sb, p, len);
562 } else {
563 lj_buf_putmem(sb, "[string]", 9);
564 }
565 return 1;
566}
567
568/* Put a compact stack dump into a buffer. */
569void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth)
570{
571 int level = 0, dir = 1, pathstrip = 1;
572 MSize lastlen = 0;
573 if (depth < 0) { level = ~depth; depth = dir = -1; } /* Reverse frames. */
574 while (level != depth) { /* Loop through all frame. */
575 int size;
576 cTValue *frame = lj_debug_frame(L, level, &size);
577 if (frame) {
578 cTValue *nextframe = size ? frame+size : NULL;
579 GCfunc *fn = frame_func(frame);
580 const uint8_t *p = (const uint8_t *)fmt;
581 int c;
582 while ((c = *p++)) {
583 switch (c) {
584 case 'p': /* Preserve full path. */
585 pathstrip = 0;
586 break;
587 case 'F': case 'f': { /* Dump function name. */
588 const char *name;
589 const char *what = lj_debug_funcname(L, frame, &name);
590 if (what) {
591 if (c == 'F' && isluafunc(fn)) { /* Dump module:name for 'F'. */
592 GCproto *pt = funcproto(fn);
593 if (pt->firstline != ~(BCLine)0) { /* Not a bytecode builtin. */
594 debug_putchunkname(sb, pt, pathstrip);
595 lj_buf_putb(sb, ':');
596 }
597 }
598 lj_buf_putmem(sb, name, (MSize)strlen(name));
599 break;
600 } /* else: can't derive a name, dump module:line. */
601 }
602 /* fallthrough */
603 case 'l': /* Dump module:line. */
604 if (isluafunc(fn)) {
605 GCproto *pt = funcproto(fn);
606 if (debug_putchunkname(sb, pt, pathstrip)) {
607 /* Regular Lua function. */
608 BCLine line = c == 'l' ? debug_frameline(L, fn, nextframe) :
609 pt->firstline;
610 lj_buf_putb(sb, ':');
611 lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline);
612 }
613 } else if (isffunc(fn)) { /* Dump numbered builtins. */
614 lj_buf_putmem(sb, "[builtin#", 9);
615 lj_strfmt_putint(sb, fn->c.ffid);
616 lj_buf_putb(sb, ']');
617 } else { /* Dump C function address. */
618 lj_buf_putb(sb, '@');
619 lj_strfmt_putptr(sb, fn->c.f);
620 }
621 break;
622 case 'Z': /* Zap trailing separator. */
623 lastlen = sbuflen(sb);
624 break;
625 default:
626 lj_buf_putb(sb, c);
627 break;
628 }
629 }
630 } else if (dir == 1) {
631 break;
632 } else {
633 level -= size; /* Reverse frame order: quickly skip missing level. */
634 }
635 level += dir;
636 }
637 if (lastlen)
638 setsbufP(sb, sbufB(sb) + lastlen); /* Zap trailing separator. */
639}
640#endif
641
537/* Number of frames for the leading and trailing part of a traceback. */ 642/* Number of frames for the leading and trailing part of a traceback. */
538#define TRACEBACK_LEVELS1 12 643#define TRACEBACK_LEVELS1 12
539#define TRACEBACK_LEVELS2 10 644#define TRACEBACK_LEVELS2 10
diff --git a/src/lj_debug.h b/src/lj_debug.h
index 4144b47e..d93380ac 100644
--- a/src/lj_debug.h
+++ b/src/lj_debug.h
@@ -32,7 +32,7 @@ LJ_FUNC const char *lj_debug_uvname(GCproto *pt, uint32_t idx);
32LJ_FUNC const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp); 32LJ_FUNC const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp);
33LJ_FUNC const char *lj_debug_slotname(GCproto *pt, const BCIns *pc, 33LJ_FUNC const char *lj_debug_slotname(GCproto *pt, const BCIns *pc,
34 BCReg slot, const char **name); 34 BCReg slot, const char **name);
35LJ_FUNC const char *lj_debug_funcname(lua_State *L, TValue *frame, 35LJ_FUNC const char *lj_debug_funcname(lua_State *L, cTValue *frame,
36 const char **name); 36 const char **name);
37LJ_FUNC void lj_debug_shortname(char *out, GCstr *str, BCLine line); 37LJ_FUNC void lj_debug_shortname(char *out, GCstr *str, BCLine line);
38LJ_FUNC void lj_debug_addloc(lua_State *L, const char *msg, 38LJ_FUNC void lj_debug_addloc(lua_State *L, const char *msg,
@@ -40,6 +40,10 @@ LJ_FUNC void lj_debug_addloc(lua_State *L, const char *msg,
40LJ_FUNC void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc); 40LJ_FUNC void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc);
41LJ_FUNC int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, 41LJ_FUNC int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar,
42 int ext); 42 int ext);
43#if LJ_HASPROFILE
44LJ_FUNC void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt,
45 int depth);
46#endif
43 47
44/* Fixed internal variable names. */ 48/* Fixed internal variable names. */
45#define VARNAMEDEF(_) \ 49#define VARNAMEDEF(_) \
diff --git a/src/lj_dispatch.c b/src/lj_dispatch.c
index d76dda41..01bc4239 100644
--- a/src/lj_dispatch.c
+++ b/src/lj_dispatch.c
@@ -27,6 +27,9 @@
27#endif 27#endif
28#include "lj_trace.h" 28#include "lj_trace.h"
29#include "lj_dispatch.h" 29#include "lj_dispatch.h"
30#if LJ_HASPROFILE
31#include "lj_profile.h"
32#endif
30#include "lj_vm.h" 33#include "lj_vm.h"
31#include "luajit.h" 34#include "luajit.h"
32 35
@@ -84,11 +87,12 @@ void lj_dispatch_init_hotcount(global_State *g)
84#endif 87#endif
85 88
86/* Internal dispatch mode bits. */ 89/* Internal dispatch mode bits. */
87#define DISPMODE_JIT 0x01 /* JIT compiler on. */ 90#define DISPMODE_CALL 0x01 /* Override call dispatch. */
88#define DISPMODE_REC 0x02 /* Recording active. */ 91#define DISPMODE_RET 0x02 /* Override return dispatch. */
89#define DISPMODE_INS 0x04 /* Override instruction dispatch. */ 92#define DISPMODE_INS 0x04 /* Override instruction dispatch. */
90#define DISPMODE_CALL 0x08 /* Override call dispatch. */ 93#define DISPMODE_JIT 0x10 /* JIT compiler on. */
91#define DISPMODE_RET 0x10 /* Override return dispatch. */ 94#define DISPMODE_REC 0x20 /* Recording active. */
95#define DISPMODE_PROF 0x40 /* Profiling active. */
92 96
93/* Update dispatch table depending on various flags. */ 97/* Update dispatch table depending on various flags. */
94void lj_dispatch_update(global_State *g) 98void lj_dispatch_update(global_State *g)
@@ -100,6 +104,9 @@ void lj_dispatch_update(global_State *g)
100 mode |= G2J(g)->state != LJ_TRACE_IDLE ? 104 mode |= G2J(g)->state != LJ_TRACE_IDLE ?
101 (DISPMODE_REC|DISPMODE_INS|DISPMODE_CALL) : 0; 105 (DISPMODE_REC|DISPMODE_INS|DISPMODE_CALL) : 0;
102#endif 106#endif
107#if LJ_HASPROFILE
108 mode |= (g->hookmask & HOOK_PROFILE) ? (DISPMODE_PROF|DISPMODE_INS) : 0;
109#endif
103 mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0; 110 mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0;
104 mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0; 111 mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0;
105 mode |= (g->hookmask & LUA_MASKRET) ? DISPMODE_RET : 0; 112 mode |= (g->hookmask & LUA_MASKRET) ? DISPMODE_RET : 0;
@@ -128,9 +135,9 @@ void lj_dispatch_update(global_State *g)
128 disp[GG_LEN_DDISP+BC_LOOP] = f_loop; 135 disp[GG_LEN_DDISP+BC_LOOP] = f_loop;
129 136
130 /* Set dynamic instruction dispatch. */ 137 /* Set dynamic instruction dispatch. */
131 if ((oldmode ^ mode) & (DISPMODE_REC|DISPMODE_INS)) { 138 if ((oldmode ^ mode) & (DISPMODE_PROF|DISPMODE_REC|DISPMODE_INS)) {
132 /* Need to update the whole table. */ 139 /* Need to update the whole table. */
133 if (!(mode & (DISPMODE_REC|DISPMODE_INS))) { /* No ins dispatch? */ 140 if (!(mode & DISPMODE_INS)) { /* No ins dispatch? */
134 /* Copy static dispatch table to dynamic dispatch table. */ 141 /* Copy static dispatch table to dynamic dispatch table. */
135 memcpy(&disp[0], &disp[GG_LEN_DDISP], GG_LEN_SDISP*sizeof(ASMFunction)); 142 memcpy(&disp[0], &disp[GG_LEN_DDISP], GG_LEN_SDISP*sizeof(ASMFunction));
136 /* Overwrite with dynamic return dispatch. */ 143 /* Overwrite with dynamic return dispatch. */
@@ -142,12 +149,13 @@ void lj_dispatch_update(global_State *g)
142 } 149 }
143 } else { 150 } else {
144 /* The recording dispatch also checks for hooks. */ 151 /* The recording dispatch also checks for hooks. */
145 ASMFunction f = (mode & DISPMODE_REC) ? lj_vm_record : lj_vm_inshook; 152 ASMFunction f = (mode & DISPMODE_PROF) ? lj_vm_profhook :
153 (mode & DISPMODE_REC) ? lj_vm_record : lj_vm_inshook;
146 uint32_t i; 154 uint32_t i;
147 for (i = 0; i < GG_LEN_SDISP; i++) 155 for (i = 0; i < GG_LEN_SDISP; i++)
148 disp[i] = f; 156 disp[i] = f;
149 } 157 }
150 } else if (!(mode & (DISPMODE_REC|DISPMODE_INS))) { 158 } else if (!(mode & DISPMODE_INS)) {
151 /* Otherwise set dynamic counting ins. */ 159 /* Otherwise set dynamic counting ins. */
152 disp[BC_FORL] = f_forl; 160 disp[BC_FORL] = f_forl;
153 disp[BC_ITERL] = f_iterl; 161 disp[BC_ITERL] = f_iterl;
@@ -495,3 +503,34 @@ out:
495 return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */ 503 return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */
496} 504}
497 505
506#if LJ_HASPROFILE
507/* Profile dispatch. */
508void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc)
509{
510 ERRNO_SAVE
511 global_State *g = G(L);
512 uint8_t mask = g->hookmask;
513 g->hookmask = (mask & ~HOOK_PROFILE);
514 lj_dispatch_update(g);
515 if (!(mask & HOOK_VMEVENT)) {
516 GCfunc *fn = curr_func(L);
517 GCproto *pt = funcproto(fn);
518 void *cf = cframe_raw(L->cframe);
519 const BCIns *oldpc = cframe_pc(cf);
520 uint8_t oldh = hook_save(g);
521 BCReg slots;
522 hook_vmevent(g);
523 setcframe_pc(cf, pc);
524 slots = cur_topslot(pt, pc, cframe_multres_n(cf));
525 L->top = L->base + slots; /* Fix top. */
526 lj_profile_interpreter(L);
527 setgcref(g->cur_L, obj2gco(L));
528 setcframe_pc(cf, oldpc);
529 hook_restore(g, oldh);
530 lj_trace_abort(g);
531 setvmstate(g, INTERP);
532 }
533 ERRNO_RESTORE
534}
535#endif
536
diff --git a/src/lj_dispatch.h b/src/lj_dispatch.h
index 326297cd..811a0ae4 100644
--- a/src/lj_dispatch.h
+++ b/src/lj_dispatch.h
@@ -29,7 +29,7 @@
29 _(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \ 29 _(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \
30 _(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \ 30 _(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \
31 _(pow) _(fmod) _(ldexp) \ 31 _(pow) _(fmod) _(ldexp) \
32 _(lj_dispatch_call) _(lj_dispatch_ins) _(lj_err_throw) \ 32 _(lj_dispatch_call) _(lj_dispatch_ins) _(lj_dispatch_profile) _(lj_err_throw)\
33 _(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \ 33 _(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \
34 _(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \ 34 _(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \
35 _(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \ 35 _(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \
@@ -110,7 +110,9 @@ LJ_FUNC void lj_dispatch_update(global_State *g);
110/* Instruction dispatch callback for hooks or when recording. */ 110/* Instruction dispatch callback for hooks or when recording. */
111LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc); 111LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc);
112LJ_FUNCA ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns*pc); 112LJ_FUNCA ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns*pc);
113LJ_FUNCA void LJ_FASTCALL lj_dispatch_return(lua_State *L, const BCIns *pc); 113#if LJ_HASPROFILE
114LJ_FUNCA void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc);
115#endif
114 116
115#if LJ_HASFFI && !defined(_BUILDVM_H) 117#if LJ_HASFFI && !defined(_BUILDVM_H)
116/* Save/restore errno and GetLastError() around hooks, exits and recording. */ 118/* Save/restore errno and GetLastError() around hooks, exits and recording. */
diff --git a/src/lj_obj.h b/src/lj_obj.h
index 846c290f..b1bbf1c9 100644
--- a/src/lj_obj.h
+++ b/src/lj_obj.h
@@ -554,6 +554,7 @@ typedef struct global_State {
554#define HOOK_ACTIVE_SHIFT 4 554#define HOOK_ACTIVE_SHIFT 4
555#define HOOK_VMEVENT 0x20 555#define HOOK_VMEVENT 0x20
556#define HOOK_GC 0x40 556#define HOOK_GC 0x40
557#define HOOK_PROFILE 0x80
557#define hook_active(g) ((g)->hookmask & HOOK_ACTIVE) 558#define hook_active(g) ((g)->hookmask & HOOK_ACTIVE)
558#define hook_enter(g) ((g)->hookmask |= HOOK_ACTIVE) 559#define hook_enter(g) ((g)->hookmask |= HOOK_ACTIVE)
559#define hook_entergc(g) ((g)->hookmask |= (HOOK_ACTIVE|HOOK_GC)) 560#define hook_entergc(g) ((g)->hookmask |= (HOOK_ACTIVE|HOOK_GC))
diff --git a/src/lj_profile.c b/src/lj_profile.c
new file mode 100644
index 00000000..0baad06c
--- /dev/null
+++ b/src/lj_profile.c
@@ -0,0 +1,274 @@
1/*
2** Low-overhead profiling.
3** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lj_profile_c
7#define LUA_CORE
8
9#include "lj_obj.h"
10
11#if LJ_HASPROFILE
12
13#include "lj_buf.h"
14#include "lj_frame.h"
15#include "lj_debug.h"
16#include "lj_dispatch.h"
17#include "lj_profile.h"
18
19#include "luajit.h"
20
21#if LJ_PROFILE_SIGPROF
22
23#include <sys/time.h>
24#include <signal.h>
25
26#elif LJ_PROFILE_PTHREAD
27
28#include <pthread.h>
29
30#elif LJ_PROFILE_WTHREAD
31
32#define WIN32_LEAN_AND_MEAN
33#include <windows.h>
34typedef unsigned int (WINAPI *WMM_TPFUNC)(unsigned int);
35
36#endif
37
38/* Profiler state. */
39typedef struct ProfileState {
40 global_State *g; /* VM state that started the profiler. */
41 luaJIT_profile_callback cb; /* Profiler callback. */
42 void *data; /* Profiler callback data. */
43 SBuf sb; /* String buffer for stack dumps. */
44 int interval; /* Sample interval in milliseconds. */
45 int samples; /* Number of samples for next callback. */
46 int vmstate; /* VM state when profile timer triggered. */
47#if LJ_PROFILE_SIGPROF
48 struct sigaction oldsa; /* Previous SIGPROF state. */
49#elif LJ_PROFILE_PTHREAD
50 pthread_t thread; /* Timer thread. */
51 int abort; /* Abort timer thread. */
52#elif LJ_PROFILE_WTHREAD
53 HINSTANCE wmm; /* WinMM library handle. */
54 WMM_TPFUNC wmm_tbp; /* WinMM timeBeginPeriod function. */
55 WMM_TPFUNC wmm_tep; /* WinMM timeEndPeriod function. */
56 HANDLE thread; /* Timer thread. */
57 int abort; /* Abort timer thread. */
58#endif
59} ProfileState;
60
61/* Sadly, we have to use a static profiler state.
62**
63** The SIGPROF variant needs a static pointer to the global state, anyway.
64** And it would be hard to extend for multiple threads. You can still use
65** multiple VMs in multiple threads, but only profile one at a time.
66*/
67static ProfileState profile_state;
68
69/* Default sample interval in milliseconds. */
70#define LJ_PROFILE_INTERVAL_DEFAULT 10
71
72/* -- Profile callbacks --------------------------------------------------- */
73
74/* Callback from profile hook (HOOK_PROFILE already cleared). */
75void LJ_FASTCALL lj_profile_interpreter(lua_State *L)
76{
77 ProfileState *ps = &profile_state;
78 int samples = ps->samples;
79 ps->samples = 0;
80 ps->cb(ps->data, L, samples, ps->vmstate); /* Invoke user callback. */
81}
82
83/* Trigger profile hook. Asynchronous call from OS-specific profile timer. */
84static void profile_trigger(ProfileState *ps)
85{
86 global_State *g = ps->g;
87 uint8_t mask;
88 ps->samples++; /* Always increment number of samples. */
89 mask = g->hookmask;
90 if (!(mask & HOOK_PROFILE)) { /* Set profile hook, unless already set. */
91 int st = g->vmstate;
92 ps->vmstate = st >= 0 ? 'N' :
93 st == ~LJ_VMST_INTERP ? 'I' :
94 st == ~LJ_VMST_C ? 'C' :
95 st == ~LJ_VMST_GC ? 'G' : 'J';
96 g->hookmask = (mask | HOOK_PROFILE);
97 lj_dispatch_update(g);
98 }
99}
100
101/* -- OS-specific profile timer handling ---------------------------------- */
102
103#if LJ_PROFILE_SIGPROF
104
105/* SIGPROF handler. */
106static void profile_signal(int sig)
107{
108 UNUSED(sig);
109 profile_trigger(&profile_state);
110}
111
112/* Start profiling timer. */
113static void profile_timer_start(ProfileState *ps)
114{
115 int interval = ps->interval;
116 struct itimerval tm;
117 struct sigaction sa;
118 tm.it_value.tv_sec = tm.it_interval.tv_sec = interval / 1000;
119 tm.it_value.tv_usec = tm.it_interval.tv_usec = (interval % 1000) * 1000;
120 setitimer(ITIMER_PROF, &tm, NULL);
121 sa.sa_flags = SA_RESTART;
122 sa.sa_handler = profile_signal;
123 sigemptyset(&sa.sa_mask);
124 sigaction(SIGPROF, &sa, &ps->oldsa);
125}
126
127/* Stop profiling timer. */
128static void profile_timer_stop(ProfileState *ps)
129{
130 struct itimerval tm;
131 tm.it_value.tv_sec = tm.it_interval.tv_sec = 0;
132 tm.it_value.tv_usec = tm.it_interval.tv_usec = 0;
133 setitimer(ITIMER_PROF, &tm, NULL);
134 sigaction(SIGPROF, &ps->oldsa, NULL);
135}
136
137#elif LJ_PROFILE_PTHREAD
138
139/* POSIX timer thread. */
140static void *profile_thread(ProfileState *ps)
141{
142 int interval = ps->interval;
143 struct timespec ts;
144 ts.tv_sec = interval / 1000;
145 ts.tv_nsec = (interval % 1000) * 1000000;
146 while (1) {
147 nanosleep(&ts, NULL);
148 if (ps->abort) break;
149 profile_trigger(ps);
150 }
151 return NULL;
152}
153
154/* Start profiling timer thread. */
155static void profile_timer_start(ProfileState *ps)
156{
157 ps->abort = 0;
158 pthread_create(&ps->thread, NULL, (void *(*)(void *))profile_thread, ps);
159}
160
161/* Stop profiling timer thread. */
162static void profile_timer_stop(ProfileState *ps)
163{
164 ps->abort = 1;
165 pthread_join(ps->thread, NULL);
166}
167
168#elif LJ_PROFILE_WTHREAD
169
170/* Windows timer thread. */
171static DWORD WINAPI profile_thread(void *psx)
172{
173 ProfileState *ps = (ProfileState *)psx;
174 int interval = ps->interval;
175 ps->wmm_tbp(1);
176 while (1) {
177 Sleep(interval);
178 if (ps->abort) break;
179 profile_trigger(ps);
180 }
181 ps->wmm_tep(1);
182 return 0;
183}
184
185/* Start profiling timer thread. */
186static void profile_timer_start(ProfileState *ps)
187{
188 if (!ps->wmm) { /* Load WinMM library on-demand. */
189 ps->wmm = LoadLibraryA("winmm.dll");
190 if (ps->wmm) {
191 ps->wmm_tbp = (WMM_TPFUNC)GetProcAddress(ps->wmm, "timeBeginPeriod");
192 ps->wmm_tep = (WMM_TPFUNC)GetProcAddress(ps->wmm, "timeEndPeriod");
193 if (!ps->wmm_tbp || !ps->wmm_tep) {
194 ps->wmm = NULL;
195 return;
196 }
197 }
198 }
199 ps->abort = 0;
200 ps->thread = CreateThread(NULL, 0, profile_thread, ps, 0, NULL);
201}
202
203/* Stop profiling timer thread. */
204static void profile_timer_stop(ProfileState *ps)
205{
206 ps->abort = 1;
207 WaitForSingleObject(ps->thread, INFINITE);
208}
209
210#endif
211
212/* -- Public profiling API ------------------------------------------------ */
213
214/* Start profiling. */
215LUA_API void luaJIT_profile_start(lua_State *L, const char *mode,
216 luaJIT_profile_callback cb, void *data)
217{
218 ProfileState *ps = &profile_state;
219 int interval = LJ_PROFILE_INTERVAL_DEFAULT;
220 while (*mode) {
221 switch (*mode++) {
222 case 'i':
223 interval = 0;
224 while (*mode >= '0' && *mode <= '9')
225 interval = interval * 10 + (*mode++ - '0');
226 if (interval <= 0) interval = 1;
227 break;
228 default: /* Ignore unknown mode chars. */
229 break;
230 }
231 }
232 if (ps->g) {
233 luaJIT_profile_stop(L);
234 if (ps->g) return; /* Profiler in use by another VM. */
235 }
236 ps->g = G(L);
237 ps->interval = interval;
238 ps->cb = cb;
239 ps->data = data;
240 ps->samples = 0;
241 lj_buf_init(L, &ps->sb);
242 profile_timer_start(ps);
243}
244
245/* Stop profiling. */
246LUA_API void luaJIT_profile_stop(lua_State *L)
247{
248 ProfileState *ps = &profile_state;
249 global_State *g = ps->g;
250 if (G(L) == g) { /* Only stop profiler if started by this VM. */
251 profile_timer_stop(ps);
252 g->hookmask &= ~HOOK_PROFILE;
253 lj_dispatch_update(g);
254 lj_buf_free(g, &ps->sb);
255 setmref(ps->sb.b, NULL);
256 setmref(ps->sb.e, NULL);
257 ps->g = NULL;
258 }
259}
260
261/* Return a compact stack dump. */
262LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
263 int depth, size_t *len)
264{
265 ProfileState *ps = &profile_state;
266 SBuf *sb = &ps->sb;
267 setsbufL(sb, L);
268 lj_buf_reset(sb);
269 lj_debug_dumpstack(L, sb, fmt, depth);
270 *len = (size_t)sbuflen(sb);
271 return sbufB(sb);
272}
273
274#endif
diff --git a/src/lj_profile.h b/src/lj_profile.h
new file mode 100644
index 00000000..ad26f2b6
--- /dev/null
+++ b/src/lj_profile.h
@@ -0,0 +1,17 @@
1/*
2** Low-overhead profiling.
3** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#ifndef _LJ_PROFILE_H
7#define _LJ_PROFILE_H
8
9#include "lj_obj.h"
10
11#if LJ_HASPROFILE
12
13LJ_FUNC void LJ_FASTCALL lj_profile_interpreter(lua_State *L);
14
15#endif
16
17#endif
diff --git a/src/lj_state.c b/src/lj_state.c
index f11467fe..8fd11b2f 100644
--- a/src/lj_state.c
+++ b/src/lj_state.c
@@ -27,6 +27,7 @@
27#include "lj_vm.h" 27#include "lj_vm.h"
28#include "lj_lex.h" 28#include "lj_lex.h"
29#include "lj_alloc.h" 29#include "lj_alloc.h"
30#include "luajit.h"
30 31
31/* -- Stack handling ------------------------------------------------------ */ 32/* -- Stack handling ------------------------------------------------------ */
32 33
@@ -237,8 +238,11 @@ LUA_API void lua_close(lua_State *L)
237{ 238{
238 global_State *g = G(L); 239 global_State *g = G(L);
239 int i; 240 int i;
240 setgcrefnull(g->cur_L);
241 L = mainthread(g); /* Only the main thread can be closed. */ 241 L = mainthread(g); /* Only the main thread can be closed. */
242#if LJ_HASPROFILE
243 luaJIT_profile_stop(L);
244#endif
245 setgcrefnull(g->cur_L);
242 lj_func_closeuv(L, tvref(L->stack)); 246 lj_func_closeuv(L, tvref(L->stack));
243 lj_gc_separateudata(g, 1); /* Separate udata which have GC metamethods. */ 247 lj_gc_separateudata(g, 1); /* Separate udata which have GC metamethods. */
244#if LJ_HASJIT 248#if LJ_HASJIT
diff --git a/src/lj_vm.h b/src/lj_vm.h
index 948d63c2..5893d0b2 100644
--- a/src/lj_vm.h
+++ b/src/lj_vm.h
@@ -43,6 +43,7 @@ LJ_ASMF void lj_vm_record(void);
43LJ_ASMF void lj_vm_inshook(void); 43LJ_ASMF void lj_vm_inshook(void);
44LJ_ASMF void lj_vm_rethook(void); 44LJ_ASMF void lj_vm_rethook(void);
45LJ_ASMF void lj_vm_callhook(void); 45LJ_ASMF void lj_vm_callhook(void);
46LJ_ASMF void lj_vm_profhook(void);
46 47
47/* Trace exit handling. */ 48/* Trace exit handling. */
48LJ_ASMF void lj_vm_exit_handler(void); 49LJ_ASMF void lj_vm_exit_handler(void);
diff --git a/src/ljamalg.c b/src/ljamalg.c
index 7198a09f..29fed380 100644
--- a/src/ljamalg.c
+++ b/src/ljamalg.c
@@ -47,6 +47,7 @@
47#include "lj_strscan.c" 47#include "lj_strscan.c"
48#include "lj_strfmt.c" 48#include "lj_strfmt.c"
49#include "lj_api.c" 49#include "lj_api.c"
50#include "lj_profile.c"
50#include "lj_lex.c" 51#include "lj_lex.c"
51#include "lj_parse.c" 52#include "lj_parse.c"
52#include "lj_bcread.c" 53#include "lj_bcread.c"
diff --git a/src/luajit.h b/src/luajit.h
index a4c939bf..80530d95 100644
--- a/src/luajit.h
+++ b/src/luajit.h
@@ -64,6 +64,15 @@ enum {
64/* Control the JIT engine. */ 64/* Control the JIT engine. */
65LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode); 65LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);
66 66
67/* Low-overhead profiling API. */
68typedef void (*luaJIT_profile_callback)(void *data, lua_State *L,
69 int samples, int vmstate);
70LUA_API void luaJIT_profile_start(lua_State *L, const char *mode,
71 luaJIT_profile_callback cb, void *data);
72LUA_API void luaJIT_profile_stop(lua_State *L);
73LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
74 int depth, size_t *len);
75
67/* Enforce (dynamic) linker error for version mismatches. Call from main. */ 76/* Enforce (dynamic) linker error for version mismatches. Call from main. */
68LUA_API void LUAJIT_VERSION_SYM(void); 77LUA_API void LUAJIT_VERSION_SYM(void);
69 78
diff --git a/src/vm_arm.dasc b/src/vm_arm.dasc
index dd39052c..0bd929fd 100644
--- a/src/vm_arm.dasc
+++ b/src/vm_arm.dasc
@@ -2082,6 +2082,18 @@ static void build_subroutines(BuildCtx *ctx)
2082 | ldr INS, [PC, #-4] 2082 | ldr INS, [PC, #-4]
2083 | bx CRET1 2083 | bx CRET1
2084 | 2084 |
2085 |->vm_profhook: // Dispatch target for profiler hook.
2086#if LJ_HASPROFILE
2087 | mov CARG1, L
2088 | str BASE, L->base
2089 | mov CARG2, PC
2090 | bl extern lj_dispatch_profile // (lua_State *L, const BCIns *pc)
2091 | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
2092 | ldr BASE, L->base
2093 | sub PC, PC, #4
2094 | b ->cont_nop
2095#endif
2096 |
2085 |//----------------------------------------------------------------------- 2097 |//-----------------------------------------------------------------------
2086 |//-- Trace exit handler ------------------------------------------------- 2098 |//-- Trace exit handler -------------------------------------------------
2087 |//----------------------------------------------------------------------- 2099 |//-----------------------------------------------------------------------
diff --git a/src/vm_mips.dasc b/src/vm_mips.dasc
index 39d1521d..e7d01dc4 100644
--- a/src/vm_mips.dasc
+++ b/src/vm_mips.dasc
@@ -2011,6 +2011,20 @@ static void build_subroutines(BuildCtx *ctx)
2011 | jr CRET1 2011 | jr CRET1
2012 |. lw INS, -4(PC) 2012 |. lw INS, -4(PC)
2013 | 2013 |
2014 |->vm_profhook: // Dispatch target for profiler hook.
2015#if LJ_HASPROFILE
2016 | load_got lj_dispatch_profile
2017 | sw MULTRES, SAVE_MULTRES
2018 | move CARG2, PC
2019 | sw BASE, L->base
2020 | call_intern lj_dispatch_profile // (lua_State *L, const BCIns *pc)
2021 |. move CARG1, L
2022 | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
2023 | addiu PC, PC, -4
2024 | b ->cont_nop
2025 |. lw BASE, L->base
2026#endif
2027 |
2014 |//----------------------------------------------------------------------- 2028 |//-----------------------------------------------------------------------
2015 |//-- Trace exit handler ------------------------------------------------- 2029 |//-- Trace exit handler -------------------------------------------------
2016 |//----------------------------------------------------------------------- 2030 |//-----------------------------------------------------------------------
diff --git a/src/vm_ppc.dasc b/src/vm_ppc.dasc
index d9186c44..293c5c6f 100644
--- a/src/vm_ppc.dasc
+++ b/src/vm_ppc.dasc
@@ -2505,6 +2505,19 @@ static void build_subroutines(BuildCtx *ctx)
2505 | mtctr CRET1 2505 | mtctr CRET1
2506 | bctr 2506 | bctr
2507 | 2507 |
2508 |->vm_profhook: // Dispatch target for profiler hook.
2509#if LJ_HASPROFILE
2510 | mr CARG1, L
2511 | stw MULTRES, SAVE_MULTRES
2512 | mr CARG2, PC
2513 | stp BASE, L->base
2514 | bl extern lj_dispatch_profile // (lua_State *L, const BCIns *pc)
2515 | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
2516 | lp BASE, L->base
2517 | subi PC, PC, 4
2518 | b ->cont_nop
2519#endif
2520 |
2508 |//----------------------------------------------------------------------- 2521 |//-----------------------------------------------------------------------
2509 |//-- Trace exit handler ------------------------------------------------- 2522 |//-- Trace exit handler -------------------------------------------------
2510 |//----------------------------------------------------------------------- 2523 |//-----------------------------------------------------------------------
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc
index 7fe891b1..eaa99740 100644
--- a/src/vm_x86.dasc
+++ b/src/vm_x86.dasc
@@ -2588,7 +2588,7 @@ static void build_subroutines(BuildCtx *ctx)
2588 | mov FCARG2, PC // Caveat: FCARG2 == BASE 2588 | mov FCARG2, PC // Caveat: FCARG2 == BASE
2589 | mov FCARG1, L:RB 2589 | mov FCARG1, L:RB
2590 | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC. 2590 | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC.
2591 | call extern lj_dispatch_ins@8 // (lua_State *L, BCIns *pc) 2591 | call extern lj_dispatch_ins@8 // (lua_State *L, const BCIns *pc)
2592 |3: 2592 |3:
2593 | mov BASE, L:RB->base 2593 | mov BASE, L:RB->base
2594 |4: 2594 |4:
@@ -2659,6 +2659,19 @@ static void build_subroutines(BuildCtx *ctx)
2659 | add NARGS:RD, 1 2659 | add NARGS:RD, 1
2660 | jmp RBa 2660 | jmp RBa
2661 | 2661 |
2662 |->vm_profhook: // Dispatch target for profiler hook.
2663#if LJ_HASPROFILE
2664 | mov L:RB, SAVE_L
2665 | mov L:RB->base, BASE
2666 | mov FCARG2, PC // Caveat: FCARG2 == BASE
2667 | mov FCARG1, L:RB
2668 | call extern lj_dispatch_profile@8 // (lua_State *L, const BCIns *pc)
2669 | mov BASE, L:RB->base
2670 | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
2671 | sub PC, 4
2672 | jmp ->cont_nop
2673#endif
2674 |
2662 |//----------------------------------------------------------------------- 2675 |//-----------------------------------------------------------------------
2663 |//-- Trace exit handler ------------------------------------------------- 2676 |//-- Trace exit handler -------------------------------------------------
2664 |//----------------------------------------------------------------------- 2677 |//-----------------------------------------------------------------------