Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/luadebug/hookmgr.lua
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,11 @@ end
function hookmgr.coroutine_from(co)
end

---
---@param enable boolean
---启用luajit的jit支持
---
function hookmgr.enable_jit(enable)
end

return hookmgr
17 changes: 14 additions & 3 deletions extension/script/backend/worker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -659,16 +659,25 @@ function event.step(line)
end
end

function event.newproto(proto, level)
if not debuggeeReady() then return end
rdebug.getinfo(level, "S", info)
local function newprotoimpl(proto, info)
local src = source.create(info.source)
if not source.valid(src) then
return false
end
return breakpoint.newproto(proto, src, info.linedefined.."-"..info.lastlinedefined)
end

function event.newproto(proto, level)
if not debuggeeReady() then return end
rdebug.getinfo(level, "S", info)
return newprotoimpl(proto, info)
end

function event.newprotoimpl(proto, info)
if not debuggeeReady() then return end
return newprotoimpl(proto, info)
end

function event.update()
debuggeeReady()
workerThreadUpdate()
Expand Down Expand Up @@ -881,3 +890,5 @@ end)
sendToMaster 'initWorker' {}

hookmgr.update_open(true)

return event
18 changes: 18 additions & 0 deletions extension/script/backend/worker/eval.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,22 @@ generate("ffi_reflect", function ()
end
end)

generate("vmevent", function ()
if not luaver.isjit then
return
end
local handler = assert(rdebug.load(readfile "backend.worker.eval.vmevent"))
local ok, fn = rdebug.eval(handler)
if not ok then
return
end
if rdebug.type(fn) ~= "function" then
return function ()
end
end
return function (...)
return rdebug.eval(fn, ...)
end
end)

return m
56 changes: 56 additions & 0 deletions extension/script/backend/worker/eval/vmevent.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
local jit = require("jit")
if not jit.status() then
return "LuaJIT jit is not enabled"
end
if not pcall(require, 'jit.profile') then
--需要profile来update防止正在运行的代码全部被jit了而不无法update
return "LuaJIT profile is not enabled"
end
local active = false
local record_count = 0
local record_updeta_count = 1024

---@module "script.debugger"
local luadebugger = debug.getregistry()["lua-debug"]

local function update_trace()
luadebugger:event("update")
end
local function update_record()
record_count = record_count + 1
if record_count < record_updeta_count then
return
end
luadebugger:event("update")
record_count = 0
end
local function update_texit()
luadebugger:event("update")
end

local function update_bc(pt)
luadebugger:event("create_proto", pt)
end

local function on()
jit.attach(update_bc, "bc")
jit.attach(update_trace, "trace")
jit.attach(update_record, "record")
jit.attach(update_texit, "texit")
active = true
end
local function off()
jit.attach(update_texit)
jit.attach(update_record)
jit.attach(update_trace)
jit.attach(update_bc)
active = false
end

return function (enable)
if enable and not active then
on()
elseif active then
off()
end
end
62 changes: 62 additions & 0 deletions extension/script/backend/worker/luajit.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
local ev = require 'backend.event'
local rdebug = require 'luadebug.visitor'
local luaver = require 'backend.worker.luaver'
local hookmgr = require 'luadebug.hookmgr'

local enable_jit = false
local no_vmevent = false

local function set_jitmode(on)
on = on and "on" or "off"
local code = ([[
if jit and jit.%s then
jit.%s()
end
]]):format(on, on)
local thunk = rdebug.load(code)
if thunk then
rdebug.eval(thunk)
end
end

local function attach_vmevent()
local eval = require 'backend.worker.eval'
return eval.vmevent(true)
end

local function detach_vmevent()
local eval = require 'backend.worker.eval'
eval.vmevent(false)
end

ev.on('initializing', function (config)
if not luaver.isjit then
return
end
enable_jit = no_vmevent or not config.disable_jit
if not enable_jit then
set_jitmode(false)
return
end
if not attach_vmevent() then
no_vmevent = true
return
end
local worker = require 'backend.worker'
worker.autoUpdate(false)
hookmgr.enable_jit(true)
end)

