From: Mikhail Elhimov via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: Sergey Kaplun <skaplun@tarantool.org>,
Sergey Bronnikov <sergeyb@tarantool.org>,
Evgeniy Temirgaleev <e.temirgaleev@tarantool.org>
Cc: tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [PATCH luajit 2/4] dbg: avoid hardcoded enums
Date: Fri, 13 Nov 2026 02:42:23 +0300 [thread overview]
Message-ID: <fd5adcd59ddf0307c88149715a11fddc1ba27a39.1794522533.git.m.elhimov@vk.team> (raw)
In-Reply-To: <cover.1794522533.git.m.elhimov@vk.team>
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 (corresponding tests to check mapping of
FPMATHOP were added).
Resolves tarantool/tarantool#13094
Resolves tarantool/tarantool#13159
---
src/luajit_dbg.py | 675 +++++-------------
.../debug-extension-tests.py | 62 +-
2 files changed, 249 insertions(+), 488 deletions(-)
diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
index 77abf8c6..ceba4c58 100644
--- a/src/luajit_dbg.py
+++ b/src/luajit_dbg.py
@@ -106,6 +106,8 @@ class Debugger(object):
def initialize_extension(self, commands):
if self.configure():
for name, command in commands.items():
+ if hasattr(command, 'pre_register'):
+ command.pre_register()
self.register_command(command, name)
self.write('{} command initialized\n'.format(name))
self.write('LuaJIT debug extension is successfully loaded\n')
@@ -119,6 +121,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.'''
@@ -191,6 +200,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_member_name, enum_name=None):
+ '''Return debugger-specific value object that represents
+ the given enum member.
+ '''
+ pass
+
@abc.abstractproperty
def LJBase(self):
'''Base command class.
@@ -218,6 +237,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
@@ -338,6 +360,15 @@ class _GDBDebugger(Debugger):
def register_command(self, command, name):
command(name)
+ def create_enum_value(self, enum_member_name, enum_name=None):
+ val = self.eval(enum_member_name)
+ if val.type.code != gdb.TYPE_CODE_ENUM:
+ raise self.error('{}: expected enum, got type {}'.format(
+ enum_member_name,
+ val.type.code,
+ ))
+ return val
+
class LJBase(gdb and gdb.Command or object):
def __init__(ljbase, name):
# XXX Fragile: Though the command initialization looks
@@ -376,6 +407,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:
@@ -489,8 +524,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))
@@ -566,11 +600,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(
@@ -580,7 +613,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):
@@ -589,6 +621,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()
@@ -738,6 +776,55 @@ class _LLDBDebugger(Debugger):
)
)
+ def create_enum_value(self, enum_member_name, enum_name=None):
+ if enum_name is not None:
+ # In LLDB an enum member has to be specified in the
+ # form: <enum_name>::<enum_member_name>
+ expr = enum_name + "::" + enum_member_name
+ try:
+ val = self.eval(expr)
+ except Exception:
+ val = None
+
+ if val is not None:
+ if not self._lldb_tp_isenum(val.sbvalue.GetType()):
+ raise self.error('{}: expected enum, got type {}'.format(
+ expr,
+ val.sbvalue.GetType().GetTypeClass(),
+ ))
+ return val
+
+ # LLDB needs the enum name in the expression above but
+ # 1. Enum might be anonymous (like LJ_VMST__MAX)
+ # 2. 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 these cases 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)
+
+ raise self.error('{}: not found'.format(enum_member_name))
+
class LJBase(object):
# Ignore given parameters by LLDB.
def __init__(ljbase, debugger, unused):
@@ -829,6 +916,55 @@ def strx64(val):
return re.sub('L?$', '', hex(int(tou64(val))))
+class EnumBasedList(object):
+ def __init__(self, max_enum_member, enum_name, map_func=None,
+ *map_func_args):
+ self.__max_enum_member = max_enum_member
+ self.__enum_name = enum_name
+ self.__map_func = map_func
+ self.__map_func_args = map_func_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:
+ try:
+ max_enum_value = dbg.create_enum_value(
+ self.__max_enum_member, self.__enum_name
+ )
+ except Exception as e:
+ msg = 'failed to resolve {} enum members using {}'.format(
+ self.__enum_name or 'anonymous',
+ self.__max_enum_member,
+ )
+ raise dbg.error('{}: {}'.format(msg, e))
+ items = []
+ for i in range(max_enum_value):
+ item = str(dbg.cast_typeof(max_enum_value, i))
+ if self.__map_func:
+ item = self.__map_func(item, *self.__map_func_args)
+ items.append(item)
+ self.__items = items
+ return self.__items
+
+ def index(self, item):
+ return self.__get_items().index(item)
+
+
+def cut_prefix(s, prefix):
+ return s[len(prefix):] if s.startswith(prefix) else s
+
+
# Types and TValues.
@@ -906,10 +1042,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('BCM_max', 'BCMode', cut_prefix, 'BCM')
lj_bc_mode_ = None
@@ -935,136 +1068,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('BC__MAX', 'BCOp', cut_prefix, 'BC_')
def proto_bc(proto):
@@ -1219,42 +1223,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('MM__MAX', 'MMS', 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({
@@ -1298,18 +1276,17 @@ def ggfname_by_offset(offset):
return ggfname
+VM_STATES = EnumBasedList('LJ_VMST__MAX', None, cut_prefix, 'LJ_VMST_')
+
+
def vm_state(g):
- return {
- i2notu32(0): 'INTERP',
- i2notu32(1): 'LFUNC',
- i2notu32(2): 'FFUNC',
- i2notu32(3): 'CFUNC',
- i2notu32(4): 'GC',
- i2notu32(5): 'EXIT',
- i2notu32(6): 'RECORD',
- i2notu32(7): 'OPT',
- i2notu32(8): 'ASM',
- }.get(int(tou32(g['vmstate'])), 'TRACE')
+ index = i2notu32(g['vmstate'])
+ return VM_STATES[index] if index < len(VM_STATES) \
+ else vm_state_trace(~index)
+
+
+def vm_state_trace(traceno):
+ return 'TRACE(#{})'.format(traceno)
def gc_state(g):
@@ -1506,140 +1483,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('IR__MAX', 'IROp', cut_prefix, 'IR_')
# Mode bits: Commutative, {Normal/Ref, Alloc, Load, Store},
@@ -1691,71 +1535,31 @@ 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('IRT__MAX', 'IRType', 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',
-]
+IRT_NUM = None
-IRFPMS = [
- 'floor',
- 'ceil',
- 'trunc',
- 'sqrt',
- 'exp2',
- 'log',
- 'log2',
- 'other'
-]
+def irt_num():
+ global IRT_NUM
+ if IRT_NUM is None:
+ IRT_NUM = IRTYPES.index('num')
+ return IRT_NUM
+
+
+IRFIELDS = EnumBasedList('IRFL__MAX', 'IRFieldID', lambda x:
+ cut_prefix(x, 'IRFL_').lower().replace('_', '.', 1))
+
+
+IRFPMS = EnumBasedList('IRFPM__MAX', 'IRFPMathOp',
+ lambda x: cut_prefix(x, 'IRFPM_').lower())
# Don't use *[ to be compatible with Python 2.
@@ -1784,112 +1588,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('IRCALL__MAX', 'IRCallID', cut_prefix, 'IRCALL_')
def regname(reg_number):
@@ -2026,7 +1725,7 @@ def irt_isguard(t):
def irt_toitype(irt):
t = irt_type(irt)
- if LJ_DUALNUM and t > IRT_NUM:
+ if LJ_DUALNUM and t > irt_num():
return LJ_T['NUMX']
else:
return i2notu32(t)
@@ -3193,13 +2892,15 @@ If L is omitted, the main coroutine is used.
class LJState(dbg.LJBase):
- '''
+ @classmethod
+ def pre_register(cls):
+ cls.__doc__ = '''
lj-state
The command requires no args and dumps current VM and GC states:
-* VM state: <INTERP|C|GC|EXIT|RECORD|OPT|ASM|TRACE>
+* VM state: <{}>
* GC state: <PAUSE|PROPAGATE|ATOMIC|SWEEPSTRING|SWEEP|FINALIZE|LAST>
* JIT state: <IDLE|ACTIVE|RECORD|START|END|ASM|ERR>
- '''
+ '''.format('|'.join(list(VM_STATES) + [vm_state_trace('TRACENO')]))
def execute(self, arg):
g = G(L(None))
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index fe8c5028..8a3ef96a 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -289,12 +289,26 @@ class TestLJArch(TestCaseBase):
)
+RX_VM_STATE = r'({})'.format('|'.join([
+ r'INTERP',
+ r'LFUNC',
+ r'FFUNC',
+ r'CFUNC',
+ r'GC',
+ r'EXIT',
+ r'RECORD',
+ r'OPT',
+ r'ASM',
+ r'TRACE\(#\d+\)',
+]))
+
+
class TestLJState(TestCaseBase):
extension_cmds = 'lj-state'
location = 'lj_cf_print'
lua_script = 'print(1)'
pattern = (
- r'VM state: [A-Z]+\n'
+ r'VM state: ' + RX_VM_STATE + '\n'
r'GC state: [A-Z]+\n'
r'JIT state: [A-Z]+\n'
)
@@ -857,6 +871,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 = (
--
2.55.0
next prev parent reply other threads:[~2026-11-12 23:43 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 23:42 [Tarantool-patches] [PATCH luajit 0/4] " Mikhail Elhimov via Tarantool-patches
2026-11-12 23:42 ` [Tarantool-patches] [PATCH luajit 1/4] dbg: clean up and unification Mikhail Elhimov via Tarantool-patches
2026-11-12 23:42 ` Mikhail Elhimov via Tarantool-patches [this message]
2026-11-12 23:42 ` [Tarantool-patches] [PATCH luajit 3/4] dbg: display fast function name along with ffid Mikhail Elhimov via Tarantool-patches
2026-11-12 23:42 ` [Tarantool-patches] [PATCH luajit 4/4] dbg: remove wrong GC state Mikhail Elhimov via Tarantool-patches
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fd5adcd59ddf0307c88149715a11fddc1ba27a39.1794522533.git.m.elhimov@vk.team \
--to=tarantool-patches@dev.tarantool.org \
--cc=e.temirgaleev@tarantool.org \
--cc=m.elhimov@vk.team \
--cc=sergeyb@tarantool.org \
--cc=skaplun@tarantool.org \
--subject='Re: [Tarantool-patches] [PATCH luajit 2/4] dbg: avoid hardcoded enums' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox