Re: How come simple "closures" aren't compiled?
- From: Luke Gorrie <luke@xxxxxxxx>
- To: luajit@xxxxxxxxxxxxx
- Date: Sun, 4 Dec 2016 15:43:43 +0100
On 3 December 2016 at 11:50, Las <lasssafin@xxxxxxxxx> wrote:
For example:
local n = 0;
local f = function() return 1 end
n = f();
Couldn't f be compiled pretty easily, since it doesn't depend on any
upvalues?
This code can JIT but there are a couple of reasons it did not here:
The JIT waits until a function has been called often enough to become "hot"
before it bothers to compile it;
In practice most functions are not compiled in isolation but rather inlined
into a larger "trace" and compiled together with their callers.
If you want to force the JIT to compile the f() function in isolation then
you could change the example to call it in a loop and also ensure that the
loop itself is not compiled (because then it would inline f() instead of
compiling it separately):
-- simple.lua
local n = 0;
local f = function() return 1 end
-- Create a function that will call f() in a loop
local loop = function ()
for i = 1, 1000 do
n = f()
end
end
-- Disable JIT for the loop (to avoid noise.)
jit.off(loop)
-- Run the loop.
loop()
This will generate machine code for f():
$ ./luajit -jdump simple.lua
---- TRACE 1 start simple.lua:2
0001 KSHORT 0 1
0002 RET1 0 2
---- TRACE 1 IR
---- TRACE 1 mcode 42
0bcbffcf mov dword [0x405ed410], 0x1
0bcbffda movsd xmm7, [0x40604d68]
0bcbffe3 movsd [rdx], xmm7
0bcbffe7 xor eax, eax
0bcbffe9 mov ebx, 0x405f5300
0bcbffee mov r14d, 0x405edfe0
0bcbfff4 jmp 0x00420eb9
---- TRACE 1 stop -> return
You could make the example slightly more juicy by instead calling f() in a
loop, summing the return values, and allowing the JIT to operate on the
loop:
-- simple2.lua
local n = 0;
local f = function() return 1 end
for i = 1, 100 do n = n + f() end
Then the whole loop, including the inlined call to f(), will compile into
these four instructions:
->LOOP:
0bcbffe0 addsd xmm7, xmm0
0bcbffe4 add ebp, +0x01
0bcbffe7 cmp ebp, 0x3b9aca00
0bcbffed jle 0x0bcbffe0 ->LOOP
where the first instruction (addsd xmm7, xmm0) is the entire code for the
statement n = n + f().
That is not bad: calling your function, returning its result, and adding it
to the accumulator all with one instruction :-)
Cheers,
-Luke
Other related posts: