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 4C1C16EC40; Tue, 10 Aug 2021 19:40:49 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 4C1C16EC40 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1628613649; bh=dRMwjOK5u/n1ZpqIayJwvuve4UO5fk4Hkt+QpH+MdFo=; h=Date:In-Reply-To:To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=oa3Zmh1d2qJyYeow9YYKyHx3QeAcCCQJhrTH2J0WKZ9h9euKWEoOM98nkngXk9yKF 8nnChE3T5I/5CFNKig+nNZ0BGnKeObUhpE1xcmHwS0Lj7kPLDQ9t0xPB2T+giHGS5h XQLeOAV034YU47D+CPdfSJRH6ZRnRcmIEKyKzZdY= Received: from smtp43.i.mail.ru (smtp43.i.mail.ru [94.100.177.103]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id C74FD6EC40 for ; Tue, 10 Aug 2021 19:40:47 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org C74FD6EC40 Received: by smtp43.i.mail.ru with esmtpa (envelope-from ) id 1mDUo2-0004UB-Nc; Tue, 10 Aug 2021 19:40:47 +0300 Message-Id: <4BF6CB05-7904-4918-81BA-73149399FD04@tarantool.org> Content-Type: multipart/alternative; boundary="Apple-Mail=_280D9147-E72B-4DC1-9FE3-5CD77A99F455" Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.100.0.2.22\)) Date: Tue, 10 Aug 2021 19:40:45 +0300 In-Reply-To: To: Sergey Kaplun References: <20210707143606.3499-1-skaplun@tarantool.org> <20210801103955.GY27855@tarantool.org> <20210808192846.GH27855@tarantool.org> X-Mailer: Apple Mail (2.3654.100.0.2.22) X-4EC0790: 10 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD92087353F0EC44DD906AB4890CDABF0C5CB76CEE71D3E4007182A05F5380850400192ADBEB942B4C1AC9D6CDA18B0B3F18B1E94E99E1E0BDE151D351EAE1B3081 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE74FC9C1E089083C84EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F79006379A70878BADDF00B98638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D8E0F19991489A063364F5DD9BBC8ABB05117882F4460429724CE54428C33FAD305F5C1EE8F4F765FC3A703B70628EAD7BA471835C12D1D9774AD6D5ED66289B52BA9C0B312567BB23117882F44604297287769387670735201E561CDFBCA1751F28451B159A507268D2E47CDBA5A96583BA9C0B312567BB231DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B67393CE827C55B5F775ECD9A6C639B01B4E70A05D1297E1BBCB5012B2E24CD356 X-C1DE0DAB: 0D63561A33F958A53D2D596B43B05067554DCC8BD601A09A880982C61FB26B97D59269BC5F550898D99A6476B3ADF6B47008B74DF8BB9EF7333BD3B22AA88B938A852937E12ACA753177526CD55AFC11410CA545F18667F91A7EA1CDA0B5A7A0 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D342C0B628602DFD0BCD3CCB694E8719D054E02B2EEE102F114A9E5120EF0B613607B402D054D0859861D7E09C32AA3244C697711903897141D9E2C3784BAB5ACF3A8CE788DE6831205FACE5A9C96DEB163 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2bioj6qlzQV0oSZOQMT/4xCtIrw== X-Mailru-Sender: 3B9A0136629DC912F4AABCEFC589C81E1AAFD3BED2C1E4E8393E53E719E302E1CDEF86246319806DAD07DD1419AC565FA614486B47F28B67C5E079CCF3B0523AED31B7EB2E253A9E112434F685709FCF0DA7A0AF5A3A8387 X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH luajit] ARM64: Fix write barrier in BC_USETS. 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 Ostanevich via Tarantool-patches Reply-To: Sergey Ostanevich Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" --Apple-Mail=_280D9147-E72B-4DC1-9FE3-5CD77A99F455 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Hi! Thanks for the patch, LGTM. I have no other explanation than that =E2=80=98missed flag as a result = of compare=E2=80=99. But you did it better - took time for me to get to the point.=20 BTW, will make easier to grasp with a simple C equivalent, like=20 - if (iswite(str) || closed !=3D 0) + if (iswite(str) || closed =3D=3D 0) Sergos. > On 9 Aug 2021, at 19:01, Sergey Kaplun wrote: >=20 > Igor, thanks for the feedback! >=20 > On 08.08.21, Igor Munkin wrote: >> Sergey, >>=20 >> Thanks for the fixes! See some new comments below. >>=20 >> On 01.08.21, Sergey Kaplun wrote: >>> Igor, >>>=20 >>> Thanks for the review! >>> Update commit message on the branch, considering you comments. >>=20 >> Got it, but I still have some more comments regarding it. >>=20 >>>=20 >>> See answers to you questions below. >>>=20 >>=20 >> >>=20 >>>=20 >>>>=20 >>>>> | ccmp TMP0w, #0, #0, ne >>>>> | beq <1 // branch out from barrier movement >>>>> `TMP0w` contains `upvalue->closed` field. If it equals NULL (the = first >>>>> `#0`). The second zero is the value of NZCV condition flags set if = the >>>>> condition (`ne`) is FALSE [1][2]. If the set value is not white, = then >>>>> flags are set to zero and branch is not taken (no Zero flag). If = it >>>>> happens at propagate or atomic GC State and the = `lj_gc_barrieruv()` >>>>> function is called then the gray value to set is marked as white. = That >>>>> leads to the assertion failure in the `gc_mark()` function. >>>>=20 >>>> OK, I understand almost nothing from the part above. Here are the >>>> comments: >>>> 1. "If it equals NULL (the first `#0`)", then what? >>>=20 >>> My bad: >>> I mean here: >>> If it equals NULL (the first `#0`), then the upvalue is open. >>=20 >> So why do you use NULL instead of 0? The field is uint8_t type, so 0 = is >> much clearer. >=20 > Changed. >=20 >>=20 >>> Added this. >>>=20 >>>> 2. Just to check we are on the same page: the second "immediate" >>>> mentioned in docs[1] is NZCV? >>>=20 >>> Yes. >>>=20 >>>> Then beq <1 branch is not taken since >>>> (TMP0w !=3D 0) is FALSE (i.e. upvalue is not closed), but zero flag = in >>>> NZCV value is not set? >>>=20 >>> Yes. >>>=20 >>>> So how does the color of the value to be = stored >>>> relate to this control flow? >>>=20 >>> This NZCV value isn't set if the upvalue is white, because condition = is >>> of the following instruction >>>=20 >>> | tst TMP1w, #LJ_GC_WHITES // iswhite(str) >>>=20 >>> is TRUE. So the <1 branch is taken, because the upvalue is closed. >>=20 >> Well... I can't imagine how I needed to find this... This relates = mostly >> to ARM docs you've mentioned, but it would be nice to describe this >> behaviour in the commit message (since you're writing a verbose one). >>=20 >>>=20 >>>> 3. AFAICS, if the branch is not taken and is = called at >>>> propagate or atomic phase, the value is colored either to gray or = black. >>>=20 >>> Yes, that leads to the assertion failure mentioned in the ticket in = the >>> LuaJIT upstream. >>>=20 >>>>=20 >>>>>=20 >>>>> This patch changes yielded NZCV condition flag to 4 (Zero flag is = up) to >>>>> take the correct branch after `ccmp` instruction. >>>>>=20 >>>>> Sergey Kaplun: >>>>> * added the description and the test for the problem >>>>>=20 >>>>> [1]: = https://developer.arm.com/documentation/dui0801/g/pge1427897656225 >>>>> [2]: = https://community.arm.com/developer/ip-products/processors/b/processors-ip= -blog/posts/condition-codes-1-condition-flags-and-codes >>>>=20 >>>> Minor: Why #5629 is not mentioned? >>>=20 >>> Added. >>=20 >> Considering everything above, I propose the following wording: >> | Contributed by Javier Guerra Giraldez. >> | >> | (cherry picked from commit = c785131ca5a6d24adc519e5e0bf1b69b671d912f) >> | >> | >> | Closed upvalues are never gray. Hence when closed upvalue is = marked, it >> | is marked as black. Black objects can't refer white objects, so for >> | storing a white value in a closed upvalue, we need to move the = barrier >> | forward and color our value to gray by using `lj_gc_barrieruv()`. = This >> | function can't be called on closed upvalues with non-white values = since >> | there is no need to mark it again. >> | >> | USETS bytecode for arm64 architecture has the incorrect NZCV = condition >> | flag value in the instruction that checks the upvalue is closed: >> | | tst TMP1w, #LJ_GC_WHITES >> | | ccmp TMP0w, #0, #0, ne >> | | beq <1 // branch out from barrier movement >> | `TMP0w` contains `upvalue->closed` field, so the upvalue is open if = this >> | field equals to zero (the first one in `ccmp`). The second zero is = the >> | value of NZCV condition flags[1] yielded if the specified condition >> | (`ne`) is met for the current values of the condition flags[2]. = Hence, >> | if the value to be stored is not white (`TMP1w` holds its color), = then >> | the condition is FALSE and all flags bits are set to zero so branch = is >> | not taken (Zero flag is not set). If this happens at propagate or = atomic >> | GC phase, the `lj_gc_barrieruv()` function is called and the gray = value >> | to be set is marked like if it is white. That leads to the = assertion >> | failure in the `gc_mark()` function. >> | >> | This patch changes NZCV condition flag to 4 (Zero flag is set) to = take >> | the correct branch after `ccmp` instruction. >> | >> | Sergey Kaplun: >> | * added the description and the test for the problem >> | >> | [1]: = https://community.arm.com/developer/ip-products/processors/b/processors-ip= -blog/posts/condition-codes-1-condition-flags-and-codes >> | [2]: = https://developer.arm.com/documentation/dui0801/g/pge1427897656225 >> | >> | Part of tarantool/tarantool#5629 >=20 > Updated, as you've suggested. >=20 >>=20 >>>=20 >>=20 >> >>=20 >>>>=20 >>>>>=20 >>>>> src/vm_arm64.dasc | 2 +- >>>>> ...6-arm64-incorrect-check-closed-uv.test.lua | 38 = +++++++++++++++++++ >>>>> 2 files changed, 39 insertions(+), 1 deletion(-) >>>>> create mode 100644 = test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua >>>>>=20 >>>>=20 >>>> >>>>=20 >>>>> diff --git = a/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua = b/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua >>>>> new file mode 100644 >>>>> index 00000000..b757133f >>>>> --- /dev/null >>>>> +++ = b/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua >>>>> @@ -0,0 +1,38 @@ >>>>> +local tap =3D require('tap') >>>>> + >>>>> +local test =3D tap.test('lj-426-arm64-incorrect-check-closed-uv') >>>>> +test:plan(1) >>>>> + >>>>> +-- Test file to demonstrate LuaJIT USETS bytecode incorrect >>>>> +-- behaviour on arm64 in case when non-white object is set to >>>>> +-- closed upvalue. >>>>> +-- See also, https://github.com/LuaJIT/LuaJIT/issues/426. >>>>> + >>>>> +-- First, create a closed upvalue. >>>>> +do >>>>=20 >>>> Minor: I'm not sure, we need a separate lexical block here. Could = you >>>> please clarify the reason in the comment? >>>=20 >>> We need a closed upvalue. I suppose that it is the simpiest way to >>> create one. Please, provide a simplier example if you know one. >>=20 >> My bad. Yes, the easiest way to emit UCLO bytecode is using a = separate >> lexical block. >>=20 >>>=20 >>>>=20 >>>>> + local uv -- luacheck: no unused >>>>> + -- The function's prototype is created with the following >>>>> + -- constants at chunk parsing. After adding this constant to >>>>> + -- the function's prototype it will be marked as gray during >>>>> + -- propogate phase. >>>>=20 >>>> Then what does it test, if the constant is marked as gray? Will = this >>>> string be white later? >>>=20 >>> It shouldn't be white, it should be gray, otherwise the = aforementioned >>> condition is TRUE (remember, we need FALSE). >>=20 >> Again, PEBKAC, thanks for the explanation. >>=20 >>>=20 >>>>=20 >>>>> + local function usets() uv =3D '' end >>>>> + _G.usets =3D usets >>>>> +end >>>>> + >>>>> +-- Set GC state to GCpause. >>>>> +collectgarbage() >>>>> +-- Do GC step as often as possible. >>>>> +collectgarbage('setstepmul', 100) >>>>=20 >>>> Minor: Don't get, why you need to make GC less aggressive for the = test. >>>> The test is run, until propagate phase is finished. >>>=20 >>> More likely, that it is run, until the upvalue is marked as black >>> during traversing (with the bug). I can remove this line if you = insist. >>=20 >> Drop it, please. I can't even *feel* its effect ;) >=20 > Done. >=20 >>=20 >>>=20 >>>>=20 >>>>> + >>>>> +-- We don't know on what exactly step our upvalue is marked as >>>>> +-- black and USETS become dangerous, so just check it at each >>>>> +-- step. >>>>> +-- Don't need to do the full GC cycle step by step. >>=20 >> Minor: It would be nice to drop a few words about string and upvalue >> colours during this loop, but it's up to you. >=20 > Added. >=20 > The iterative patch is the following: >=20 > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > diff --git = a/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua = b/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua > index b757133f..4cdf1211 100644 > --- = a/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua > +++ = b/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua > @@ -21,9 +21,10 @@ end >=20 > -- Set GC state to GCpause. > collectgarbage() > --- Do GC step as often as possible. > -collectgarbage('setstepmul', 100) >=20 > +-- We want to wait for the situation, when upvalue is black, > +-- the string is gray. Both conditions are satisfied, when the > +-- corresponding `usets()` function is marked, for example. > -- We don't know on what exactly step our upvalue is marked as > -- black and USETS become dangerous, so just check it at each > -- step. > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >=20 >>=20 >>>>> +local old_steps_atomic =3D misc.getmetrics().gc_steps_atomic >>>>> +while (misc.getmetrics().gc_steps_atomic =3D=3D old_steps_atomic) = do >>>>> + collectgarbage('step') >>>>> + usets() -- luacheck: no global >>>>> +end >>>>> + >>>>> +test:ok(true) >>>>> +os.exit(test:check() and 0 or 1) >>>>> --=20 >>>>> 2.31.0 >>>>>=20 >>>>=20 >>>> [1]: = https://lists.tarantool.org/tarantool-patches/20210719073632.12008-1-skapl= un@tarantool.org/T/#u >>>>=20 >>>> --=20 >>>> Best regards, >>>> IM >>>=20 >>> --=20 >>> Best regards, >>> Sergey Kaplun >>=20 >> --=20 >> Best regards, >> IM >=20 > --=20 > Best regards, > Sergey Kaplun --Apple-Mail=_280D9147-E72B-4DC1-9FE3-5CD77A99F455 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8 Hi!

