Skip to content

Commit e34829c

Browse files
committed
userdata支持__pairs
1 parent d26cc04 commit e34829c

File tree

4 files changed

+226
-1
lines changed

4 files changed

+226
-1
lines changed

extension/script/backend/worker/variables.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,30 @@ local function extandUserdata(varRef)
933933
}
934934
end
935935
end
936+
937+
local members = {}
938+
local loct = rdebug.userdata_pairs(u)
939+
if loct then
940+
for i = 1, #loct, 3 do
941+
local key, value, valueref = loct[i], loct[i + 1], loct[i + 2]
942+
local key_type = rdebug.type(key)
943+
if varCanExtand(key_type, key) then
944+
members[#members + 1] = varCreateTableKV(key, value, "variables")
945+
else
946+
varCreate {
947+
vars = members,
948+
varRef = varRef,
949+
name = varGetName(key),
950+
value = value,
951+
evaluateName = evaluateTabelKey(evaluateName, key),
952+
calcValue = function() return valueref end,
953+
}
954+
end
955+
end
956+
table.sort(members, function(a, b) return a.name < b.name end)
957+
table.move(members, 1, #members, #vars + 1)
958+
end
959+
936960
return vars
937961
end
938962

src/luadebug/rdebug_visitor.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,69 @@ namespace luadebug::visitor {
269269
return 0;
270270
}
271271

272+
template <bool getref = true>
273+
static int visitor_userdata_pairs(luadbg_State* L, lua_State* hL, protected_area& area) {
274+
area.check_client_stack(4);
275+
if (!copy_from_dbg(L, hL, area, 1, LUADBG_TUSERDATA)) {
276+
return 0;
277+
}
278+
if (lua_getmetatable(hL, -1) == 0) {
279+
lua_pop(hL, 1);
280+
return 0;
281+
}
282+
lua_getfield(hL, -1, "__pairs");
283+
if (LUA_TFUNCTION == lua_type(hL, -1)) {
284+
lua_pop(hL, 3);
285+
return 0;
286+
}
287+
lua_remove(hL, -2);
288+
lua_insert(hL, -2);
289+
if (!debug_pcall(hL, 1, 3, 0)) {
290+
lua_pop(hL, 1);
291+
return 0;
292+
}
293+
luadbg_newtable(L);
294+
luadbg_Integer n = 0;
295+
unsigned int index = 0;
296+
for (;;) {
297+
// next, t, k
298+
lua_pushvalue(hL, -3);
299+
lua_pushvalue(hL, -3);
300+
lua_pushvalue(hL, -3);
301+
lua_remove(hL, -4);
302+
// next, t, next, t, k
303+
if (!debug_pcall(hL, 2, 2, 0)) {
304+
lua_pop(hL, 3);
305+
return 0;
306+
}
307+
// next, t, k, v
308+
if (lua_isnoneornil(hL, -2)) {
309+
lua_pop(hL, 4);
310+
return 1;
311+
}
312+
if (copy_to_dbg(hL, L) == LUA_TNONE) {
313+
refvalue::create(L, 1, refvalue::USERDATA_KEY { index });
314+
}
315+
luadbg_rawseti(L, -2, ++n);
316+
lua_pop(hL, 1);
317+
318+
if (getref) {
319+
refvalue::create(L, 1, refvalue::USERDATA_VAL { index });
320+
if (copy_to_dbg(hL, L) == LUA_TNONE) {
321+
luadbg_pushvalue(L, -1);
322+
}
323+
luadbg_rawseti(L, -3, ++n);
324+
} else {
325+
if (copy_to_dbg(hL, L) == LUA_TNONE) {
326+
refvalue::create(L, 1, refvalue::USERDATA_VAL { index });
327+
}
328+
}
329+
++index;
330+
luadbg_rawseti(L, -2, ++n);
331+
}
332+
return 1;
333+
}
334+
272335
template <bool getref = true>
273336
static int visitor_tablearray(luadbg_State* L, lua_State* hL, protected_area& area) {
274337
unsigned int i = area.optinteger<unsigned int>(L, 2, 0);
@@ -1059,6 +1122,8 @@ namespace luadebug::visitor {
10591122
{ "getuservaluev", protected_call<visitor_getuservalue<false>> },
10601123
{ "field", protected_call<visitor_field> },
10611124
{ "fieldv", protected_call<visitor_field<false>> },
1125+
{ "userdata_pairs", protected_call<visitor_userdata_pairs> },
1126+
{ "userdata_pairsv", protected_call<visitor_userdata_pairs<false>> },
10621127
{ "tablearray", protected_call<visitor_tablearray> },
10631128
{ "tablearrayv", protected_call<visitor_tablearray<false>> },
10641129
{ "tablehash", protected_call<visitor_tablehash> },

src/luadebug/util/refvalue.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,31 @@
88
#include "compat/table.h"
99
#include "rdebug_lua.h"
1010

11+
#ifdef LUAJIT_VERSION
12+
# include <lj_cdata.h>
13+
# include <lj_debug.h>
14+
#else
15+
# include <lstate.h>
16+
#endif
17+
1118
namespace luadebug::refvalue {
19+
static int debug_pcall(lua_State* hL, int nargs, int nresults, int errfunc) {
20+
#ifdef LUAJIT_VERSION
21+
global_State* g = G(hL);
22+
bool needClean = !hook_active(g);
23+
hook_enter(g);
24+
int ok = lua_pcall(hL, nargs, nresults, errfunc);
25+
if (needClean)
26+
hook_leave(g);
27+
#else
28+
lu_byte oldah = hL->allowhook;
29+
hL->allowhook = 0;
30+
int ok = lua_pcall(hL, nargs, nresults, errfunc);
31+
hL->allowhook = oldah;
32+
#endif
33+
return ok;
34+
}
35+
1236
template <typename T>
1337
int eval(T&, lua_State*, value*);
1438

@@ -204,6 +228,106 @@ namespace luadebug::refvalue {
204228
return lua_type(hL, -1);
205229
}
206230

231+
template <>
232+
int eval<USERDATA_KEY>(USERDATA_KEY& v, lua_State* hL, value* parent) {
233+
int t = eval(parent, hL);
234+
if (t == LUA_TNONE)
235+
return LUA_TNONE;
236+
if (t != LUA_TUSERDATA) {
237+
lua_pop(hL, 1);
238+
return LUA_TNONE;
239+
}
240+
if (lua_getmetatable(hL, -1) == 0) {
241+
lua_pop(hL, 1);
242+
return LUA_TNONE;
243+
}
244+
lua_getfield(hL, -1, "__pairs");
245+
if (LUA_TFUNCTION == lua_type(hL, -1)) {
246+
lua_pop(hL, 3);
247+
return LUA_TNONE;
248+
}
249+
lua_remove(hL, -2);
250+
lua_insert(hL, -2);
251+
if (!debug_pcall(hL, 1, 3, 0)) {
252+
lua_pop(hL, 1);
253+
return LUA_TNONE;
254+
}
255+
for (auto i = 0;; ++i) {
256+
// next, t, k
257+
lua_pushvalue(hL, -3);
258+
lua_pushvalue(hL, -3);
259+
lua_pushvalue(hL, -3);
260+
lua_remove(hL, -4);
261+
// next, t, next, t, k
262+
if (!debug_pcall(hL, 2, 2, 0)) {
263+
lua_pop(hL, 3);
264+
return LUA_TNONE;
265+
}
266+
// next, t, k, v
267+
if (lua_isnoneornil(hL, -2)) {
268+
lua_pop(hL, 4);
269+
return LUA_TNONE;
270+
}
271+
if (i == v.index) {
272+
lua_pop(hL, 1);
273+
lua_remove(hL, -2);
274+
lua_remove(hL, -2);
275+
return lua_type(hL, -1);
276+
}
277+
lua_pop(hL, 1);
278+
}
279+
}
280+
281+
template <>
282+
int eval<USERDATA_VAL>(USERDATA_VAL& v, lua_State* hL, value* parent) {
283+
int t = eval(parent, hL);
284+
if (t == LUA_TNONE)
285+
return LUA_TNONE;
286+
if (t != LUA_TUSERDATA) {
287+
lua_pop(hL, 1);
288+
return LUA_TNONE;
289+
}
290+
if (lua_getmetatable(hL, -1) == 0) {
291+
lua_pop(hL, 1);
292+
return LUA_TNONE;
293+
}
294+
lua_getfield(hL, -1, "__pairs");
295+
if (LUA_TFUNCTION == lua_type(hL, -1)) {
296+
lua_pop(hL, 3);
297+
return LUA_TNONE;
298+
}
299+
lua_remove(hL, -2);
300+
lua_insert(hL, -2);
301+
if (!debug_pcall(hL, 1, 3, 0)) {
302+
lua_pop(hL, 1);
303+
return LUA_TNONE;
304+
}
305+
for (auto i = 0;; ++i) {
306+
// next, t, k
307+
lua_pushvalue(hL, -3);
308+
lua_pushvalue(hL, -3);
309+
lua_pushvalue(hL, -3);
310+
lua_remove(hL, -4);
311+
// next, t, next, t, k
312+
if (!debug_pcall(hL, 2, 2, 0)) {
313+
lua_pop(hL, 3);
314+
return LUA_TNONE;
315+
}
316+
// next, t, k, v
317+
if (lua_isnoneornil(hL, -2)) {
318+
lua_pop(hL, 4);
319+
return LUA_TNONE;
320+
}
321+
if (i == v.index) {
322+
lua_remove(hL, -2);
323+
lua_remove(hL, -2);
324+
lua_remove(hL, -2);
325+
return lua_type(hL, -1);
326+
}
327+
lua_pop(hL, 1);
328+
}
329+
}
330+
207331
int eval(value* v, lua_State* hL) {
208332
return visit([hL, v](auto&& arg) { return eval(arg, hL, v + 1); }, *v);
209333
}

src/luadebug/util/refvalue.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ namespace luadebug::refvalue {
4747
struct TABLE_HASH_VAL {
4848
unsigned int index;
4949
};
50+
struct USERDATA_KEY {
51+
unsigned int index;
52+
};
53+
struct USERDATA_VAL {
54+
unsigned int index;
55+
};
5056
using value = variant<
5157
FRAME_LOCAL,
5258
FRAME_FUNC,
@@ -58,7 +64,9 @@ namespace luadebug::refvalue {
5864
USERVALUE,
5965
TABLE_ARRAY,
6066
TABLE_HASH_KEY,
61-
TABLE_HASH_VAL>;
67+
TABLE_HASH_VAL,
68+
USERDATA_KEY,
69+
USERDATA_VAL>;
6270
static_assert(std::is_trivially_copyable_v<value>);
6371

6472
template <typename T>
@@ -90,6 +98,10 @@ namespace luadebug::refvalue {
9098
struct allow_as_child<TABLE_HASH_KEY> : public std::true_type {};
9199
template <>
92100
struct allow_as_child<TABLE_HASH_VAL> : public std::true_type {};
101+
template <>
102+
struct allow_as_child<USERDATA_KEY> : public std::true_type {};
103+
template <>
104+
struct allow_as_child<USERDATA_VAL> : public std::true_type {};
93105

94106
int eval(value* v, lua_State* hL);
95107
bool assign(value* v, lua_State* hL);

0 commit comments

Comments
 (0)