Skip to content

Commit fe4aebd

Browse files
authored
fix(virtualmachine): preserve nils in varargs and multiret (#7)
Avoid `table.insert` and `unpack({...})` patterns that drop nils by using a pack helper `(select('#', ...))` and `unpack` with explicit bounds. Fixes argument/return handling for varargs, `CALL`/`TAILCALL`, and `RETURN` in cases where values include nil.
1 parent 4e47e34 commit fe4aebd

File tree

1 file changed

+18
-42
lines changed

1 file changed

+18
-42
lines changed

the-tiny-lua-compiler.lua

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3741,6 +3741,10 @@ function VirtualMachine:getLength(...)
37413741
return select("#", ...)
37423742
end
37433743

3744+
local function pack(...)
3745+
return select("#", ...), { ... }
3746+
end
3747+
37443748
function VirtualMachine:pushClosure(closure)
37453749
closure = {
37463750
nupvalues = closure.nupvalues or 0,
@@ -3786,8 +3790,7 @@ function VirtualMachine:executeClosure(...)
37863790
stack[paramIdx - 1] = params[paramIdx]
37873791
end
37883792
if isVararg then
3789-
vararg = { select(numparams + 1, ...) }
3790-
varargLen = self:getLength(unpack(vararg))
3793+
varargLen, vararg = pack(select(numparams + 1, ...))
37913794
stack[numparams] = vararg -- Implicit "arg" argument.
37923795
end
37933796

@@ -4010,48 +4013,28 @@ function VirtualMachine:executeClosure(...)
40104013
-- Call a closure (function) with arguments and handle returns.
40114014
elseif opcode == "CALL" then
40124015
local func = stack[a]
4013-
local args = {}
4014-
local nArgs
40154016
if b ~= USE_CURRENT_TOP then
4016-
nArgs = b - 1
4017-
for index = 1, nArgs do
4018-
table.insert(args, stack[a + index])
4019-
end
4020-
else
4021-
nArgs = top - (a + 1)
4022-
for index = a + 1, top - 1 do
4023-
table.insert(args, stack[index])
4024-
end
4017+
top = a + b
40254018
end
40264019

4027-
local returns = { func(unpack(args)) }
4020+
local nReturns, returns = pack(func(unpack(stack, a + 1, top - 1)))
40284021

40294022
if c ~= USE_CURRENT_TOP then
4030-
for index = 0, c - 2 do
4031-
stack[a + index] = returns[index + 1]
4032-
end
4023+
nReturns = c - 1
40334024
else
40344025
-- Multi-return: push all results onto the stack.
4035-
local nReturns = self:getLength(unpack(returns))
40364026
top = a + nReturns
4037-
for index = 1, nReturns do
4038-
stack[a + index - 1] = returns[index]
4039-
end
4027+
end
4028+
for index = 1, nReturns do
4029+
stack[a + index - 1] = returns[index]
40404030
end
40414031

40424032
-- OP_TAILCALL [A, B, C] return R(A)(R(A+1), ... ,R(A+B-1))
40434033
-- Perform a tail call to a closure (function).
40444034
elseif opcode == "TAILCALL" then
40454035
local func = stack[a]
4046-
local args = {}
40474036
if b ~= USE_CURRENT_TOP then
4048-
for reg = a + 1, a + b - 1 do
4049-
table.insert(args, stack[reg])
4050-
end
4051-
else
4052-
for reg = a + 1, a + top do
4053-
table.insert(args, stack[reg])
4054-
end
4037+
top = a + b
40554038
end
40564039

40574040
-- Continuation of original implementation:
@@ -4068,23 +4051,16 @@ function VirtualMachine:executeClosure(...)
40684051
-- Since TAILCALL always comes before RETURN,
40694052
-- we can just return the function call results directly.
40704053

4071-
return func(unpack(args))
4054+
return func(unpack(stack, a + 1, top - 1))
40724055

40734056
-- OP_RETURN [A, B] return R(A), ... ,R(A+B-2)
40744057
-- Return values from function call.
40754058
elseif opcode == "RETURN" then
4076-
local returns = {}
4077-
if b == USE_CURRENT_TOP then
4078-
for reg = a, top do
4079-
table.insert(returns, stack[reg])
4080-
end
4081-
else
4082-
for reg = a, a + b - 2 do
4083-
table.insert(returns, stack[reg])
4084-
end
4059+
if b ~= USE_CURRENT_TOP then
4060+
top = a + b - 1
40854061
end
40864062

4087-
return unpack(returns)
4063+
return unpack(stack, a, top - 1)
40884064

40894065
-- OP_FORLOOP [A, sBx] R(A)+=R(A+2)
40904066
-- if R(A) <?= R(A+1) then { pc+=sBx R(A+3)=R(A) }
@@ -4251,10 +4227,10 @@ function VirtualMachine:executeClosure(...)
42514227
-- of code.
42524228
stack[a] = function(...)
42534229
self:pushClosure(tClosure)
4254-
local returns = { self:executeClosure(...) }
4230+
local nReturns, returns = pack(self:executeClosure(...))
42554231
self:pushClosure(closure)
42564232

4257-
return unpack(returns)
4233+
return unpack(returns, 1, nReturns)
42584234
end
42594235

42604236
-- OP_VARARG [A, B] R(A), R(A+1), ..., R(A+B-1) = vararg

0 commit comments

Comments
 (0)