Thanks = for the patch, LGTM.

I have no other explanation than that =E2=80=98missed flag as = a result of compare=E2=80=99.
But you did it better = - took time for me to get to the point. 
BTW, = will make easier to grasp with a simple C equivalent, = like 

- = if (iswite(str) || closed !=3D 0)
+ if = (iswite(str) || closed =3D=3D 0)

Sergos.



On 9 Aug = 2021, at 19:01, Sergey Kaplun <skaplun@tarantool.org> wrote:

Igor, thanks for the feedback!

On 08.08.21, Igor Munkin wrote:
Sergey,

Thanks for the fixes! See some new comments below.

On 01.08.21, Sergey Kaplun wrote:
Igor,

Thanks for the review!
Update commit message on = the branch, considering you comments.

Got it, but I still have some more comments regarding it.


See answers to you questions below.


<snipped>



| ccmp TMP0w, #0, #0, ne
| beq <1 // branch = out from barrier movement
`TMP0w` contains = `upvalue->closed` field. If it equals NULL (the first
`#0`). The second zero is the value of NZCV condition flags = set if the
condition (`ne`) is FALSE [1][2]. If the set = value is not white, then
flags are set to zero and branch = is not taken (no Zero flag). If it
happens at propagate or = atomic GC State and the `lj_gc_barrieruv()`
function is = called then the gray value to set is marked as white. That
leads to the assertion failure in the `gc_mark()` = function.

