Question about SETFIELD nil emission in table constructor codegen

95 views
Skip to first unread message

重归混沌

unread,
Feb 27, 2026, 9:24:39 PM (3 days ago) Feb 27
to lua-l
Hi all,

I’m looking at table constructor codegen in Lua 5.5.

For code like:

local t = {
  a = nil,
  b = nil,
  c = nil,
}

luac -l -p outputs:

1       [1]     VARARGPREP      0
2       [1]     NEWTABLE        0 3 0   ; 0
3       [1]     EXTRAARG        0
4       [2]     SETFIELD        0 0 1k  ; "a" nil
5       [3]     SETFIELD        0 2 1k  ; "b" nil
6       [4]     SETFIELD        0 3 1k  ; "c" nil
7       [5]     RETURN          1 1 1   ; 0 out

From ltable.c, luaH_newkey does not insert a new entry when the value is nil (if (!ttisnil(value)) ...), so these writes do not seem to result in actual table entries.

My question is more about semantics:
for constructor fields that are statically unique and explicitly nil, is there any specific semantic reason these SETFIELD instructions must still be emitted? Or is this mainly a simplicity / uniformity choice in the code generator?

Thanks.

bil til

unread,
Feb 28, 2026, 3:44:50 AM (3 days ago) Feb 28
to lu...@googlegroups.com
Am Sa., 28. Feb. 2026 um 03:24 Uhr schrieb 重归混沌 <find...@gmail.com>:
>
> for constructor fields that are statically unique and explicitly nil, is there any specific semantic reason these SETFIELD instructions must still be emitted? Or is this mainly a

Lua compiler generally is NOT optimizing in any way... .

... the code is in full programmer control (and responsibility :) ).

Bernard L'île

unread,
Feb 28, 2026, 12:12:41 PM (3 days ago) Feb 28
to lua-l
Concerning literal tables, I've always asked myself why the compiler does not build table literals with only constant members at compile time and stores them in a constant pool, as it already does for strings and scalars.

As a further optimizations, table literals with variable components *could* (but need not) be built at compile time and then augmented with setfield opcodes to fill in the variable parts.

Błażej Roszkowski

unread,
Feb 28, 2026, 12:25:00 PM (3 days ago) Feb 28
to lu...@googlegroups.com
Complexity, I guess. LuaJIT does both optimizations you describe,
you can try reading bytecode at luajit dot me (not my website).

--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/lua-l/52ddf9da-3cbe-4319-a5ee-13a7ae11290en%40googlegroups.com.

Jure Bagić

unread,
Feb 28, 2026, 2:18:09 PM (3 days ago) Feb 28
to 'Bernard L'île' via lua-l
> Concerning literal tables, I've always asked myself why the compiler does not
> build table literals with only constant members at compile time and stores
> them in a constant pool, as it already does for strings and scalars.

A table might have a metatable with '__index' entry, and so the table set or
field set operation might do something entirely different
(see 'luaV_finishset').

--
Jure
signature.asc

Jure Bagić

unread,
Feb 28, 2026, 3:10:44 PM (3 days ago) Feb 28
to 'Bernard L'île' via lua-l
> A table might have a metatable with '__index' entry, and so the table set or
> field set operation might do something entirely different
> (see 'luaV_finishset').

Nevermind, this is incorrect, for some reason I thought you could set a
global metatable for all tables just like for strings, however that is not
possible.

--
Jure
signature.asc

Bernard L'île

unread,
Feb 28, 2026, 3:39:45 PM (3 days ago) Feb 28
to lua-l
> A table might have a metatable with '__index' entry, and so the table set or
> field set operation might do something entirely different
> (see 'luaV_finishset').

Yes of course, but for a table literal in source code, this cannot occur, as the table is created just in this moment of declaration, and the call to setmetatable() can only take place later.

bil til

unread,
Mar 1, 2026, 6:02:19 AM (2 days ago) Mar 1
to lu...@googlegroups.com
Am Sa., 28. Feb. 2026 um 18:12 Uhr schrieb 'Bernard L'île' via lua-l
<lu...@googlegroups.com>:
>
> As a further optimizations, table literals with variable components *could* (but need not) be built at compile time and then augmented with setfield opcodes to fill in the variable parts.
>

Such optimizations are typical for "offline compilers" like e. g. C
family. Typically use "multi-cycle" compling. I a first step not much
optimization, and ten more and more... . This complete process does
not need to take care very much on resources or timing, it just takes
"as long as it needs" and uses "as many resources as it needs"... .
The main thing is to get a very efficient and compact machine code in
the end.

But Lua is a script language with very efficient runtime compiler. Any
time or also RAM spoiling would be not very friendly here at all for a
huge and dominant part of applications.

Luiz Henrique de Figueiredo

unread,
Mar 1, 2026, 6:35:16 AM (2 days ago) Mar 1
to lu...@googlegroups.com
> Concerning literal tables, I've always asked myself why the compiler does not build table literals with only constant members at compile time and stores them in a constant pool, as it already does for strings and scalars.

Consider this code:

function f() return {1,2,3} end
A=f()
B=f()

With your proposed scheme, A and B would get the same table, not two
different tables with the same contents.
If the runtime needed to create copies of table literals then the
executed code would be much the same.

Philippe Verdy

unread,
Mar 1, 2026, 7:46:31 PM (2 days ago) Mar 1
to lu...@googlegroups.com
Not really: a table literal can be copied/instantiated much faster without using Lua bytecode interpretation; this depends only on the Lua compiler implementation used.

Consider also this code:

local x, y
function f() return {x, y} end
x = 1, y = 2
local A = f()
local B = f()
x = 3, y = 4
local C = f()

Note that there's also a pseudo-literal table constructor in f() which is bound in scope to a closure starting with the context where local x and y are defined: is that code supposed to return the same literal?
* Maybe for A and B (where A[1]==B[1]==1 and A[2]==B[2]==1).
* But then look at C, the values of x and y have changed when f() is called, so C[1]=3, C[2]=4.
* This means that each function call must instantiate a separate table; however the compiler could still construct a hidden literal for {x,y}, bound to the closure where x,y are defined, using accessors: the instantiation would still need to replace the references to x,y by their effective value, and in that case it's just simpler to generate the code that builds {x,y} with normal Lua evaluations.

The optimization using constant pools is possible only if the table constructor does not depend on external variables or on local variables whose values are not constant within the function making the instantiation. This requires data flow analysis by the compiler (something the the standard Lua compiler will probably never do, but that optimized Lua VM implementation may want to perform to detect when optimizations are possible, like the extreme optimizations made in modern Javascript engines; for now it is not a goal of the reference Lua compiler, but it is trivial for strings and scalars, and for table constructors containing only strings and scalars (something that is very frequent in many Lua projects that contain lot of constant lookup tables, e.g. tables generated for finite state machines, or stable reference datasets or geometric models, historical datasets defined in reusable Lua modules and libraries).

--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages