* [Tarantool-patches] [PATCH luajit] dbg: display fast function name along with ffid
@ 2026-09-09 13:07 Mikhail Elhimov via Tarantool-patches
2026-09-22 9:16 ` Sergey Kaplun via Tarantool-patches
0 siblings, 1 reply; 6+ messages in thread
From: Mikhail Elhimov via Tarantool-patches @ 2026-09-09 13:07 UTC (permalink / raw)
To: Sergey Kaplun, Sergey Bronnikov, Evgeniy Temirgaleev; +Cc: tarantool-patches
Part of tarantool/tarantool#4808
---
This patch is to be applied after the 'avoid hardcoded enums' patch.
Branch: https://github.com/tarantool/luajit/tree/elhimov/gh-4808-display-fast-function-name
Related issue: https://github.com/tarantool/tarantool/issues/4808
src/luajit_dbg.py | 17 +++++++++++------
.../debug-extension-tests.py | 2 +-
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
index 1ac1d275..262fdad1 100644
--- a/src/luajit_dbg.py
+++ b/src/luajit_dbg.py
@@ -1682,8 +1682,11 @@ def ir_kint64(ir):
# Dumpers.
+FF_NAMES = EnumBasedList('FastFunc', 'FF__MAX', cut_prefix, 'FF_')
+
# GCobj dumpers.
+
def dump_lj_gco_str(gcobj):
return 'string {body} @ {address}'.format(
body=strdata(gcobj),
@@ -1705,7 +1708,7 @@ def dump_lj_gco_proto(gcobj):
def dump_lj_gco_func(gcobj):
func = dbg.cast('struct GCfuncC *', gcobj)
- ffid = func['ffid']
+ ffid = int(func['ffid'])
if ffid == 0:
pt = funcproto(func)
@@ -1718,7 +1721,8 @@ def dump_lj_gco_func(gcobj):
elif ffid == 1:
return 'C function @ {}'.format(strx64(func['f']))
else:
- return 'fast function #{}'.format(int(ffid))
+ ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
+ return 'fast function #{}({})'.format(ffid, ffname)
def dump_lj_gco_trace(gcobj):
@@ -2068,7 +2072,7 @@ def dump_proto(proto):
def dump_func(func):
- ffid = func['ffid']
+ ffid = int(func['ffid'])
if ffid == 0:
pt = funcproto(func)
@@ -2076,7 +2080,8 @@ def dump_func(func):
elif ffid == 1:
return 'C function @ {}\n'.format(strx64(func['f']))
else:
- return 'fast function #{}\n'.format(int(ffid))
+ ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
+ return 'fast function #{}({})\n'.format(ffid, ffname)
# FFI dumpers.
@@ -2702,7 +2707,7 @@ the type and some info related to it.
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
<CFUNC>: C function <mcode address>
- <FFUNC>: fast function #<ffid>
+ <FFUNC>: fast function #<ffid>(<ffname>)
* LJ_TTRACE: trace <traceno> @ <gcr>
* LJ_TCDATA: cdata @ <gcr>
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
@@ -2921,7 +2926,7 @@ the type and some info related to it.
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
<CFUNC>: C function <mcode address>
- <FFUNC>: fast function #<ffid>
+ <FFUNC>: fast function #<ffid>(<ffname>)
* LJ_TTRACE: trace <traceno> @ <gcr>
* LJ_TCDATA: cdata @ <gcr>
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index 9989032b..40a27c3a 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -338,7 +338,7 @@ GCO_RX = (
r'thread @ ' + RX_ADDR + r'\n'
r'Lua function @ ' + RX_ADDR + r', [0-9]+ upvalues, .+:[0-9]+\n'
r'C function @ ' + RX_ADDR + r'\n'
- r'fast function #[0-9]+\n'
+ r'fast function #[0-9]+\(\w+\)\n'
r'cdata @ ' + RX_ADDR + r' \[\d+\] <int \*> 0x0\n'
r'table @ ' + RX_ADDR + r' \(asize: \d+, hmask: ' + RX_HASH + r'\)\n'
r'userdata @ ' + RX_ADDR + r'\n'
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [Tarantool-patches] [PATCH luajit] dbg: display fast function name along with ffid
2026-09-09 13:07 [Tarantool-patches] [PATCH luajit] dbg: display fast function name along with ffid Mikhail Elhimov via Tarantool-patches
@ 2026-09-22 9:16 ` Sergey Kaplun via Tarantool-patches
2026-09-23 22:55 ` Mikhail Elhimov via Tarantool-patches
2026-09-24 16:48 ` [Tarantool-patches] [PATCH luajit v2] " Mikhail Elhimov via Tarantool-patches
0 siblings, 2 replies; 6+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2026-09-22 9:16 UTC (permalink / raw)
To: Mikhail Elhimov; +Cc: tarantool-patches
Hi, Mikhail!
Thanks for the patch!
Generally, LGTM, with minor suggestions below.
On 09.09.26, Mikhail Elhimov wrote:
> Part of tarantool/tarantool#4808
> ---
> This patch is to be applied after the 'avoid hardcoded enums' patch.
>
> Branch: https://github.com/tarantool/luajit/tree/elhimov/gh-4808-display-fast-function-name
> Related issue: https://github.com/tarantool/tarantool/issues/4808
>
> src/luajit_dbg.py | 17 +++++++++++------
> .../debug-extension-tests.py | 2 +-
> 2 files changed, 12 insertions(+), 7 deletions(-)
>
> diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
> index 1ac1d275..262fdad1 100644
> --- a/src/luajit_dbg.py
> +++ b/src/luajit_dbg.py
> @@ -1682,8 +1682,11 @@ def ir_kint64(ir):
>
> # Dumpers.
>
> +FF_NAMES = EnumBasedList('FastFunc', 'FF__MAX', cut_prefix, 'FF_')
It would be nice to replace `_` in functions names to `.`.
Resulting: math_min -> math.min
Minor: I would rather placed it somewhere into the section:
| # LuaJIT macro implementations and structure access.
> +
> # GCobj dumpers.
>
> +
> def dump_lj_gco_str(gcobj):
> return 'string {body} @ {address}'.format(
> body=strdata(gcobj),
> @@ -1705,7 +1708,7 @@ def dump_lj_gco_proto(gcobj):
>
> def dump_lj_gco_func(gcobj):
> func = dbg.cast('struct GCfuncC *', gcobj)
> - ffid = func['ffid']
> + ffid = int(func['ffid'])
>
> if ffid == 0:
> pt = funcproto(func)
> @@ -1718,7 +1721,8 @@ def dump_lj_gco_func(gcobj):
> elif ffid == 1:
> return 'C function @ {}'.format(strx64(func['f']))
> else:
> - return 'fast function #{}'.format(int(ffid))
> + ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
> + return 'fast function #{}({})'.format(ffid, ffname)
I suggest the following format insted:
| 'fast function {} (#{})'.format(ffname, ffid)
Generally we needed ffid less then the function name.
>
>
> def dump_lj_gco_trace(gcobj):
> @@ -2068,7 +2072,7 @@ def dump_proto(proto):
>
>
> def dump_func(func):
> - ffid = func['ffid']
> + ffid = int(func['ffid'])
>
> if ffid == 0:
> pt = funcproto(func)
> @@ -2076,7 +2080,8 @@ def dump_func(func):
> elif ffid == 1:
> return 'C function @ {}\n'.format(strx64(func['f']))
> else:
> - return 'fast function #{}\n'.format(int(ffid))
> + ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
> + return 'fast function #{}({})\n'.format(ffid, ffname)
I suggest the following format insted:
| 'fast function {} (#{})\n'.format(ffname, ffid)
Generally we needed ffid less then the function name.
>
>
> # FFI dumpers.
> @@ -2702,7 +2707,7 @@ the type and some info related to it.
> * LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
> <LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
> <CFUNC>: C function <mcode address>
> - <FFUNC>: fast function #<ffid>
> + <FFUNC>: fast function #<ffid>(<ffname>)
I suggest the following format instead:
| <FFUNC>: fast function <ffname> (#<ffid>)
> * LJ_TTRACE: trace <traceno> @ <gcr>
> * LJ_TCDATA: cdata @ <gcr>
> * LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
> @@ -2921,7 +2926,7 @@ the type and some info related to it.
> * LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
> <LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
> <CFUNC>: C function <mcode address>
> - <FFUNC>: fast function #<ffid>
I suggest the following format instead:
| <FFUNC>: fast function <ffname> (#<ffid>)
> + <FFUNC>: fast function #<ffid>(<ffname>)
> * LJ_TTRACE: trace <traceno> @ <gcr>
> * LJ_TCDATA: cdata @ <gcr>
> * LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
> diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
> index 9989032b..40a27c3a 100644
> --- a/test/tarantool-debugger-tests/debug-extension-tests.py
> +++ b/test/tarantool-debugger-tests/debug-extension-tests.py
> @@ -338,7 +338,7 @@ GCO_RX = (
> r'thread @ ' + RX_ADDR + r'\n'
> r'Lua function @ ' + RX_ADDR + r', [0-9]+ upvalues, .+:[0-9]+\n'
> r'C function @ ' + RX_ADDR + r'\n'
> - r'fast function #[0-9]+\n'
> + r'fast function #[0-9]+\(\w+\)\n'
Lets check the specific name here. I suggest `math.min` to check the
_ -> . mapping.
> r'cdata @ ' + RX_ADDR + r' \[\d+\] <int \*> 0x0\n'
> r'table @ ' + RX_ADDR + r' \(asize: \d+, hmask: ' + RX_HASH + r'\)\n'
> r'userdata @ ' + RX_ADDR + r'\n'
> --
> 2.43.0
>
--
Best regards,
Sergey Kaplun
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [Tarantool-patches] [PATCH luajit] dbg: display fast function name along with ffid
2026-09-22 9:16 ` Sergey Kaplun via Tarantool-patches
@ 2026-09-23 22:55 ` Mikhail Elhimov via Tarantool-patches
2026-09-24 16:48 ` [Tarantool-patches] [PATCH luajit v2] " Mikhail Elhimov via Tarantool-patches
1 sibling, 0 replies; 6+ messages in thread
From: Mikhail Elhimov via Tarantool-patches @ 2026-09-23 22:55 UTC (permalink / raw)
To: Sergey Kaplun; +Cc: tarantool-patches
Hi, Sergey!
Thanks for the review! See my comments below
On 22.09.2026 12:16, Sergey Kaplun wrote:
> Hi, Mikhail!
> Thanks for the patch!
> Generally, LGTM, with minor suggestions below.
>
> On 09.09.26, Mikhail Elhimov wrote:
>> Part of tarantool/tarantool#4808
>> ---
>> This patch is to be applied after the 'avoid hardcoded enums' patch.
>>
>> Branch: https://github.com/tarantool/luajit/tree/elhimov/gh-4808-display-fast-function-name
>> Related issue: https://github.com/tarantool/tarantool/issues/4808
>>
>> src/luajit_dbg.py | 17 +++++++++++------
>> .../debug-extension-tests.py | 2 +-
>> 2 files changed, 12 insertions(+), 7 deletions(-)
>>
>> diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
>> index 1ac1d275..262fdad1 100644
>> --- a/src/luajit_dbg.py
>> +++ b/src/luajit_dbg.py
>> @@ -1682,8 +1682,11 @@ def ir_kint64(ir):
>>
>> # Dumpers.
>>
>> +FF_NAMES = EnumBasedList('FastFunc', 'FF__MAX', cut_prefix, 'FF_')
> It would be nice to replace `_` in functions names to `.`.
> Resulting: math_min -> math.min
Then what about these and similar ones (they have 3 underscores in a row):
ffi_meta___index
io_method___gc
?
May be replace only first underscore?
> Minor: I would rather placed it somewhere into the section:
> | # LuaJIT macro implementations and structure access.
Done
>> +
>> # GCobj dumpers.
>>
>> +
>> def dump_lj_gco_str(gcobj):
>> return 'string {body} @ {address}'.format(
>> body=strdata(gcobj),
>> @@ -1705,7 +1708,7 @@ def dump_lj_gco_proto(gcobj):
>>
>> def dump_lj_gco_func(gcobj):
>> func = dbg.cast('struct GCfuncC *', gcobj)
>> - ffid = func['ffid']
>> + ffid = int(func['ffid'])
>>
>> if ffid == 0:
>> pt = funcproto(func)
>> @@ -1718,7 +1721,8 @@ def dump_lj_gco_func(gcobj):
>> elif ffid == 1:
>> return 'C function @ {}'.format(strx64(func['f']))
>> else:
>> - return 'fast function #{}'.format(int(ffid))
>> + ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
>> + return 'fast function #{}({})'.format(ffid, ffname)
> I suggest the following format insted:
> | 'fast function {} (#{})'.format(ffname, ffid)
>
> Generally we needed ffid less then the function name.
Done
>>
>>
>> def dump_lj_gco_trace(gcobj):
>> @@ -2068,7 +2072,7 @@ def dump_proto(proto):
>>
>>
>> def dump_func(func):
>> - ffid = func['ffid']
>> + ffid = int(func['ffid'])
>>
>> if ffid == 0:
>> pt = funcproto(func)
>> @@ -2076,7 +2080,8 @@ def dump_func(func):
>> elif ffid == 1:
>> return 'C function @ {}\n'.format(strx64(func['f']))
>> else:
>> - return 'fast function #{}\n'.format(int(ffid))
>> + ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
>> + return 'fast function #{}({})\n'.format(ffid, ffname)
> I suggest the following format insted:
> | 'fast function {} (#{})\n'.format(ffname, ffid)
>
> Generally we needed ffid less then the function name.
Done
>>
>>
>> # FFI dumpers.
>> @@ -2702,7 +2707,7 @@ the type and some info related to it.
>> * LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
>> <LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
>> <CFUNC>: C function <mcode address>
>> - <FFUNC>: fast function #<ffid>
>> + <FFUNC>: fast function #<ffid>(<ffname>)
> I suggest the following format instead:
>
> | <FFUNC>: fast function <ffname> (#<ffid>)
Done
>> * LJ_TTRACE: trace <traceno> @ <gcr>
>> * LJ_TCDATA: cdata @ <gcr>
>> * LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
>> @@ -2921,7 +2926,7 @@ the type and some info related to it.
>> * LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
>> <LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
>> <CFUNC>: C function <mcode address>
>> - <FFUNC>: fast function #<ffid>
> I suggest the following format instead:
>
> | <FFUNC>: fast function <ffname> (#<ffid>)
Done
>> + <FFUNC>: fast function #<ffid>(<ffname>)
>> * LJ_TTRACE: trace <traceno> @ <gcr>
>> * LJ_TCDATA: cdata @ <gcr>
>> * LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
>> diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
>> index 9989032b..40a27c3a 100644
>> --- a/test/tarantool-debugger-tests/debug-extension-tests.py
>> +++ b/test/tarantool-debugger-tests/debug-extension-tests.py
>> @@ -338,7 +338,7 @@ GCO_RX = (
>> r'thread @ ' + RX_ADDR + r'\n'
>> r'Lua function @ ' + RX_ADDR + r', [0-9]+ upvalues, .+:[0-9]+\n'
>> r'C function @ ' + RX_ADDR + r'\n'
>> - r'fast function #[0-9]+\n'
>> + r'fast function #[0-9]+\(\w+\)\n'
> Lets check the specific name here. I suggest `math.min` to check the
> _ -> . mapping.
No problem, but first we need to agree on how to handle underscores (see
above comment about multiple undescores)
>
>> ing r'cdata @ ' + RX_ADDR + r' \[\d+\] <int \*> 0x0\n'
>> r'table @ ' + RX_ADDR + r' \(asize: \d+, hmask: ' + RX_HASH + r'\)\n'
>> r'userdata @ ' + RX_ADDR + r'\n'
>> --
>> 2.43.0
>>
--
Best regards,
Mikhail Elhimov
^ permalink raw reply [flat|nested] 6+ messages in thread* [Tarantool-patches] [PATCH luajit v2] dbg: display fast function name along with ffid
2026-09-22 9:16 ` Sergey Kaplun via Tarantool-patches
2026-09-23 22:55 ` Mikhail Elhimov via Tarantool-patches
@ 2026-09-24 16:48 ` Mikhail Elhimov via Tarantool-patches
2026-09-24 20:14 ` [Tarantool-patches] [PATCH luajit v3] " Mikhail Elhimov via Tarantool-patches
1 sibling, 1 reply; 6+ messages in thread
From: Mikhail Elhimov via Tarantool-patches @ 2026-09-24 16:48 UTC (permalink / raw)
To: Sergey Kaplun, Sergey Bronnikov, Evgeniy Temirgaleev; +Cc: tarantool-patches
Part of tarantool/tarantool#4808
---
Changes in v2:
- Format is changed to 'ffname (#ffid)'
- Replaced single '_' with '.' in ffname
- Adjusted tests to check mapping
This patch is to be applied after https://lists.tarantool.org/pipermail/tarantool-patches/2026-September/030791.html.
Branch: https://github.com/tarantool/luajit/tree/elhimov/gh-4808-display-fast-function-name
Related issue: https://github.com/tarantool/tarantool/issues/4808
src/luajit_dbg.py | 19 +++++++++++++------
.../debug-extension-tests.py | 6 ++++--
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
index 5cd23a88..a564801b 100644
--- a/src/luajit_dbg.py
+++ b/src/luajit_dbg.py
@@ -1121,6 +1121,11 @@ def frames(L):
# LuaJIT macro implementations and structure access.
+# Get FastFunc enum members and replace any single '_' with '.'.
+FF_NAMES = EnumBasedList('FastFunc', 'FF__MAX', lambda x:
+ re.sub('(?<!_)_(?!_)', '.', cut_prefix(x, 'FF_')))
+
+
def mref(typename, obj):
return dbg.cast(typename, obj['ptr64'] if LJ_GC64 else obj['ptr32'])
@@ -1716,7 +1721,7 @@ def dump_lj_gco_proto(gcobj):
def dump_lj_gco_func(gcobj):
func = dbg.cast('struct GCfuncC *', gcobj)
- ffid = func['ffid']
+ ffid = int(func['ffid'])
if ffid == 0:
pt = funcproto(func)
@@ -1729,7 +1734,8 @@ def dump_lj_gco_func(gcobj):
elif ffid == 1:
return 'C function @ {}'.format(strx64(func['f']))
else:
- return 'fast function #{}'.format(int(ffid))
+ ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
+ return 'fast function {} (#{})'.format(ffname, ffid)
def dump_lj_gco_trace(gcobj):
@@ -2079,7 +2085,7 @@ def dump_proto(proto):
def dump_func(func):
- ffid = func['ffid']
+ ffid = int(func['ffid'])
if ffid == 0:
pt = funcproto(func)
@@ -2087,7 +2093,8 @@ def dump_func(func):
elif ffid == 1:
return 'C function @ {}\n'.format(strx64(func['f']))
else:
- return 'fast function #{}\n'.format(int(ffid))
+ ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
+ return 'fast function {} (#{})\n'.format(ffname, ffid)
# FFI dumpers.
@@ -2713,7 +2720,7 @@ the type and some info related to it.
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
<CFUNC>: C function <mcode address>
- <FFUNC>: fast function #<ffid>
+ <FFUNC>: fast function <ffname> (#<ffid>)
* LJ_TTRACE: trace <traceno> @ <gcr>
* LJ_TCDATA: cdata @ <gcr>
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
@@ -2932,7 +2939,7 @@ the type and some info related to it.
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
<CFUNC>: C function <mcode address>
- <FFUNC>: fast function #<ffid>
+ <FFUNC>: fast function <ffname> (#<ffid>)
* LJ_TTRACE: trace <traceno> @ <gcr>
* LJ_TCDATA: cdata @ <gcr>
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index 5e369f00..86954909 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -326,7 +326,7 @@ GCO_ARGS = (
'coroutine.create(function() end),\n'
'function() end,\n'
'require,\n'
- 'print,\n'
+ 'math.min,\n'
'ffi.new("int*"),\n'
'{1},\n'
'newproxy(),\n'
@@ -338,7 +338,7 @@ GCO_RX = (
r'thread @ ' + RX_ADDR + r'\n'
r'Lua function @ ' + RX_ADDR + r', [0-9]+ upvalues, .+:[0-9]+\n'
r'C function @ ' + RX_ADDR + r'\n'
- r'fast function #[0-9]+\n'
+ r'fast function math.min (#[0-9]+)\n'
r'cdata @ ' + RX_ADDR + r' \[\d+\] <int \*> 0x0\n'
r'table @ ' + RX_ADDR + r' \(asize: \d+, hmask: ' + RX_HASH + r'\)\n'
r'userdata @ ' + RX_ADDR + r'\n'
@@ -367,6 +367,7 @@ class TestLJTV(TestCaseBase):
# Sorted in LJT order.
lua_script = (
'local ffi = require("ffi")\n'
+ 'local math = require("math")\n'
'print(\n'
' nil,\n'
' false,\n'
@@ -435,6 +436,7 @@ class TestLJGCo(TestCaseBase):
lua_script = (
'local ffi = require("ffi")\n'
+ 'local math = require("math")\n'
'print(\n' +
GCO_ARGS +
' 1\n' # Stub for the pattern.
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [Tarantool-patches] [PATCH luajit v3] dbg: display fast function name along with ffid
2026-09-24 16:48 ` [Tarantool-patches] [PATCH luajit v2] " Mikhail Elhimov via Tarantool-patches
@ 2026-09-24 20:14 ` Mikhail Elhimov via Tarantool-patches
0 siblings, 0 replies; 6+ messages in thread
From: Mikhail Elhimov via Tarantool-patches @ 2026-09-24 20:14 UTC (permalink / raw)
To: Sergey Kaplun, Sergey Bronnikov, Evgeniy Temirgaleev; +Cc: tarantool-patches
Part of tarantool/tarantool#4808
---
Changes in v3:
- Fixed fast function regexp in tests
Changes in v2:
- Format is changed to 'ffname (#ffid)'
- Replaced single '_' with '.' in ffname
- Adjusted tests to check mapping
This patch is to be applied after https://lists.tarantool.org/pipermail/tarantool-patches/2026-September/030791.html.
Branch: https://github.com/tarantool/luajit/tree/elhimov/gh-4808-display-fast-function-name
Related issue: https://github.com/tarantool/tarantool/issues/4808
src/luajit_dbg.py | 19 +++++++++++++------
.../debug-extension-tests.py | 6 ++++--
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
index 5cd23a88..a564801b 100644
--- a/src/luajit_dbg.py
+++ b/src/luajit_dbg.py
@@ -1121,6 +1121,11 @@ def frames(L):
# LuaJIT macro implementations and structure access.
+# Get FastFunc enum members and replace any single '_' with '.'.
+FF_NAMES = EnumBasedList('FastFunc', 'FF__MAX', lambda x:
+ re.sub('(?<!_)_(?!_)', '.', cut_prefix(x, 'FF_')))
+
+
def mref(typename, obj):
return dbg.cast(typename, obj['ptr64'] if LJ_GC64 else obj['ptr32'])
@@ -1716,7 +1721,7 @@ def dump_lj_gco_proto(gcobj):
def dump_lj_gco_func(gcobj):
func = dbg.cast('struct GCfuncC *', gcobj)
- ffid = func['ffid']
+ ffid = int(func['ffid'])
if ffid == 0:
pt = funcproto(func)
@@ -1729,7 +1734,8 @@ def dump_lj_gco_func(gcobj):
elif ffid == 1:
return 'C function @ {}'.format(strx64(func['f']))
else:
- return 'fast function #{}'.format(int(ffid))
+ ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
+ return 'fast function {} (#{})'.format(ffname, ffid)
def dump_lj_gco_trace(gcobj):
@@ -2079,7 +2085,7 @@ def dump_proto(proto):
def dump_func(func):
- ffid = func['ffid']
+ ffid = int(func['ffid'])
if ffid == 0:
pt = funcproto(func)
@@ -2087,7 +2093,8 @@ def dump_func(func):
elif ffid == 1:
return 'C function @ {}\n'.format(strx64(func['f']))
else:
- return 'fast function #{}\n'.format(int(ffid))
+ ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
+ return 'fast function {} (#{})\n'.format(ffname, ffid)
# FFI dumpers.
@@ -2713,7 +2720,7 @@ the type and some info related to it.
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
<CFUNC>: C function <mcode address>
- <FFUNC>: fast function #<ffid>
+ <FFUNC>: fast function <ffname> (#<ffid>)
* LJ_TTRACE: trace <traceno> @ <gcr>
* LJ_TCDATA: cdata @ <gcr>
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
@@ -2932,7 +2939,7 @@ the type and some info related to it.
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
<CFUNC>: C function <mcode address>
- <FFUNC>: fast function #<ffid>
+ <FFUNC>: fast function <ffname> (#<ffid>)
* LJ_TTRACE: trace <traceno> @ <gcr>
* LJ_TCDATA: cdata @ <gcr>
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index 5e369f00..fe5e34f5 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -326,7 +326,7 @@ GCO_ARGS = (
'coroutine.create(function() end),\n'
'function() end,\n'
'require,\n'
- 'print,\n'
+ 'math.min,\n'
'ffi.new("int*"),\n'
'{1},\n'
'newproxy(),\n'
@@ -338,7 +338,7 @@ GCO_RX = (
r'thread @ ' + RX_ADDR + r'\n'
r'Lua function @ ' + RX_ADDR + r', [0-9]+ upvalues, .+:[0-9]+\n'
r'C function @ ' + RX_ADDR + r'\n'
- r'fast function #[0-9]+\n'
+ r'fast function math.min \(#[0-9]+\)\n'
r'cdata @ ' + RX_ADDR + r' \[\d+\] <int \*> 0x0\n'
r'table @ ' + RX_ADDR + r' \(asize: \d+, hmask: ' + RX_HASH + r'\)\n'
r'userdata @ ' + RX_ADDR + r'\n'
@@ -367,6 +367,7 @@ class TestLJTV(TestCaseBase):
# Sorted in LJT order.
lua_script = (
'local ffi = require("ffi")\n'
+ 'local math = require("math")\n'
'print(\n'
' nil,\n'
' false,\n'
@@ -435,6 +436,7 @@ class TestLJGCo(TestCaseBase):
lua_script = (
'local ffi = require("ffi")\n'
+ 'local math = require("math")\n'
'print(\n' +
GCO_ARGS +
' 1\n' # Stub for the pattern.
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Tarantool-patches] [PATCH luajit v2] dbg: avoid hardcoded enums (get them from target)
@ 2026-09-23 22:27 Mikhail Elhimov via Tarantool-patches
2026-09-24 17:33 ` [Tarantool-patches] [PATCH luajit v3] dbg: display fast function name along with ffid Mikhail Elhimov via Tarantool-patches
0 siblings, 1 reply; 6+ messages in thread
From: Mikhail Elhimov via Tarantool-patches @ 2026-09-23 22:27 UTC (permalink / raw)
To: Sergey Kaplun, Sergey Bronnikov, Evgeniy Temirgaleev; +Cc: tarantool-patches
Besides reducing lines of code this way the extension becomes compatible
with various versions of LuaJIT because different versions might use
different sets of enum members (a newer version might introduce
additional BC/IR/etc.)
Prior to this patch, the string was used as a debugger-agnostic way to
specify type, but this way might not work in the case of an enum because
debugging information might be optimized out if no variable of such an
enum type is declared and its members are used only as predefined
constants. The type of enum is needed to be able to get human-readable
value (member name instead of number). The alternative way to get enum
type is to get it from the value, i.e. somehow obtain the value that is
of enum type and then use this type to convert the numbers to the member
names.
Creating the value of the given enum member is quite different in GDB
and LLDB, so separate method `create_enum_value` was introduced in
Debugger API. Also new method `cast_typeof` was introduced to perform
value-based cast, i.e. it casts to the same type as a reference value.
Also this patch fixes the mapping of FPMATHOP to a human-readable form,
because prior to this patch, IRFPMS contained the incorrect entry
'exp2'. IRFPMS is a human-readable form of enum IRFPMathOp, but there is
no 'exp2' enum member actually (see IRFPMDEF). It looks like it was
added by mistake initially (correspoding tests to check mapping of
FPMATHOP were added).
Other adjustments:
* [gdb] in 'eval' method dropped check of the value returned by
gdb.parse_and_eval() as it would fail also for expression like '0',
i.e. affects all the involved enums (looks like a kind of experimental
code that was left by mistake)
* [lldb] 'eval' adjusted to return object of the same type as 'cast'
method (this improves consistency)
* [gdb/lldb] renamed eval argument to reflect its meaning (it is
an expression rather than a command)
Resolves tarantool/tarantool#13094
Resolves tarantool/tarantool#13159
---
Changes in v2:
- Switched to the `cast_typeof` approach
- Added tests that checks FPMATHOP mapping as this patch fixes this problem as a side effect
- Typos correction
Branch: https://github.com/tarantool/luajit/tree/elhimov/gh-13094-dbg-use-enums-from-inferior
Related issues:
https://github.com/tarantool/tarantool/issues/13094
https://github.com/tarantool/tarantool/issues/13159
src/luajit_dbg.py | 632 ++++--------------
.../debug-extension-tests.py | 58 +-
2 files changed, 205 insertions(+), 485 deletions(-)
diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
index 80057a4e..5cd23a88 100644
--- a/src/luajit_dbg.py
+++ b/src/luajit_dbg.py
@@ -115,6 +115,13 @@ class Debugger(object):
'''Cast the value to the required C type.'''
pass
+ @abc.abstractmethod
+ def cast_typeof(self, ref_val, val):
+ '''Cast the value to the type of the given object
+ It is used mostly for casting when the string name of the type isn't
+ accessible (for example, anonymous enums).'''
+ pass
+
@abc.abstractmethod
def sizeof(self, typestr):
'''Return the size of the given type in bytes.'''
@@ -146,8 +153,8 @@ class Debugger(object):
pass
@abc.abstractmethod
- def eval(self, command):
- '''Parse and evaluate the given debugger command.'''
+ def eval(self, expr):
+ '''Parse and evaluate the given debugger expression.'''
pass
@abc.abstractmethod
@@ -187,6 +194,16 @@ class Debugger(object):
'''Register the command with the corresponding name.'''
pass
+ # Creating the value of the given enum member is quite
+ # different in GDB and LLDB, so this method is needed to hide
+ # the implementation details.
+ @abc.abstractmethod
+ def create_enum_value(self, enum_name, enum_member_name):
+ '''Return debugger-specific value object that represents
+ the given enum member.
+ '''
+ pass
+
@abc.abstractproperty
def LJBase(self):
'''Base command class.
@@ -214,6 +231,9 @@ class _GDBDebugger(Debugger):
def cast(self, typestr, val):
return gdb.Value(val).cast(self._dbgtype(typestr))
+ def cast_typeof(self, ref_val, val):
+ return gdb.Value(val).cast(ref_val.type)
+
def sizeof(self, typestr):
return self._dbgtype(typestr).sizeof
@@ -268,14 +288,11 @@ class _GDBDebugger(Debugger):
else:
return None
- def eval(self, command):
- if not command:
+ def eval(self, expr):
+ if not expr:
return None
- ret = gdb.parse_and_eval(command)
- if not ret:
- raise gdb.GdbError('table argument empty')
- return ret
+ return gdb.parse_and_eval(expr)
def detect_arch(self):
if hasattr(self, 'arch'):
@@ -340,6 +357,11 @@ class _GDBDebugger(Debugger):
def register_command(self, command, name):
command(name)
+ def create_enum_value(self, enum_name, enum_member_name):
+ val = self.eval(enum_member_name)
+ assert val.type.code == gdb.TYPE_CODE_ENUM
+ return val
+
class LJBase(gdb and gdb.Command or object):
def __init__(ljbase, name):
# XXX Fragile: Though the command initialization looks
@@ -378,6 +400,10 @@ class _LLDBDebugger(Debugger):
lldb.eBasicTypeInt128
]
+ def _lldb_tp_isenum(self, tp):
+ return tp.GetCanonicalType().GetTypeClass() == \
+ lldb.eTypeClassEnumeration
+
def _lldb_value_from_raw(self, raw_value, size, tp):
isfp = self._lldb_tp_isfp(tp)
if isfp:
@@ -491,8 +517,7 @@ class _LLDBDebugger(Debugger):
# Instead of default GetSummary.
if not lldbval.sbvalue.TypeIsPointerType():
tp = lldbval.sbvalue.GetType()
- is_float = self._lldb_tp_isfp(tp)
- if is_float:
+ if self._lldb_tp_isfp(tp) or self._lldb_tp_isenum(tp):
return lldbval.sbvalue.GetValue()
else:
return str(int(lldbval))
@@ -568,11 +593,10 @@ class _LLDBDebugger(Debugger):
self.dbgtype_cache[typestr] = dbgtype
return dbgtype
- def cast(self, typestr, val):
+ def _cast(self, tp, val):
if isinstance(val, lldb.value):
val = val.sbvalue
elif type(val) is int:
- tp = self._dbgtype(typestr)
return self._lldb_value_from_raw(val, tp.GetByteSize(), tp)
elif not isinstance(val, lldb.SBValue):
raise Exception(
@@ -582,7 +606,6 @@ class _LLDBDebugger(Debugger):
# XXX: Simply SBValue.Cast() works incorrectly since it
# may take the 8 bytes of memory instead of 4, before the
# cast. Construct the value on the fly.
- tp = self._dbgtype(typestr)
if self._lldb_tp_isfp(tp):
rawval = float(val.GetValue())
elif self._lldb_tp_issigned(tp):
@@ -591,6 +614,12 @@ class _LLDBDebugger(Debugger):
rawval = val.GetValueAsUnsigned()
return self._lldb_value_from_raw(rawval, val.GetByteSize(), tp)
+ def cast(self, typestr, val):
+ return self._cast(self._dbgtype(typestr), val)
+
+ def cast_typeof(self, ref_val, val):
+ return self._cast(ref_val.sbvalue.type, val)
+
def sizeof(self, typestr):
return self._dbgtype(typestr).GetByteSize()
@@ -670,15 +699,14 @@ class _LLDBDebugger(Debugger):
else:
return None
- def eval(self, command):
- if not command:
+ def eval(self, expr):
+ if not expr:
return None
process = self.target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
- ret = frame.EvaluateExpression(command)
- return ret
+ return lldb.value(frame.EvaluateExpression(expr))
def detect_arch(self):
if hasattr(self, 'arch'):
@@ -724,6 +752,47 @@ class _LLDBDebugger(Debugger):
)
)
+ def create_enum_value(self, enum_name, enum_member_name):
+ # In LLDB an enum member has to be specified in the form:
+ # <enum_name>::<enum_member_name>
+ val = self.eval(enum_name + "::" + enum_member_name)
+ # Be aware that SBValue.IsValid() is necessary, but not
+ # sufficient as it only indicates that the object does
+ # contain the relevant data (including potential error),
+ # so it is necessary to check additionally that no error
+ # has occurred while evaluating the expression.
+ if val.sbvalue.IsValid() and val.sbvalue.error.Success():
+ assert self._lldb_tp_isenum(val.sbvalue.GetType())
+ return val
+
+ # LLDB uses the enum name in the expression above but
+ # debugging information about the enum name might be
+ # optimized out if no variable of the given enum type is
+ # declared and its members are only used as the predefined
+ # constants (like in case of the enum IRFieldID).
+
+ # In this case the above method doesn't work so trying to
+ # discover the enum type by the given enum member.
+
+ def find_enum_type_member(enum_type, enum_member_name):
+ # SBTypeEnumMemberList supports members iteration and
+ # [] access (both by index and by member name) only
+ # starting from lldb-12 so this implementation is used
+ # to handle earlier versions.
+ members = enum_type.GetEnumMembers()
+ for i in range(members.GetSize()):
+ item = members.GetTypeEnumMemberAtIndex(i)
+ if item.name == enum_member_name:
+ return item
+ return None
+
+ for m in self.target.modules:
+ for et in m.GetTypes(lldb.eTypeClassEnumeration):
+ et_member = find_enum_type_member(et, enum_member_name)
+ if et_member is not None:
+ return self._cast(et, et_member.unsigned)
+ return None
+
class LJBase(object):
# Ignore given parameters by LLDB.
def __init__(ljbase, debugger, unused):
@@ -800,6 +869,45 @@ def strx64(val):
return re.sub('L?$', '', hex(int(tou64(val))))
+class EnumBasedList(object):
+ def __init__(self, enum_name, max_enum_member, map_func=None,
+ *map_func_extra_args):
+ self.__enum_name = enum_name
+ self.__max_enum_member = max_enum_member
+ self.__map_func = map_func
+ self.__map_func_extra_args = map_func_extra_args
+ # Lazy initialization (see __get_items) as the required
+ # information might be unavailable at this moment.
+ self.__items = None
+
+ def __iter__(self):
+ return iter(self.__get_items())
+
+ def __getitem__(self, key):
+ return self.__get_items()[key]
+
+ def __len__(self):
+ return len(self.__get_items())
+
+ def __get_items(self):
+ if self.__items is None:
+ max_enum_value = dbg.create_enum_value(
+ self.__enum_name, self.__max_enum_member
+ )
+ items = []
+ for i in range(max_enum_value):
+ item = str(dbg.cast_typeof(max_enum_value, dbg.eval(str(i))))
+ if self.__map_func:
+ item = self.__map_func(item, *self.__map_func_extra_args)
+ items.append(item)
+ self.__items = items
+ return self.__items
+
+
+def cut_prefix(s, prefix):
+ return s[len(prefix):] if s.startswith(prefix) else s
+
+
# Types and TValues.
@@ -877,10 +985,7 @@ def bc_d(ins):
return int(ins) >> 16
-BCMODE = [
- 'none', 'dst', 'base', 'var', 'rbase', 'uv',
- 'lit', 'lits', 'pri', 'num', 'str', 'tab', 'func', 'jump', 'cdata',
-]
+BCMODE = EnumBasedList('BCMode', 'BCM_max', cut_prefix, 'BCM')
lj_bc_mode_ = None
@@ -906,136 +1011,7 @@ def bcmode_cd(op):
return int((lj_bc_mode()[op] >> 7) & 15)
-# Unfortunately, there is no place in the VM except the generated
-# Lua table, where the bytecode names are stored. So duplicate
-# them here.
-BYTECODES = [
- # Comparison ops. ORDER OPR.
- 'ISLT',
- 'ISGE',
- 'ISLE',
- 'ISGT',
-
- 'ISEQV',
- 'ISNEV',
- 'ISEQS',
- 'ISNES',
- 'ISEQN',
- 'ISNEN',
- 'ISEQP',
- 'ISNEP',
-
- # Unary test and copy ops.
- 'ISTC',
- 'ISFC',
- 'IST',
- 'ISF',
- 'ISTYPE',
- 'ISNUM',
- 'MOV',
- 'NOT',
- 'UNM',
- 'LEN',
- 'ADDVN',
- 'SUBVN',
- 'MULVN',
- 'DIVVN',
- 'MODVN',
-
- # Binary ops. ORDER OPR.
- 'ADDNV',
- 'SUBNV',
- 'MULNV',
- 'DIVNV',
- 'MODNV',
-
- 'ADDVV',
- 'SUBVV',
- 'MULVV',
- 'DIVVV',
- 'MODVV',
-
- 'POW',
- 'CAT',
-
- # Constant ops.
- 'KSTR',
- 'KCDATA',
- 'KSHORT',
- 'KNUM',
- 'KPRI',
- 'KNIL',
-
- # Upvalue and function ops.
- 'UGET',
- 'USETV',
- 'USETS',
- 'USETN',
- 'USETP',
- 'UCLO',
- 'FNEW',
-
- # Table ops.
- 'TNEW',
- 'TDUP',
- 'GGET',
- 'GSET',
- 'TGETV',
- 'TGETS',
- 'TGETB',
- 'TGETR',
- 'TSETV',
- 'TSETS',
- 'TSETB',
- 'TSETM',
- 'TSETR',
-
- # Calls and vararg handling. T = tail call.
- 'CALLM',
- 'CALL',
- 'CALLMT',
- 'CALLT',
- 'ITERC',
- 'ITERN',
- 'VARG',
- 'ISNEXT',
-
- # Returns.
- 'RETM',
- 'RET',
- 'RET0',
- 'RET1',
-
- # Loops and branches. I/J = interp/JIT.
- # I/C/L = init/call/loop.
- 'FORI',
- 'JFORI',
-
- 'FORL',
- 'IFORL',
- 'JFORL',
-
- 'ITERL',
- 'IITERL',
- 'JITERL',
-
- 'LOOP',
- 'ILOOP',
- 'JLOOP',
-
- 'JMP',
-
- # Function headers. I/J = interp/JIT.
- # F/V/C = fixarg/vararg/C func.
- 'FUNCF',
- 'IFUNCF',
- 'JFUNCF',
- 'FUNCV',
- 'IFUNCV',
- 'JFUNCV',
- 'FUNCC',
- 'FUNCCW',
-]
+BYTECODES = EnumBasedList('BCOp', 'BC__MAX', cut_prefix, 'BC_')
def proto_bc(proto):
@@ -1190,42 +1166,16 @@ def J(g):
# Matched `MMDEF(_)`.
-MM_NAMES = [
- 'index',
- 'newindex',
- 'gc',
- 'mode',
- 'eq',
- 'len',
- 'lt',
- 'le',
- 'concat',
- 'call',
- 'add',
- 'sub',
- 'mul',
- 'div',
- 'mod',
- 'pow',
- 'unm',
- 'metatable',
- 'tostring',
- # TODO: depends on LJ_HASFFI, see `MMDEF_FFI(_)`.
- 'new',
- # TODO: depends on LJ_52 || LJ_HASFFI, see `MMDEF_PAIRS(_)`.
- 'pairs',
- 'ipairs',
-]
-
-
-GCROOT_MMNAME = 0
-GCROOT_BASEMT = GCROOT_MMNAME + len(MM_NAMES)
-GCROOT_IO_INPUT = GCROOT_BASEMT + i2notu32(LJ_T['NUMX']) + 1
-GCROOT_IO_OUTPUT = GCROOT_IO_INPUT + 1
+MM_NAMES = EnumBasedList('MMS', 'MM__MAX', cut_prefix, 'MM_')
# Get the name of the index in the predefined arrays.
def idx_name(field_name):
+ GCROOT_MMNAME = 0
+ GCROOT_BASEMT = GCROOT_MMNAME + len(MM_NAMES)
+ GCROOT_IO_INPUT = GCROOT_BASEMT + i2notu32(LJ_T['NUMX']) + 1
+ GCROOT_IO_OUTPUT = GCROOT_IO_INPUT + 1
+
# Don't use **{ to be compatible with Python 2.
gcroot = {}
gcroot.update({
@@ -1477,140 +1427,7 @@ def cdataptr(cd):
# JIT engine.
-IRS = [
- # Guarded assertions.
- 'LT',
- 'GE',
- 'LE',
- 'GT',
-
- 'ULT',
- 'UGE',
- 'ULE',
- 'UGT',
-
- 'EQ',
- 'NE',
-
- 'ABC',
- 'RETF',
-
- # Miscellaneous ops.
- 'NOP',
- 'BASE',
- 'PVAL',
- 'GCSTEP',
- 'HIOP',
- 'LOOP',
- 'USE',
- 'PHI',
- 'RENAME',
- 'PROF',
-
- # Constants.
- 'KPRI',
- 'KINT',
- 'KGC',
- 'KPTR',
- 'KKPTR',
- 'KNULL',
- 'KNUM',
- 'KINT64',
- 'KSLOT',
-
- # Bit ops.
- 'BNOT',
- 'BSWAP',
- 'BAND',
- 'BOR',
- 'BXOR',
- 'BSHL',
- 'BSHR',
- 'BSAR',
- 'BROL',
- 'BROR',
-
- # Arithmetic ops. ORDER ARITH
- 'ADD',
- 'SUB',
- 'MUL',
- 'DIV',
- 'MOD',
- 'POW',
- 'NEG',
-
- 'ABS',
- 'LDEXP',
- 'MIN',
- 'MAX',
- 'FPMATH',
-
- # Overflow-checking arithmetic ops.
- 'ADDOV',
- 'SUBOV',
- 'MULOV',
-
- # Memory ops. A = array, H = hash, U = upvalue, F = field,
- # S = stack.
-
- # Memory references.
- 'AREF',
- 'HREFK',
- 'HREF',
- 'NEWREF',
- 'UREFO',
- 'UREFC',
- 'FREF',
- 'STRREF',
- 'LREF',
-
- # Loads and Stores. These must be in the same order.
- 'ALOAD',
- 'HLOAD',
- 'ULOAD',
- 'FLOAD',
- 'XLOAD',
- 'SLOAD',
- 'VLOAD',
-
- 'ASTORE',
- 'HSTORE',
- 'USTORE',
- 'FSTORE',
- 'XSTORE',
-
- # Allocations.
- 'SNEW',
- 'XSNEW',
- 'TNEW',
- 'TDUP',
- 'CNEW',
- 'CNEWI',
-
- # Buffer operations.
- 'BUFHDR',
- 'BUFPUT',
- 'BUFSTR',
-
- # Barriers.
- 'TBAR',
- 'OBAR',
- 'XBAR',
-
- # Type conversions.
- 'CONV',
- 'TOBIT',
- 'TOSTR',
- 'STRTO',
-
- # Calls.
- 'CALLN',
- 'CALLA',
- 'CALLL',
- 'CALLS',
- 'CALLXS',
- 'CARG',
-]
+IRS = EnumBasedList('IROp', 'IR__MAX', cut_prefix, 'IR_')
# Mode bits: Commutative, {Normal/Ref, Alloc, Load, Store},
@@ -1662,71 +1479,21 @@ def ir_mode(op):
return mode
-IRTYPES = [
- 'nil',
- 'fal',
- 'tru',
- 'lud',
- 'str',
- 'p32',
- 'thr',
- 'pro',
- 'fun',
- 'p64',
- 'cdt',
- 'tab',
- 'udt',
- 'flt',
- 'num',
- 'i8 ',
- 'u8 ',
- 'i16',
- 'u16',
- 'int',
- 'u32',
- 'i64',
- 'u64',
- 'sfp',
-]
+IRTYPES = EnumBasedList('IRType', 'IRT__MAX', lambda x: {
+ 'IRT_CDATA': 'cdt',
+ 'IRT_FLOAT': 'flt',
+ 'IRT_LIGHTUD': 'lud',
+ 'IRT_SOFTFP': 'sfp',
+ 'IRT_UDATA': 'udt',
+ }.get(x, cut_prefix(x, 'IRT_')[:3].ljust(3).lower()))
-IRT_NUM = 14
-assert IRTYPES[IRT_NUM] == 'num', 'incorrect IRT_NUM definition'
-
-
-IRFIELDS = [
- 'str.len',
- 'func.env',
- 'func.pc',
- 'func.ffid',
- 'thread.env',
- 'tab.meta',
- 'tab.array',
- 'tab.node',
- 'tab.asize',
- 'tab.hmask',
- 'tab.nomm',
- 'udata.meta',
- 'udata.udtype',
- 'udata.file',
- 'cdata.ctypeid',
- 'cdata.ptr',
- 'cdata.int',
- 'cdata.int64',
- 'cdata.int64_4',
-]
+IRFIELDS = EnumBasedList('IRFieldID', 'IRFL__MAX', lambda x:
+ cut_prefix(x, 'IRFL_').lower().replace('_', '.', 1))
-IRFPMS = [
- 'floor',
- 'ceil',
- 'trunc',
- 'sqrt',
- 'exp2',
- 'log',
- 'log2',
- 'other'
-]
+IRFPMS = EnumBasedList('IRFPMathOp', 'IRFPM__MAX',
+ lambda x: cut_prefix(x, 'IRFPM_').lower())
# Don't use *[ to be compatible with Python 2.
@@ -1755,112 +1522,7 @@ REGISTERS = {
}
-IR_CALLS = [
- 'lj_str_cmp',
- 'lj_str_find',
- 'lj_str_new',
- 'lj_strscan_num',
- 'lj_strfmt_int',
- 'lj_strfmt_num',
- 'lj_strfmt_char',
- 'lj_strfmt_putint',
- 'lj_strfmt_putnum',
- 'lj_strfmt_putquoted',
- 'lj_strfmt_putfxint',
- 'lj_strfmt_putfnum_int',
- 'lj_strfmt_putfnum_uint',
- 'lj_strfmt_putfnum',
- 'lj_strfmt_putfstr',
- 'lj_strfmt_putfchar',
- 'lj_buf_putmem',
- 'lj_buf_putstr',
- 'lj_buf_putchar',
- 'lj_buf_putstr_reverse',
- 'lj_buf_putstr_lower',
- 'lj_buf_putstr_upper',
- 'lj_buf_putstr_rep',
- 'lj_buf_puttab',
- 'lj_buf_tostr',
- 'lj_tab_new_ah',
- 'lj_tab_new1',
- 'lj_tab_dup',
- 'lj_tab_clear',
- 'lj_tab_newkey',
- 'lj_tab_len',
- 'lj_gc_step_jit',
- 'lj_gc_barrieruv',
- 'lj_mem_newgco',
- 'lj_math_random_step',
- 'lj_vm_modi',
- 'log10',
- 'exp',
- 'sin',
- 'cos',
- 'tan',
- 'asin',
- 'acos',
- 'atan',
- 'sinh',
- 'cosh',
- 'tanh',
- 'fputc',
- 'fwrite',
- 'fflush',
- 'lj_vm_floor',
- 'lj_vm_ceil',
- 'lj_vm_trunc',
- 'sqrt',
- 'log',
- 'lj_vm_log2',
- 'pow',
- 'atan2',
- 'ldexp',
- 'lj_vm_tobit',
- 'softfp_add',
- 'softfp_sub',
- 'softfp_mul',
- 'softfp_div',
- 'softfp_cmp',
- 'softfp_i2d',
- 'softfp_d2i',
- 'lj_vm_sfmin',
- 'lj_vm_sfmax',
- 'lj_vm_tointg',
- 'softfp_ui2d',
- 'softfp_f2d',
- 'softfp_d2ui',
- 'softfp_d2f',
- 'softfp_i2f',
- 'softfp_ui2f',
- 'softfp_f2i',
- 'softfp_f2ui',
- 'fp64_l2d',
- 'fp64_ul2d',
- 'fp64_l2f',
- 'fp64_ul2f',
- 'fp64_d2l',
- 'fp64_d2ul',
- 'fp64_f2l',
- 'fp64_f2ul',
- 'lj_carith_divi64',
- 'lj_carith_divu64',
- 'lj_carith_modi64',
- 'lj_carith_modu64',
- 'lj_carith_powi64',
- 'lj_carith_powu64',
- 'lj_cdata_newv',
- 'lj_cdata_setfin',
- 'strlen',
- 'memcpy',
- 'memset',
- 'lj_vm_errno',
- 'lj_carith_mul64',
- 'lj_carith_shl64',
- 'lj_carith_shr64',
- 'lj_carith_sar64',
- 'lj_carith_rol64',
- 'lj_carith_ror64',
-]
+IR_CALLS = EnumBasedList('IRCallID', 'IRCALL__MAX', cut_prefix, 'IRCALL_')
def regname(reg_number):
@@ -1996,6 +1658,8 @@ def irt_isguard(t):
def irt_toitype(irt):
+ IRT_NUM = 14
+ assert IRTYPES[IRT_NUM] == 'num', 'incorrect IRT_NUM definition'
t = irt_type(irt)
if LJ_DUALNUM and t > IRT_NUM:
return LJ_T['NUMX']
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index 895171a4..5e369f00 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -830,6 +830,52 @@ class TestLJIRCallXSCType(TestCaseBase):
)
+# Base class to check FPMATHOP mapping in FPMATH IR.
+class TestLJIRFPMathOpBase(TestCaseBase):
+ location = 'lj_cf_print'
+ extension_cmds = 'lj-trace &((GG_State *)L)->J->cur'
+
+ @classmethod
+ def setUpClass(cls):
+ cls.lua_script = (
+ 'jit.opt.start("hotloop=1")\n'
+ 'local function trace(a)\n'
+ ' local x = {}\n'
+ ' return x\n'
+ 'end\n'
+ 'trace(1.1)\n'
+ 'trace(1.1)\n'
+ 'print()\n'
+ ).format(cls.lua_expr)
+ cls.pattern = r'num FPMATH .* ref: ' + RX_IRN + r' lit: ' + cls.op
+ super(TestLJIRFPMathOpBase, cls).setUpClass()
+
+
+class TestLJIRFPMathFloor(TestLJIRFPMathOpBase):
+ lua_expr = 'math.floor(a)'
+ op = 'floor'
+
+
+class TestLJIRFPMathCeil(TestLJIRFPMathOpBase):
+ lua_expr = 'math.ceil(a)'
+ op = 'ceil'
+
+
+class TestLJIRFPMathSqrt(TestLJIRFPMathOpBase):
+ lua_expr = 'math.sqrt(a)'
+ op = 'sqrt'
+
+
+class TestLJIRFPMathLog(TestLJIRFPMathOpBase):
+ lua_expr = 'math.log(a)'
+ op = 'log'
+
+
+class TestLJIRFPMathLog2(TestLJIRFPMathOpBase):
+ lua_expr = 'math.log(a, 3)'
+ op = 'log2'
+
+
class TestLJJSlotsBase(TestCaseBase):
location = 'trace_stop'
extension_cmds = (
@@ -1051,7 +1097,17 @@ class TestLJCTypeBase(TestCaseBase):
pattern = r'\[\d+\] <int>'
-for test_cls in TestCaseBase.__subclasses__():
+def get_leaf_subclasses(cls):
+ subclasses = cls.__subclasses__()
+ if not subclasses:
+ yield cls
+ else:
+ for sub in subclasses:
+ for leaf in get_leaf_subclasses(sub):
+ yield leaf
+
+
+for test_cls in get_leaf_subclasses(TestCaseBase):
test_cls.test = lambda self: self.check()
if __name__ == '__main__':
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [Tarantool-patches] [PATCH luajit v3] dbg: display fast function name along with ffid
2026-09-23 22:27 [Tarantool-patches] [PATCH luajit v2] dbg: avoid hardcoded enums (get them from target) Mikhail Elhimov via Tarantool-patches
@ 2026-09-24 17:33 ` Mikhail Elhimov via Tarantool-patches
0 siblings, 0 replies; 6+ messages in thread
From: Mikhail Elhimov via Tarantool-patches @ 2026-09-24 17:33 UTC (permalink / raw)
To: Sergey Kaplun, Sergey Bronnikov, Evgeniy Temirgaleev; +Cc: tarantool-patches
Part of tarantool/tarantool#4808
---
Changes in v3:
- Fixed fast function regexp in tests
Changes in v2:
- Format is changed to 'ffname (#ffid)'
- Replaced single '_' with '.' in ffname
- Adjusted tests to check mapping
This patch is to be applied after https://lists.tarantool.org/pipermail/tarantool-patches/2026-September/030791.html.
Branch: https://github.com/tarantool/luajit/tree/elhimov/gh-4808-display-fast-function-name
Related issue: https://github.com/tarantool/tarantool/issues/4808
src/luajit_dbg.py | 19 +++++++++++++------
.../debug-extension-tests.py | 6 ++++--
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
index 5cd23a88..a564801b 100644
--- a/src/luajit_dbg.py
+++ b/src/luajit_dbg.py
@@ -1121,6 +1121,11 @@ def frames(L):
# LuaJIT macro implementations and structure access.
+# Get FastFunc enum members and replace any single '_' with '.'.
+FF_NAMES = EnumBasedList('FastFunc', 'FF__MAX', lambda x:
+ re.sub('(?<!_)_(?!_)', '.', cut_prefix(x, 'FF_')))
+
+
def mref(typename, obj):
return dbg.cast(typename, obj['ptr64'] if LJ_GC64 else obj['ptr32'])
@@ -1716,7 +1721,7 @@ def dump_lj_gco_proto(gcobj):
def dump_lj_gco_func(gcobj):
func = dbg.cast('struct GCfuncC *', gcobj)
- ffid = func['ffid']
+ ffid = int(func['ffid'])
if ffid == 0:
pt = funcproto(func)
@@ -1729,7 +1734,8 @@ def dump_lj_gco_func(gcobj):
elif ffid == 1:
return 'C function @ {}'.format(strx64(func['f']))
else:
- return 'fast function #{}'.format(int(ffid))
+ ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
+ return 'fast function {} (#{})'.format(ffname, ffid)
def dump_lj_gco_trace(gcobj):
@@ -2079,7 +2085,7 @@ def dump_proto(proto):
def dump_func(func):
- ffid = func['ffid']
+ ffid = int(func['ffid'])
if ffid == 0:
pt = funcproto(func)
@@ -2087,7 +2093,8 @@ def dump_func(func):
elif ffid == 1:
return 'C function @ {}\n'.format(strx64(func['f']))
else:
- return 'fast function #{}\n'.format(int(ffid))
+ ffname = FF_NAMES[ffid] if ffid < len(FF_NAMES) else "unknown"
+ return 'fast function {} (#{})\n'.format(ffname, ffid)
# FFI dumpers.
@@ -2713,7 +2720,7 @@ the type and some info related to it.
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
<CFUNC>: C function <mcode address>
- <FFUNC>: fast function #<ffid>
+ <FFUNC>: fast function <ffname> (#<ffid>)
* LJ_TTRACE: trace <traceno> @ <gcr>
* LJ_TCDATA: cdata @ <gcr>
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
@@ -2932,7 +2939,7 @@ the type and some info related to it.
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
<CFUNC>: C function <mcode address>
- <FFUNC>: fast function #<ffid>
+ <FFUNC>: fast function <ffname> (#<ffid>)
* LJ_TTRACE: trace <traceno> @ <gcr>
* LJ_TCDATA: cdata @ <gcr>
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index 5e369f00..fe5e34f5 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -326,7 +326,7 @@ GCO_ARGS = (
'coroutine.create(function() end),\n'
'function() end,\n'
'require,\n'
- 'print,\n'
+ 'math.min,\n'
'ffi.new("int*"),\n'
'{1},\n'
'newproxy(),\n'
@@ -338,7 +338,7 @@ GCO_RX = (
r'thread @ ' + RX_ADDR + r'\n'
r'Lua function @ ' + RX_ADDR + r', [0-9]+ upvalues, .+:[0-9]+\n'
r'C function @ ' + RX_ADDR + r'\n'
- r'fast function #[0-9]+\n'
+ r'fast function math.min \(#[0-9]+\)\n'
r'cdata @ ' + RX_ADDR + r' \[\d+\] <int \*> 0x0\n'
r'table @ ' + RX_ADDR + r' \(asize: \d+, hmask: ' + RX_HASH + r'\)\n'
r'userdata @ ' + RX_ADDR + r'\n'
@@ -367,6 +367,7 @@ class TestLJTV(TestCaseBase):
# Sorted in LJT order.
lua_script = (
'local ffi = require("ffi")\n'
+ 'local math = require("math")\n'
'print(\n'
' nil,\n'
' false,\n'
@@ -435,6 +436,7 @@ class TestLJGCo(TestCaseBase):
lua_script = (
'local ffi = require("ffi")\n'
+ 'local math = require("math")\n'
'print(\n' +
GCO_ARGS +
' 1\n' # Stub for the pattern.
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-24 20:14 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-09 13:07 [Tarantool-patches] [PATCH luajit] dbg: display fast function name along with ffid Mikhail Elhimov via Tarantool-patches
2026-09-22 9:16 ` Sergey Kaplun via Tarantool-patches
2026-09-23 22:55 ` Mikhail Elhimov via Tarantool-patches
2026-09-24 16:48 ` [Tarantool-patches] [PATCH luajit v2] " Mikhail Elhimov via Tarantool-patches
2026-09-24 20:14 ` [Tarantool-patches] [PATCH luajit v3] " Mikhail Elhimov via Tarantool-patches
2026-09-23 22:27 [Tarantool-patches] [PATCH luajit v2] dbg: avoid hardcoded enums (get them from target) Mikhail Elhimov via Tarantool-patches
2026-09-24 17:33 ` [Tarantool-patches] [PATCH luajit v3] dbg: display fast function name along with ffid Mikhail Elhimov via Tarantool-patches
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox