šŸ“ƒ Lua Alpha

General discussion and feedback on Second Life's SLua Alpha
lsl-luau discrepancy with mono: register exhaustion with concatenation & possible performance issue of list string casting
While trying to stress test / benchmark a comparison for (string) list and llDumpList2String , I came across a register exhaustion for a script in lsl-luau that works in mono. I'm reporting both as one canny because I'm unsure if these are related. A) First, for the benchmark: In LSO: === list-to-string benchmark: 100 iterations x 300 items === (string)list total = 1040.432007 ms mean = 10.404320 ms llDumpList2String total = 1896.921143 ms mean = 18.969212 ms ratio (string/dump) = 0.548485x === DONE === In Mono: === list-to-string benchmark: 100 iterations x 300 items === (string)list total = 226.023000 ms mean = 2.260230 ms llDumpList2String total = 316.186000 ms mean = 3.161860 ms ratio (string/dump) = 0.714842x === DONE === In LSL-LUAU: === list-to-string benchmark: 100 iterations x 300 items === (string)list total = 2287.902000 ms mean = 22.879020 ms llDumpList2String total = 589.087000 ms mean = 5.890871 ms ratio (string/dump) = 3.883810x === DONE === === list-to-string benchmark: 100 reps x 500 items === (string)list total = 4536.675000 ms mean = 45.366750 ms llDumpList2String total = 1022.474000 ms mean = 10.224740 ms ratio (string/dump) = 4.436957x === DONE === Something about how casting a list to a string is way worse in lsl-luau. My thought was that it's likely something that could be optimized if llDumpList2String is about 4x faster already. B) Second, a test script of the discrepancy is the following default { state_entry() { integer i = 1; string s = (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i + (string)i ; llOwnerSay(s); } } It prints "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" in mono, but in lsl-luau it fails to compile with "Out of registers when trying to allocate 1 registers: exceeded limit 255" I doubt there are many real use cases where this would have an impact after switching off mono, but it is still a notable difference.
2
Ā·
Bug
Ā·
tracked
lsl-luau vm bug: lists are incorrectly evaluated to empty when included on the left-hand and right-hand side of an expression
I encountered this Mono vs LSL VM discrepancy while trying to use AVSitter compiled to the LSL VM (offsets would fail to work due to how lists are handled in sitA) Here is a sample script that breaks on LSL VM but works on Mono: default { state_entry() { list vectors = [<1,0,1>,<0,-0.192,2.479>]; vectors = [(vector)llList2String(vectors, 0),(vector)llList2String(vectors, 1)]; // <--- does not work in lsl vm llSay(0,"LSL VM TEST VECTOR PARSE: " + (string)((vector)llList2String(vectors, 1))); } } This pattern breaks compatibility due to the self-referenced assignment, the vectors array becomes [<0,0,0>, <0,0,0>] instead of keeping the same values [<1,0,1>,<0,-0.192,2.479>]. The expected output of llSay here is <0,-0.192,2.479> like in Mono, but in lsl vm it outputs <0,0,0> Tested in Clawed region, current simulator: Luau 2026-06-09.27238848717 A simpler version that also breaks: default { state_entry() { list integers = [1,2,3]; integers = [llList2Integer(integers, 0)]; llSay(0, llList2String(integers, 0)); // Expected Output: 1, Actual: 0 } } Some further observations from Suzanna: Another example, tested on the Beta grid, Luau 2026-07-24.30110090421: default { state_entry() { list myList = ["test"]; myList = [myList == []]; // myList should be [0] llOwnerSay((string)myList); // --> 1 } } When the list being assigned to is also used inside the expression, its value is evaluated to an empty list. I think the bug comes from here: https://github.com/secondlife/slua/blob/ab883b7072887e73d5f962bd6d35467d098276d8/Compiler/src/LSLCompiler.cpp#L921-L964 where the destination list is assigned a new empty table before evaluating the expression.
6
Ā·
Bug
Ā·
inĀ progress
Erratic starts of halted SLua scripts when drag-copying the containing object.
When drag-copying an object containing a halted LSL-Mono script, the script in the new copy is also halted. This is the desired behavior. When drag-copying an object containing a halted SLua script the copied script may start running depending on A, the exact contents of the script, and B, whether one is copying a single instance or multiple instances. Procedure to reproduce: Step 1: Rez a block. Put the following script in the block, mark it Not Running, and save. local base = ll.GetPos() while true do ll.SetLinkPrimitiveParamsFast( LINK_THIS, {PRIM_POSITION, vector(math.random()-0.5, 0, 0) + (base + ll.GetPos())/2 } ) ll.SetLinkPrimitiveParamsFast( LINK_THIS, {PRIM_POSITION, vector(0, math.random()-0.5, 0) + (base + ll.GetPos())/2 } ) ll.SetLinkPrimitiveParamsFast( LINK_THIS, {PRIM_POSITION, vector(0, 0, math.random()-0.5) + (base + ll.GetPos())/2 } ) ll.SetText( tostring(ll.GetPos()-base), vector(1,1,1), 1 ) end--while Drag-copy the object horizontally several times. Observe that the script remains halted. Select the newly created group of objects. Drag-copy the group vertically several times. Observe that some or all scripts in the new copies spontaneously start running. Step 2: Delete the first group. Rez a new block and put the following nearly identical script in it. (Difference is ll.SetText argument in line 6.) Again, mark it as not running and save. local base = ll.GetPos() while true do ll.SetLinkPrimitiveParamsFast( LINK_THIS, {PRIM_POSITION, vector(math.random()-0.5, 0, 0) + (base + ll.GetPos())/2 } ) ll.SetLinkPrimitiveParamsFast( LINK_THIS, {PRIM_POSITION, vector(0, math.random()-0.5, 0) + (base + ll.GetPos())/2 } ) ll.SetLinkPrimitiveParamsFast( LINK_THIS, {PRIM_POSITION, vector(0, 0, math.random()-0.5) + (base + ll.GetPos())/2 } ) ll.SetText( tostring(os.clock()), vector(1,1,1), 1 ) end--while Again, drag-copy the object. Observe that the new copy starts running immediately every time. As you can imagine, this bug defeats attempts to start a group of test scripts together, or to precisely place a group of objects containing scripts that will move the objects before starting.
4
Ā·
Bug
Ā·
inĀ progress
Load More
→