OK, I understand = almost nothing from the part above. Here are the
comments:
1. "If it equals NULL (the first = `#0`)", then what?

My bad:
I mean here:
If it equals NULL (the first = `#0`), then the upvalue is open.

So why do you use NULL instead of 0? The field is uint8_t = type, so 0 is
much clearer.

Changed.


Added this.

2. Just to check we are = on the same page: the second "immediate"
mentioned in = docs[1] is NZCV?

Yes.

          &nb= sp;            = ;      Then beq <1 branch is not taken = since
(TMP0w !=3D 0) is FALSE (i.e. upvalue is not = closed), but zero flag in
NZCV value is not set?

Yes.

          &nb= sp;           So = how does the color of the value to be stored
relate to = this control flow?

This NZCV = value isn't set if the upvalue is white, because condition is
of the following instruction

| =    tst TMP1w, #LJ_GC_WHITES // iswhite(str)

is TRUE. So the <1 branch is taken, because the upvalue is = closed.

Well... I can't = imagine how I needed to find this... This relates mostly
to = ARM docs you've mentioned, but it would be nice to describe this
behaviour in the commit message (since you're writing a = verbose one).


3. = AFAICS, if the branch is not taken and <lj_gc_barrieruv> is called = at
propagate or atomic phase, the value is colored either = to gray or black.

Yes, that = leads to the assertion failure mentioned in the ticket in the
LuaJIT upstream.



This patch changes yielded NZCV condition flag = to 4 (Zero flag is up) to
take the correct branch after = `ccmp` instruction.

Sergey Kaplun:
* added the description and the test for the problem

[1]: https://developer.arm.com/documentation/dui0801/g/pge1427897656= 225
[2]: https://community.arm.com/developer/ip-products/processors/b/pr= ocessors-ip-blog/posts/condition-codes-1-condition-flags-and-codes

Minor: Why #5629 is not = mentioned?

Added.

Considering everything above, I = propose the following wording:
| Contributed by Javier = Guerra Giraldez.
|
| (cherry picked from = commit c785131ca5a6d24adc519e5e0bf1b69b671d912f)
|
|
| Closed upvalues are never gray. Hence when = closed upvalue is marked, it
| is marked as black. Black = objects can't refer white objects, so for
| storing a = white value in a closed upvalue, we need to move the barrier
| forward and color our value to gray by using = `lj_gc_barrieruv()`. This
| function can't be called on = closed upvalues with non-white values since
| there is no = need to mark it again.
|
| USETS bytecode = for arm64 architecture has the incorrect NZCV condition
| = flag value in the instruction that checks the upvalue is closed:
| | tst TMP1w, #LJ_GC_WHITES
| | ccmp TMP0w, = #0, #0, ne
| | beq <1 // branch out from barrier = movement
| `TMP0w` contains `upvalue->closed` field, so = the upvalue is open if this
| field equals to zero (the = first one in `ccmp`). The second zero is the
| value of = NZCV condition flags[1] yielded if the specified condition
|= (`ne`) is met for the current values of the condition flags[2]. = Hence,
| if the value to be stored is not white (`TMP1w` = holds its color), then
| the condition is FALSE and all = flags bits are set to zero so branch is
| not taken (Zero = flag is not set). If this happens at propagate or atomic
| = GC phase, the `lj_gc_barrieruv()` function is called and the gray = value
| to be set is marked like if it is white. That = leads to the assertion
| failure in the `gc_mark()` = function.
|
| This patch changes NZCV = condition flag to 4 (Zero flag is set) to take
| the = correct branch after `ccmp` instruction.
|
| = Sergey Kaplun:
| * added the description and the test for = the problem
|
| [1]: https://community.arm.com/developer/ip-products/processors/b/pr= ocessors-ip-blog/posts/condition-codes-1-condition-flags-and-codes
| [2]: https://developer.arm.com/documentation/dui0801/g/pge1427897656= 225
|
| Part of = tarantool/tarantool#5629

Updated, as = you've suggested.




<snipped>



src/vm_arm64.dasc =             &n= bsp;           &nbs= p;   |  2 +-
...6-arm64-incorrect-check-closed-uv.test.lua | 38 = +++++++++++++++++++
2 files changed, 39 insertions(+), 1 = deletion(-)
create mode 100644 = test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua


<snipped>

diff = --git = a/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua = b/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua
new file mode 100644
index = 00000000..b757133f
--- /dev/null
+++ = b/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua
@@ -0,0 +1,38 @@
+local tap =3D = require('tap')
+
+local test =3D = tap.test('lj-426-arm64-incorrect-check-closed-uv')
+test:plan(1)
+
+-- Test file to = demonstrate LuaJIT USETS bytecode incorrect
+-- behaviour = on arm64 in case when non-white object is set to
+-- = closed upvalue.
+-- See also, https://github.com/LuaJIT/LuaJIT/issues/426.
+
+-- First, create a closed upvalue.
+do

Minor: I'm not = sure, we need a separate lexical block here. Could you
please clarify the reason in the comment?

We need a closed upvalue. I = suppose that it is the simpiest way to
create one. Please, = provide a simplier example if you know one.
My bad. Yes, the easiest way to emit UCLO bytecode is using = a separate
lexical block.



+  local uv -- luacheck: no unused
+ =  -- The function's prototype is created with the following
+  -- constants at chunk parsing. After adding this = constant to
+  -- the function's prototype it will be = marked as gray during
+  -- propogate phase.

Then what does it test, if the = constant is marked as gray? Will this
string be white = later?

It shouldn't be white, = it should be gray, otherwise the aforementioned
condition = is TRUE (remember, we need FALSE).

Again, PEBKAC, thanks for the explanation.



+  local function usets() uv =3D '' end
+ =  _G.usets =3D usets
+end
+
+-- Set GC state to GCpause.
+collectgarbage()+-- Do GC step as often as possible.
+collectgarbage('setstepmul', 100)

Minor: Don't get, why you need to = make GC less aggressive for the test.
The test is run, = until propagate phase is finished.

More likely, that it is run, until the upvalue is marked as = black
during traversing (with the bug). I can remove this = line if you insist.

Drop it, = please. I can't even *feel* its effect ;)

Done.



+
+-- We don't know on what exactly step our = upvalue is marked as
+-- black and USETS become dangerous, = so just check it at each
+-- step.
+-- Don't = need to do the full GC cycle step by step.

Minor: = It would be nice to drop a few words about string and upvalue
colours during this loop, but it's up to you.

Added.

The iterative patch is the following:

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
diff --git = a/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua = b/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua
index = b757133f..4cdf1211 100644
--- = a/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua
+++ = b/test/tarantool-tests/lj-426-arm64-incorrect-check-closed-uv.test.lua
@@ -21,9 = +21,10 @@ end

-- Set GC = state to GCpause.
collectgarbage()
--- Do GC step as often as possible.
-collectgarbage('setstepmul', 100)

+-- We want = to wait for the situation, when upvalue is black,
+-- the = string is gray. Both conditions are satisfied, when the
+-- = corresponding `usets()` function is marked, for example.
-- We don't = know on what exactly step our upvalue is marked as
-- black and = USETS become dangerous, so just check it at each
-- = step.
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D


+local old_steps_atomic = =3D misc.getmetrics().gc_steps_atomic
+while = (misc.getmetrics().gc_steps_atomic =3D=3D old_steps_atomic) do
+  collectgarbage('step')
+  usets() = -- luacheck: no global
+end
+
+test:ok(true)
+os.exit(test:check() and 0 or = 1)
-- 
2.31.0


[1]: https://lists.tarantool.org/tarantool-patches/20210719073632.12= 008-1-skaplun@tarantool.org/T/#u

-- 
Best = regards,
IM

-- 
Best regards,
Sergey Kaplun

-- 
Best = regards,
IM

-- 
Best = regards,
Sergey = Kaplun

= --Apple-Mail=_280D9147-E72B-4DC1-9FE3-5CD77A99F455--