mjanicek / rembulan

Rembulan, an implementation of Lua 5.3 for the Java Virtual Machine
Apache License 2.0
163 stars 28 forks source link

Use raw table access for fresh tables in the generated code #14

Open mjanicek opened 8 years ago

mjanicek commented 8 years ago

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.