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 A318F6ECCC; Tue, 13 Oct 2026 16:41:26 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org A318F6ECCC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1791898886; bh=eNr4wLL+WJ9AW35gTA/dLbrpIFIxt1C2h1pZP9XtrwA=; h=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=e2np1s4VrUOdlXbK6i/x44M/f345IbrNP8pCWgg0rFbTsXl5YPXC7W9PBIoziy0Dd 23L7AH0i9CzLIv/JU3PdH/yRaECnWNcvnTgZ7f/6Id9Ce8/xrLCmtTP+mTauE6sYhl YV0eM/QgsIXsyNTFvJXhrZ05vREvfDktqzzOUg7w= Received: from send278.i.mail.ru (send278.i.mail.ru [95.163.59.117]) (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 2172E6ECCC for ; Tue, 13 Oct 2026 16:41:25 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 2172E6ECCC Received: by exim-smtp-84d6fb566c-m966d with esmtpa (envelope-from ) id 1xGcku-00000000CB9-0YYY; Tue, 13 Oct 2026 16:41:24 +0300 Date: Tue, 13 Oct 2026 16:41:02 +0300 To: Sergey Bronnikov Message-ID: References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD91ABAE9865AC7DC884B93AE6D1534B2727DE2F6E77BE0251F182A05F5380850407A3A50A94964D6C43DE06ABAFEAF6705D928D3B0898B5F416212589471F8F21B906DE0852CB233E4 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7FDE19FEC90BA7BD7C2099A533E45F2D0395957E7521B51C2CFCAF695D4D8E9FCEA1F7E6F0F101C6759CC434672EE6371C2A783ECEC0211ADC4224003CC836476D5A39DEEDB180909611E41BBFE2FEB2B0F5257F605B4D41012CCD028BB3CDA7C57C1D077CB00FAE84004BBD888E7CDA99FA2833FD35BB23D27C277FBC8AE2E8B60CDF180582EB8FBA471835C12D1D977C4224003CC8364762BB6847A3DEAEFB0F43C7A68FF6260569E8FC8737B5C2249EC8D19AE6D49635B68655334FD4449CB9ECD01F8117BC8BEAAAE862A0553A39223F8577A6DFFEA7C9B187695B4E7C35343847C11F186F3C59DAA53EE0834AAEE X-C1DE0DAB: 0D63561A33F958A570DF4AEF33BE542B5002B1117B3ED696219AF2D2C731D22BCCE9A60C8CB01D7C823CB91A9FED034534781492E4B8EEAD0942DC5495D0595EBDAD6C7F3747799A X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE1918E10F71CB4DF9F96AB70F9BE574AE9C625B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D659859644F8382D6ED59821CAC29AC6B7102EC2D0EC8B07697B2A4150923EA9D4952225F9D72DDFC077B8341EE9D5BE9A0AE792B62CE3D849080FFE05D9CB8CC1D0B3306262912A23626536EB022892E5344C41F94D744909CECFA6C6B0C050A61A8CAF69B82BA93681CD72808BE417F3B9E0E7457915DAA85F X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXOcIETfglQORZ0zpDET4Zrk3igikrdHlWMZvMshegCzRtEW4g7DlDWI= X-Mailru-Sender: 689FA8AB762F73937C9FA53A4753B313D2873C1AF5A08973A53CA6ACF6632B8C1A59123AA66EF52CE49D44BB4BD9522A059A1ED8796F048DB274557F927329BE89D5A3BC2B10C37545BD1C3CC395C826B4A721A3011E896F X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH luajit] Optionally return PC position in jit.util.tracesnap(). 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 Kaplun via Tarantool-patches Reply-To: Sergey Kaplun Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Hi, Sergey! Thanks for the patch! LGTM, after fixing my comments below. On 08.10.26, Sergey Bronnikov wrote: > From: Mike Pall > > Suggested by Sergey Bronnikov. > > (cherry picked from commit 8e6520a7aecd0517e792b359afbbfd7274791f5f) > > The optional `getpos` argument is needed for ljopt [1], a tool that > verifies the correctness of LuaJIT optimizations by translating the > recorded IR into SMT-LIB and checking the formulas with an SMT solver. > Traces often lack sufficient information for accurate modeling, so > ljopt extracts the address of the bytecode pointed to by the snapshot > directly from LuaJIT during execution. > > The LuaJIT internal API includes the function `jit.util.tracesnap(tr, > sn)`. In principle, this function could be extended to return the > program counter (pc). This patch does exactly that: an optional third > argument is added, and when it is truthy the second value returned by > `jit.util.tracesnap()` is the PC position of the snapshot in the > bytecode of the function where the trace starts. > > Also, the patch adds a test that records a root loop trace and > checks that the returned position is the `FORL` jump target (the > loop entry), that no position is returned without the optional > argument or with a false value, and that every snapshot of the > trace reports a valid bytecode offset. I don't understand this paragraph. Usually we don't describe added tests for the features (especially in the way "what was done" instead of "why it was done"). > > 1. https://github.com/ligurio/ljopt > Please, mention the backporting issues as well. > Sergey Bronnikov: > * added the description and the test for the feature > --- > > Branch: https://github.com/tarantool/luajit/tree/ligurio/gh-xxxx-tracesnap-getpos > > src/lib_jit.c | 9 +- > .../lj-1472-tracesnap-getpos.test.lua | 89 +++++++++++++++++++ > 2 files changed, 97 insertions(+), 1 deletion(-) > create mode 100644 test/tarantool-tests/lj-1472-tracesnap-getpos.test.lua > > diff --git a/src/lib_jit.c b/src/lib_jit.c > index 9f870f68f..5a0d38611 100644 > --- a/src/lib_jit.c > +++ b/src/lib_jit.c > diff --git a/test/tarantool-tests/lj-1472-tracesnap-getpos.test.lua b/test/tarantool-tests/lj-1472-tracesnap-getpos.test.lua > new file mode 100644 > index 000000000..a56a7a679 > --- /dev/null > +++ b/test/tarantool-tests/lj-1472-tracesnap-getpos.test.lua > @@ -0,0 +1,89 @@ > +local tap = require('tap') > +local bit = require('bit') > +local jutil = require('jit.util') > +local vmdef = require('jit.vmdef') > + > +-- The test checks the optional `getpos` argument of > +-- `jit.util.tracesnap()` that makes the function return the PC > +-- position of the snapshot in the function bytecode. > +-- See also https://github.com/LuaJIT/LuaJIT/issues/1472. > + > +local test = tap.test('lj-1472-tracesnap-getpos'):skipcond({ > + ['Test requires JIT enabled'] = not jit.status(), > +}) > + > +test:plan(8) > + > +-- Entries in `vmdef.bcnames` are 6 characters long. > +local BC_NAME_LENGTH = 6 > + > +-- Return the name of the bytecode operation for the given > +-- instruction, that is encoded in the low byte. > +local function opname(ins) > + local oidx = BC_NAME_LENGTH * bit.band(ins, 0xff) > + local name = vmdef.bcnames:sub(oidx + 1, oidx + BC_NAME_LENGTH) > + return (name:gsub('%s+$', '')) Minor: I suggest the more readable: | return name:match('%a+') Feel free to ignore. > +end > + > +local function payload() > + local sum = 0 > + for i = 1, 100 do Minor: Typo: s/100/4/ > + sum = sum + i > + end > + return sum > +end > + > +-- Find the loop back-edge (FORL) in the function bytecode and > +-- compute its jump target, that is the first instruction of the Typo: s/that/which/ > +-- loop body. `pc == 0` is the JCproto header, so real > +-- instructions start from `pc == 1`. JIT compilation is disabled > +-- while scanning, so this loop is not recorded as a trace. > +jit.off() > +local nbc = jutil.funcinfo(payload).bytecodes > +local loop_entry > +for pc = 1, nbc - 1 do > + local ins = jutil.funcbc(payload, pc) > + if opname(ins) == 'FORL' then > + -- The jump offset is relative to the next instruction and is > + -- biased by `BCBIAS_J`. > + local jmp = bit.rshift(ins, 16) - 0x8000 Let's name the magic number: | local BCBIAS_J = 0x8000 > + loop_entry = pc + 1 + jmp > + break > + end > +end > +test:isnt(loop_entry, nil, 'FORL instruction is found') It should be an assert instead, since this is the test precondition. > + > +-- Record a root loop trace in `payload`. Snapshot #0 points to > +-- the loop entry (the FORL jump target). > +jit.on() > +jit.flush() > +jit.opt.start('hotloop=1') > +payload() > + > +local info = jutil.traceinfo(1) > +test:ok(info, 'the root loop trace is recorded') It should be an assert instead, since this is the test precondition. > +local snap, pos = jutil.tracesnap(1, 0, true) > +test:istable(snap, 'the snapshot table is returned') > +test:is(pos, loop_entry, 'the PC position points to the loop entry') > + > +local _, pos_without = jutil.tracesnap(1, 0) > +test:is(pos_without, nil, 'no PC position without getpos') > + > +local _, pos_false = jutil.tracesnap(1, 0, false) > +test:is(pos_false, nil, 'no PC position with getpos=false') > + > +local all_valid = true > +for sn = 0, info.nexit - 1 do > + local _, p = jutil.tracesnap(1, sn, true) > + if type(p) ~= 'number' or p < 0 or p >= nbc or > + jutil.funcbc(payload, p) == nil then > + all_valid = false > + end > +end > +test:ok(all_valid, 'positions of all snapshots are valid offsets') > + > +test:is(select('#', jutil.tracesnap(1, info.nexit, true)), 0, > + 'out-of-range snapshot returns nothing') > + It would be nice to add any correctness test. The most trivial in mind is the following: | src/luajit -Ohotloop=1 -e ' | local jutil = require"jit.util" | local function trivial() | local a = 0 | return a | end | trivial() | trivial() | | local _, b = jutil.tracesnap(1, 0, true) | print(b) | local _, b = jutil.tracesnap(1, 1, true) | print(b) | ' | 1 | 2 The snapshot is emitted at the function entry and before returning the result which makes it trivial to detect: | ---- TRACE 1 start (command line):3 | 0001 KSHORT 0 0 | 0002 RET1 0 2 | ---- TRACE 1 IR | .... SNAP #0 [ ---- ] | .... SNAP #1 [ ---- +0 ] Don't forget to reset the hotcounters during the recording of this example. > +test:done(true) > -- > 2.51.0 > -- Best regards, Sergey Kaplun