The compiler currently routes all non-constructor table accesses via Dispatch, in order to correctly handle possible metamethod calls. When it is known that the table cannot have a metatable, its accesses may be raw.
Raw table accesses are preferable to non-raw accesses, since the former does not require the insertion of resumption points, making the generated bytecode smaller and simpler (fewer entry points), giving the JVM more opportunities to perform JIT optimisations.
Consider the following Lua snippet (the first 80 numbers in the Fibonacci series):
local t = {1, 1}
for i = 3, 80 do
t[i] = t[i - 2] + t[i - 1]
end
Here, all accesses of t can be raw, since the freshly-allocated t does not have a metatable, and t does not participate in any operation that may modify its metatable.
If the snippet above was followed by
for k, v in ipairs(t) do
print(k, v)
end
print(#t) -- non-raw, t escaped
then the #t operation would not be raw, since t has been passed to ipairs as an argument: and its contents including the metatable may have been modified.
How to go about this
This feature could be implemented by a simple escape analysis.
The compiler should keep track of the "status" of table locals and temporaries. Tables are constructed fresh; table operations (t[x], t[x] = y and #t) on fresh tables are raw and do not change the table status. Whenever a table participates in a call (as an argument, e.g., f(t)) or in operation that may involve a metamethod call (e.g., t + 1) their status changes to dirty. Table operations on dirty tables are invoked via Dispatch, i.e., with checking for metamethods.
The compiler currently routes all non-constructor table accesses via
Dispatch
, in order to correctly handle possible metamethod calls. When it is known that the table cannot have a metatable, its accesses may be raw.Raw table accesses are preferable to non-raw accesses, since the former does not require the insertion of resumption points, making the generated bytecode smaller and simpler (fewer entry points), giving the JVM more opportunities to perform JIT optimisations.
Consider the following Lua snippet (the first 80 numbers in the Fibonacci series):
Here, all accesses of
t
can be raw, since the freshly-allocatedt
does not have a metatable, andt
does not participate in any operation that may modify its metatable.If the snippet above was followed by
then the
#t
operation would not be raw, sincet
has been passed toipairs
as an argument: and its contents including the metatable may have been modified.How to go about this
This feature could be implemented by a simple escape analysis.
The compiler should keep track of the "status" of table locals and temporaries. Tables are constructed fresh; table operations (
t[x]
,t[x] = y
and#t
) on fresh tables are raw and do not change the table status. Whenever a table participates in a call (as an argument, e.g.,f(t)
) or in operation that may involve a metamethod call (e.g.,t + 1
) their status changes to dirty. Table operations on dirty tables are invoked viaDispatch
, i.e., with checking for metamethods.