Also,
AFAIK luajit tracks if upvalues are immutable or not, so couldn't closures
with only immutable upvalues be compiled too?
Perhaps you could make a new bytecode instruction for compilable function
generation?
Las
On 4 December 2016 at 18:18, Las <lasssafin@xxxxxxxxx> wrote:
Yeah, that's what I meant.
I know it can compile calls, but it can't compile FNEW and UCLO of simple
functions.
The reason I'm asking is because obviously such "closures" can be used to
simplify APIs.
Like:
local t = {1, 2, 3};
foreach(t, function(i, n) return n * 2 end);
assert(t[1] == 2 and t[2] == 4 and t[3] == 6);
If this was in a loop, it would perform horrendously, even though the
closure isn't actually a closure and just a normal and pure function.
Las
On 4 December 2016 at 15:48, Peter Cawley <corsix@xxxxxxxxxx> wrote:
Luke: I think the question was why FNEW and UCLO bytecodes aren't yet
supported by the JIT compiler.
On Sun, 4 Dec 2016 at 14:44, Luke Gorrie <luke@xxxxxxxx> wrote:
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