local function terminated()
if not luaver.isjit then
return
end
if not enable_jit then
set_jitmode(true)
return
end
detach_vmevent()
hookmgr.enable_jit(false)
end

ev.on('terminated', terminated)
1 change: 0 additions & 1 deletion extension/script/debugger.lua
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ local function detectLuaDebugPath(cfg)
elseif _VERSION == "Lua 5.1" then
if (tostring(assert):match('builtin') ~= nil) then
rt = rt.."/luajit"
jit.off()
else
rt = rt.."/lua51"
end
Expand Down
12 changes: 12 additions & 0 deletions src/luadebug/compat/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ const void* lua_tocfunction_pointer(lua_State* L, int idx);
#ifdef LUAJIT_VERSION
union TValue;
struct GCproto;
union GCobj;
using CallInfo = TValue;
using Proto = GCproto;
using GCobject = GCobj;
#else
struct CallInfo;
struct Proto;
Expand All @@ -26,6 +28,16 @@ CallInfo* lua_debug2ci(lua_State* L, const lua_Debug* ar);

#ifdef LUAJIT_VERSION
int lua_isluafunc(lua_State* L, lua_Debug* ar);
using lua_foreach_gcobj_cb = void (*)(lua_State* L, void* ud, GCobject* o);
void lua_foreach_gcobj(lua_State* L, lua_foreach_gcobj_cb cb, void* ud);
Proto* lua_toproto(GCobject* o);
bool luajit_set_jitmode(lua_State* L, GCproto* pt, bool enable);
struct ProtoInfo {
const char* source;
int linedefined;
int lastlinedefined;
};
ProtoInfo lua_getprotoinfo(lua_State* L, Proto* pt);
#endif

int lua_stacklevel(lua_State* L);
Expand Down
10 changes: 10 additions & 0 deletions src/luadebug/compat/jit/fun.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <compat/internal.h>
#include <lj_obj.h>
ProtoInfo lua_getprotoinfo(lua_State* L, Proto* pt) {
GCstr* name = proto_chunkname(pt);
ProtoInfo info;
info.source = strdata(name);
info.linedefined = pt->firstline;
info.lastlinedefined = (pt->firstline || !pt->numline) ? pt->firstline + pt->numline : 0;
return info;
}
18 changes: 18 additions & 0 deletions src/luadebug/compat/jit/gc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <compat/internal.h>
#include <lj_obj.h>

void lua_foreach_gcobj(lua_State* L, lua_foreach_gcobj_cb cb, void* ud) {
auto g = G(L);
auto p = gcref(g->gc.root);
while (p != NULL) {
cb(L, ud, p);
p = gcref(p->gch.nextgc);
}
}

Proto* lua_toproto(GCobject* o) {
if (o->gch.gct == ~LJ_TPROTO) {
return gco2pt(o);
}
return nullptr;
}
128 changes: 128 additions & 0 deletions src/luadebug/compat/jit/trace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include <lj_dispatch.h>
#include <lj_jit.h>
#include <lj_obj.h>

#include <lua.hpp>

