Commit Diff


commit - 59847721d2ed97e401084b394e7195ccc6e6daff
commit + 381c9df727a745c64f902c8046620364e65283fa
blob - 538ebac0fd28dd7a635be7ae647c33057f8ccfef
blob + dd6d928faf4b101ea2f7a0f892380cd55bca9887
--- CHANGELOG.md
+++ CHANGELOG.md
@@ -16,3 +16,4 @@ and this project adheres to [Semantic Versioning](http
 - Examples with tests.
 - Documentation with usecases, API etc.
 - Add patches for PUC Rio Lua with enhanced edge and data tracking.
+- Add patches for LuaJIT with enhanced edge and data tracking.
blob - 7def16ba44921fd3d4ce22a5b42f799c2a196b9c
blob + 74db86c64ce60cb72d16bbc40e8d544624b2f4d5
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -6,16 +6,21 @@ project(luzer
 )
 
 option(USE_LUA "Use PUC Rio Lua" OFF)
+option(USE_LUAJIT "Use LuaJIT" OFF)
 option(LUA_PATCHED "Patch Lua runtime" OFF)
 
 set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
 set(CMAKE_INCLUDE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_INCLUDE_PATH})
 
 include(BuildLua)
+include(BuildLuaJIT)
 
 if (USE_LUA AND LUA_VERSION)
   build_lua(${LUA_VERSION})
   set(LUA_RUNTIME "PUC Rio Lua")
+elseif (USE_LUAJIT AND LUA_VERSION)
+  build_luajit(${LUA_VERSION})
+  set(LUA_RUNTIME "LuaJIT")
 else ()
   include(FindLua)
   find_package(Lua ${LUA_VERSION} REQUIRED)
blob - /dev/null
blob + 8c78ab6a22bb969aeb4d51eef3be2736f8924a61 (mode 644)
--- /dev/null
+++ cmake/BuildLuaJIT.cmake
@@ -0,0 +1,36 @@
+macro(build_luajit LJ_VERSION)
+    set(LJ_SOURCE_DIR ${PROJECT_BINARY_DIR}/luajit-${LJ_VERSION}/source)
+    set(LJ_BINARY_DIR ${PROJECT_BINARY_DIR}/luajit-${LJ_VERSION}/work)
+    set(LJ_PATCH_PATH ${PROJECT_SOURCE_DIR}/patches/luajit-v2.1.0.patch)
+
+    include(ExternalProject)
+
+    set(CFLAGS "-fPIC")
+
+    ExternalProject_Add(patched-luajit
+        GIT_REPOSITORY https://github.com/LuaJIT/LuaJIT
+        GIT_TAG ${LJ_VERSION}
+        GIT_PROGRESS TRUE
+        SOURCE_DIR ${LJ_SOURCE_DIR}
+        BINARY_DIR ${LJ_BINARY_DIR}/luajit-${LJ_VERSION}
+        DOWNLOAD_DIR ${LJ_BINARY_DIR}
+        TMP_DIR ${LJ_BINARY_DIR}/tmp
+        STAMP_DIR ${LJ_BINARY_DIR}/stamp
+        DOWNLOAD_EXTRACT_TIMESTAMP TRUE
+
+        PATCH_COMMAND patch -p1 -i ${LJ_PATCH_PATH}
+        CONFIGURE_COMMAND ""
+        BUILD_COMMAND cd <SOURCE_DIR> && $(MAKE) CC=${CMAKE_C_COMPILER} CFLAGS=${CFLAGS} -j
+        INSTALL_COMMAND ""
+        UPDATE_DISCONNECTED ON
+    )
+
+    set(LUA_FOUND TRUE)
+    set(LUA_VERSION_STRING ${LJ_VERSION})
+    set(LUA_INCLUDE_DIR ${LJ_SOURCE_DIR}/src/)
+    set(LUA_LIBRARIES ${LJ_SOURCE_DIR}/src/libluajit.a)
+    set(LUA_EXECUTABLE ${LJ_SOURCE_DIR}/src/luajit)
+
+    unset(LJ_SOURCE_DIR)
+    unset(LJ_BINARY_DIR)
+endmacro(build_luajit)
blob - /dev/null
blob + 4cff11d92e982518cf39777047da1ba2dd9348da (mode 644)
--- /dev/null
+++ patches/luajit-v2.1.0.patch
@@ -0,0 +1,146 @@
+diff --git a/src/lib_debug.c b/src/lib_debug.c
+index 3af7a353..10cef540 100644
+--- a/src/lib_debug.c
++++ b/src/lib_debug.c
+@@ -112,7 +112,7 @@ LJLIB_CF(debug_getinfo)
+   lj_Debug ar;
+   int arg, opt_f = 0, opt_L = 0;
+   lua_State *L1 = getthread(L, &arg);
+-  const char *options = luaL_optstring(L, arg+2, "flnSu");
++  const char *options = luaL_optstring(L, arg+2, "flnSuC");
+   if (lua_isnumber(L, arg+1)) {
+     if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), (lua_Debug *)&ar)) {
+       setnilV(L->top-1);
+@@ -148,6 +148,10 @@ LJLIB_CF(debug_getinfo)
+       settabss(L, "name", ar.name);
+       settabss(L, "namewhat", ar.namewhat);
+       break;
++    case 'C':
++      settabss(L, "rkb", ar.rkb);
++      settabss(L, "rkc", ar.rkc);
++      break;
+     case 'f': opt_f = 1; break;
+     case 'L': opt_L = 1; break;
+     default: break;
+@@ -288,7 +292,7 @@ LJLIB_CF(debug_setuservalue)
+ static void hookf(lua_State *L, lua_Debug *ar)
+ {
+   static const char *const hooknames[] =
+-    {"call", "return", "line", "count", "tail return"};
++    {"call", "return", "line", "count", "tail return", "edge", "data"};
+   (L->top++)->u64 = KEY_HOOK;
+   lua_rawget(L, LUA_REGISTRYINDEX);
+   if (lua_isfunction(L, -1)) {
+diff --git a/src/lj_debug.c b/src/lj_debug.c
+index ca893153..e3d1de67 100644
+--- a/src/lj_debug.c
++++ b/src/lj_debug.c
+@@ -498,6 +498,9 @@ int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
+       opt_f = 1;
+     } else if (*what == 'L') {
+       opt_L = 1;
++    } else if (*what == 'C') {
++      ar->rkb = "rkb";
++      ar->rkc = "rkc";
+     } else {
+       return 0;  /* Bad option. */
+     }
+diff --git a/src/lj_debug.h b/src/lj_debug.h
+index 28127ae9..ab121116 100644
+--- a/src/lj_debug.h
++++ b/src/lj_debug.h
+@@ -24,6 +24,8 @@ typedef struct lj_Debug {
+   /* Extended fields. Only valid if lj_debug_getinfo() is called with ext = 1.*/
+   int nparams;
+   int isvararg;
++  char *rkb;
++  char *rkc;
+ } lj_Debug;
+ 
+ LJ_FUNC cTValue *lj_debug_frame(lua_State *L, int level, int *size);
+diff --git a/src/lj_dispatch.c b/src/lj_dispatch.c
+index ded382aa..95f3c105 100644
+--- a/src/lj_dispatch.c
++++ b/src/lj_dispatch.c
+@@ -115,7 +115,7 @@ void lj_dispatch_update(global_State *g)
+ #if LJ_HASPROFILE
+   mode |= (g->hookmask & HOOK_PROFILE) ? (DISPMODE_PROF|DISPMODE_INS) : 0;
+ #endif
+-  mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0;
++  mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT|LUA_MASKEDGE|LUA_MASKDATA)) ? DISPMODE_INS : 0;
+   mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0;
+   mode |= (g->hookmask & LUA_MASKRET) ? DISPMODE_RET : 0;
+   if (oldmode != mode) {  /* Mode changed? */
+@@ -440,6 +440,15 @@ void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc)
+       L->top = L->base + slots;  /* Fix top again. */
+     }
+   }
++  if ((g->hookmask & LUA_MASKEDGE)) {
++    BCPos npc = proto_bcpos(pt, pc) - 1;
++    BCPos opc = proto_bcpos(pt, oldpc) - 1;
++    BCLine line = lj_debug_line(pt, npc);
++    if (pc <= oldpc || opc >= pt->sizebc || line != lj_debug_line(pt, opc)) {
++      callhook(L, LUA_HOOKEDGE, line);
++      L->top = L->base + slots;  /* Fix top again. */
++    }
++  }
+   if ((g->hookmask & LUA_MASKRET) && bc_isret(bc_op(pc[-1])))
+     callhook(L, LUA_HOOKRET, -1);
+   ERRNO_RESTORE
+diff --git a/src/lj_vm.h b/src/lj_vm.h
+index c66db004..1be9902c 100644
+--- a/src/lj_vm.h
++++ b/src/lj_vm.h
+@@ -51,6 +51,8 @@ LJ_ASMF void lj_vm_inshook(void);
+ LJ_ASMF void lj_vm_rethook(void);
+ LJ_ASMF void lj_vm_callhook(void);
+ LJ_ASMF void lj_vm_profhook(void);
++LJ_ASMF void lj_vm_edgehook(void);
++LJ_ASMF void lj_vm_datahook(void);
+ LJ_ASMF void lj_vm_IITERN(void);
+ 
+ /* Trace exit handling. */
+diff --git a/src/lua.h b/src/lua.h
+index 6d1634d1..f712d5a2 100644
+--- a/src/lua.h
++++ b/src/lua.h
+@@ -315,6 +315,8 @@ LUA_API void lua_setlevel	(lua_State *from, lua_State *to);
+ #define LUA_HOOKLINE	2
+ #define LUA_HOOKCOUNT	3
+ #define LUA_HOOKTAILRET 4
++#define LUA_HOOKEDGE    5
++#define LUA_HOOKDATA    6
+ 
+ 
+ /*
+@@ -324,6 +326,8 @@ LUA_API void lua_setlevel	(lua_State *from, lua_State *to);
+ #define LUA_MASKRET	(1 << LUA_HOOKRET)
+ #define LUA_MASKLINE	(1 << LUA_HOOKLINE)
+ #define LUA_MASKCOUNT	(1 << LUA_HOOKCOUNT)
++#define LUA_MASKEDGE	(1 << LUA_HOOKEDGE)
++#define LUA_MASKDATA	(1 << LUA_HOOKDATA)
+ 
+ typedef struct lua_Debug lua_Debug;  /* activation record */
+ 
+@@ -368,6 +372,8 @@ struct lua_Debug {
+   int linedefined;	/* (S) */
+   int lastlinedefined;	/* (S) */
+   char short_src[LUA_IDSIZE]; /* (S) */
++  char *rkb;	/* C */
++  char *rkc;	/* C */
+   /* private part */
+   int i_ci;  /* active function */
+ };
+diff --git a/src/vm_arm64.dasc b/src/vm_arm64.dasc
+index 36a036ae..24f75bfa 100644
+--- a/src/vm_arm64.dasc
++++ b/src/vm_arm64.dasc
+@@ -1787,7 +1787,7 @@ static void build_subroutines(BuildCtx *ctx)
+   |  ldrb TMP2w, GL->hookmask
+   |   ldr TMP3w, GL->hookcount
+   |  tbnz TMP2w, #HOOK_ACTIVE_SHIFT, <5	// Hook already active?
+-  |  tst TMP2w, #LUA_MASKLINE|LUA_MASKCOUNT
++  |  tst TMP2w, #LUA_MASKLINE|LUA_MASKCOUNT|LUA_MASKEDGE
+   |  beq <5
+   |   sub TMP3w, TMP3w, #1
+   |   str TMP3w, GL->hookcount