From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id CDE726ECCC; Thu, 8 Oct 2026 14:08:32 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org CDE726ECCC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1791457712; bh=P7XRMXC7xwZH+xI6ubkyV1PV4LNN1W9/93Zj0Axx6YE=; h=Date:To:Cc:References:In-Reply-To:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=JYETHIUdaegP5W8rpSNDY+CBVb9s2+bV8K9CaLfBYmIwrlBSrMxuwk5VDE9HXjXfh TuSxOSb/Ll0EtOwQ+nAhw98b7/yFaOFvTTk/QUTpiH0+fElWNtY4pK52YzisR5D9oA nHTrJgPlIysDhI7JBHvTEjU1sf5kfB/lU5K89fOc= Received: from send243.i.mail.ru (send243.i.mail.ru [95.163.59.82]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 450026ECCC for ; Thu, 8 Oct 2026 14:08:32 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 450026ECCC Received: by exim-smtp-5cc9c86755-p2vc2 with esmtpa (envelope-from ) id 1xElzD-00000000Qfx-0S3E; Thu, 08 Oct 2026 14:08:31 +0300 Message-ID: Date: Thu, 8 Oct 2026 14:08:30 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird To: Mikhail Elhimov , Sergey Kaplun , Evgeniy Temirgaleev Cc: tarantool-patches@dev.tarantool.org References: <20260909084908.354159-1-m.elhimov@vk.team> <20261007221837.123140-1-m.elhimov@vk.team> Content-Language: en-US In-Reply-To: <20261007221837.123140-1-m.elhimov@vk.team> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-4EC0790: 10 X-618D5548: 2A84BE2F4C46F1174BD03525DDD6C896F502511369D79FE9708095CCF701D712540F7FCF7629B667 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD9AF8DA1406861E5C962BA02604EE8E285E4DB8460BDA10DAE182A05F5380850403A23BB0E8C4CFF953DE06ABAFEAF670539A3BC617119B696A3A52E0E1A8BD4D1D42CF41164E76205 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7E628FE8A185FCFBEEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637AC83A81C8FD4AD23D82A6BABE6F325AC2E85FA5F3EDFCBAA7353EFBB553375667A7F105494975402807E332706A8DF4DD81F2F1B11BF6ECE1441680A74ABB94B389733CBF5DBD5E9D5E8D9A59859A8B652D31B9D28593E51CC7F00164DA146DA6F5DAA56C3B73B237318B6A418E8EAB8090A508E0FED6299176DF2183F8FC7C0CF6F77B9BC2E078CCD04E86FAF290E2DB606B96278B59C421DD303D21008E29813377AFFFEAFD269176DF2183F8FC7C0D75EB778CE7D8A0C68655334FD4449CB9ECD01F8117BC8BEAAAE862A0553A39223F8577A6DFFEA7C4DCCFF368A6260CFC4224003CC83647689D4C264860C145E X-C1DE0DAB: 0D63561A33F958A5A1972DFFE19C727C5002B1117B3ED6960BF40425A5E74D05E772F934B9BCD185823CB91A9FED034534781492E4B8EEAD21962E278E8CAFBABDAD6C7F3747799A X-C8649E89: 1C3962B70DF3F0ADB58128AB1E6D661A8E10F71CB4DF9F96AB70F9BE574AE9C625B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D659F72236E3A587F09B9DECBD110C80FFE917A809B29809242B815B65EB588C818ED7260D746F564AFBB8341EE9D5BE9A0A3A51B42395823160163AB38ABE3606EE00BFBDDBF03B6D1BC7CEAA0681F5848F4C41F94D744909CE2512F26BEC029E55448553D2254B8D95CD72808BE417F3B9E0E7457915DAA85F X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXOcIETfglQORZ0zpDET4Zrk3igikrdHlWDpLF/KQBGEIe+eya20PhEY= X-Mailru-Sender: C4F68CFF4024C8867DFDF7C7F25884580B91FD6C71AC234EF33F69C7E48EA1FB3526A8B36A37B625A00CF82E1F1123DB645D15D82EE4B272BD6E4642A116CA93524AA66B5ACBE6721EF430B9A63E2A504198E0F3ECE9B5443453F38A29522196 X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH luajit v3] dbg: avoid hardcoded enums (get them from target) X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Bronnikov via Tarantool-patches Reply-To: Sergey Bronnikov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Hi, Mikhail, thanks for the patch! LGTM Sergey On 10/8/26 01:18, Mikhail Elhimov wrote: > 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 v3: > * Adjusted the way number is casted to enum type. > For unknown reason sometimes in LLDB `gdb.eval(str(i))` did evaluate > any number to zero value, and looks like it depends on the internal > state of LLDB because it might work correctly being executed later > after some other command. The updated way looks more "stable", at > least it works correctly in all tests. > > 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..7c2d085f 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: > + # :: > + 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, 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+\] ' > > > -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__':