#if LJ_HASJIT
/* Unpatch the bytecode modified by a root trace. */
static void trace_unpatch(jit_State* J, GCtrace* T) {
BCOp op = bc_op(T->startins);
BCIns* pc = mref(T->startpc, BCIns);
UNUSED(J);
if (op == BC_JMP)
return; /* No need to unpatch branches in parent traces (yet). */
switch (bc_op(*pc)) {
case BC_JFORL:
lj_assertJ(traceref(J, bc_d(*pc)) == T, "JFORL references other trace");
*pc = T->startins;
pc += bc_j(T->startins);
lj_assertJ(bc_op(*pc) == BC_JFORI, "FORL does not point to JFORI");
setbc_op(pc, BC_FORI);
break;
case BC_JITERL:
case BC_JLOOP:
lj_assertJ(op == BC_ITERL || op == BC_ITERN || op == BC_LOOP || bc_isret(op), "bad original bytecode %d", op);
*pc = T->startins;
break;
case BC_JMP:
lj_assertJ(op == BC_ITERL, "bad original bytecode %d", op);
pc += bc_j(*pc) + 2;
if (bc_op(*pc) == BC_JITERL) {
lj_assertJ(traceref(J, bc_d(*pc)) == T, "JITERL references other trace");
*pc = T->startins;
}
break;
case BC_JFUNCF:
lj_assertJ(op == BC_FUNCF, "bad original bytecode %d", op);
*pc = T->startins;
break;
default: /* Already unpatched. */
break;
}
}
static void trace_flushroot(jit_State* J, GCtrace* T) {
GCproto* pt = &gcref(T->startpt)->pt;
lj_assertJ(T->root == 0, "not a root trace");
lj_assertJ(pt != NULL, "trace has no prototype");
/* First unpatch any modified bytecode. */
trace_unpatch(J, T);
/* Unlink root trace from chain anchored in prototype. */
if (pt->trace == T->traceno) { /* Trace is first in chain. Easy. */
pt->trace = T->nextroot;
}
else if (pt->trace) { /* Otherwise search in chain of root traces. */
GCtrace* T2 = traceref(J, pt->trace);
if (T2) {
for (; T2->nextroot; T2 = traceref(J, T2->nextroot))
if (T2->nextroot == T->traceno) {
T2->nextroot = T->nextroot; /* Unlink from chain. */
break;
}
}
}
}
void lj_trace_flushproto(global_State* g, GCproto* pt) {
while (pt->trace != 0)
trace_flushroot(G2J(g), traceref(G2J(g), pt->trace));
}

/* Re-enable compiling a prototype by unpatching any modified bytecode. */
void lj_trace_reenableproto(GCproto* pt) {
if ((pt->flags & PROTO_ILOOP)) {
BCIns* bc = proto_bc(pt);
BCPos i, sizebc = pt->sizebc;
pt->flags &= ~PROTO_ILOOP;
if (bc_op(bc[0]) == BC_IFUNCF)
setbc_op(&bc[0], BC_FUNCF);
for (i = 1; i < sizebc; i++) {
BCOp op = bc_op(bc[i]);
if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP)
setbc_op(&bc[i], (int)op + (int)BC_LOOP - (int)BC_ILOOP);
}
}
}

/* Set JIT mode for a single prototype. */
static void setptmode(global_State* g, GCproto* pt, int mode) {
if ((mode & LUAJIT_MODE_ON)) { /* (Re-)enable JIT compilation. */
pt->flags &= ~PROTO_NOJIT;
lj_trace_reenableproto(pt); /* Unpatch all ILOOP etc. bytecodes. */
}
else { /* Flush and/or disable JIT compilation. */
if (!(mode & LUAJIT_MODE_FLUSH))
pt->flags |= PROTO_NOJIT;
lj_trace_flushproto(g, pt); /* Flush all traces of prototype. */
}
}

/* Recursively set the JIT mode for all children of a prototype. */
static void setptmode_all(global_State* g, GCproto* pt, int mode) {
ptrdiff_t i;
if (!(pt->flags & PROTO_CHILD)) return;
for (i = -(ptrdiff_t)pt->sizekgc; i < 0; i++) {
GCobj* o = proto_kgc(pt, i);
if (o->gch.gct == ~LJ_TPROTO) {
setptmode(g, gco2pt(o), mode);
setptmode_all(g, gco2pt(o), mode);
}
}
}
#endif

bool luajit_set_jitmode(lua_State* L, GCproto* pt, bool enable) {
#ifdef LJ_HASJIT
bool nojit = pt->flags & PROTO_NOJIT;
if (enable) {
if (nojit)
setptmode_all(G(L), pt, LUAJIT_MODE_ON);
}
else {
if (!nojit)
setptmode_all(G(L), pt, LUAJIT_MODE_OFF);
}
return nojit;
#else
return false;
#endif
}
Loading
Loading