Skip to content

Commit 3fa08d6

Browse files
authored
Merge pull request #53 from Akeit0/fix-closure-jmp
Fix: closure upvalues
2 parents 55d8f1a + c4d560f commit 3fa08d6

File tree

3 files changed

+38
-22
lines changed

3 files changed

+38
-22
lines changed

src/Lua/CodeAnalysis/Compilation/LuaCompiler.cs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -255,23 +255,26 @@ public bool VisitTableConstructorExpressionNode(TableConstructorExpressionNode n
255255
// For the last element, we need to take into account variable arguments and multiple return values.
256256
if (listItem == lastField)
257257
{
258+
bool isFixedItems = true;
258259
switch (listItem.Expression)
259260
{
260261
case CallFunctionExpressionNode call:
261262
CompileCallFunctionExpression(call, context, false, -1);
263+
isFixedItems = false;
262264
break;
263265
case CallTableMethodExpressionNode method:
264266
CompileTableMethod(method, context, false, -1);
265267
break;
266268
case VariableArgumentsExpressionNode varArg:
267269
CompileVariableArgumentsExpression(varArg, context, -1);
270+
isFixedItems = false;
268271
break;
269272
default:
270273
listItem.Expression.Accept(this, context);
271274
break;
272275
}
273276

274-
context.PushInstruction(Instruction.SetList(tableRegisterIndex, 0, arrayBlock), listItem.Position);
277+
context.PushInstruction(Instruction.SetList(tableRegisterIndex, (ushort)(isFixedItems ? context.StackTopPosition - tableRegisterIndex : 0), arrayBlock), listItem.Position);
275278
currentArrayChunkSize = 0;
276279
}
277280
else
@@ -635,7 +638,7 @@ public bool VisitTableMethodDeclarationStatementNode(TableMethodDeclarationState
635638
// assign global variable
636639
var first = node.MemberPath[0];
637640
var tableIndex = GetOrLoadIdentifier(first.Name, context, first.Position, true);
638-
641+
639642
for (int i = 1; i < node.MemberPath.Length - 1; i++)
640643
{
641644
var member = node.MemberPath[i];
@@ -736,7 +739,7 @@ public bool VisitIfStatementNode(IfStatementNode node, ScopeCompilationContext c
736739
{
737740
using var endJumpIndexList = new PooledList<int>(8);
738741
var hasElse = node.ElseNodes.Length > 0;
739-
742+
var stackPositionToClose = (byte)(context.StackPosition + 1);
740743
// if
741744
using (var scopeContext = context.CreateChildScope())
742745
{
@@ -750,15 +753,15 @@ public bool VisitIfStatementNode(IfStatementNode node, ScopeCompilationContext c
750753
childNode.Accept(this, scopeContext);
751754
}
752755

756+
stackPositionToClose = scopeContext.HasCapturedLocalVariables ? stackPositionToClose : (byte)0;
753757
if (hasElse)
754758
{
755759
endJumpIndexList.Add(scopeContext.Function.Instructions.Length);
756-
var a = scopeContext.HasCapturedLocalVariables ? scopeContext.StackPosition : (byte)0;
757-
scopeContext.PushInstruction(Instruction.Jmp(a, 0), node.Position, true);
760+
scopeContext.PushInstruction(Instruction.Jmp(stackPositionToClose, 0), node.Position, true);
758761
}
759762
else
760763
{
761-
scopeContext.TryPushCloseUpValue(scopeContext.StackPosition, node.Position);
764+
scopeContext.TryPushCloseUpValue(stackPositionToClose, node.Position);
762765
}
763766

764767
scopeContext.Function.Instructions[ifPosition].SBx = scopeContext.Function.Instructions.Length - 1 - ifPosition;
@@ -779,16 +782,16 @@ public bool VisitIfStatementNode(IfStatementNode node, ScopeCompilationContext c
779782
childNode.Accept(this, scopeContext);
780783
}
781784

785+
stackPositionToClose = scopeContext.HasCapturedLocalVariables ? stackPositionToClose : (byte)0;
782786
// skip if node doesn't have else statements
783787
if (hasElse)
784788
{
785789
endJumpIndexList.Add(scopeContext.Function.Instructions.Length);
786-
var a = scopeContext.HasCapturedLocalVariables ? scopeContext.StackPosition : (byte)0;
787-
scopeContext.PushInstruction(Instruction.Jmp(a, 0), node.Position);
790+
scopeContext.PushInstruction(Instruction.Jmp(stackPositionToClose, 0), node.Position);
788791
}
789792
else
790793
{
791-
scopeContext.TryPushCloseUpValue(scopeContext.StackPosition, node.Position);
794+
scopeContext.TryPushCloseUpValue(stackPositionToClose, node.Position);
792795
}
793796

794797
scopeContext.Function.Instructions[elseifPosition].SBx = scopeContext.Function.Instructions.Length - 1 - elseifPosition;
@@ -821,14 +824,14 @@ public bool VisitRepeatStatementNode(RepeatStatementNode node, ScopeCompilationC
821824
context.Function.LoopLevel++;
822825

823826
using var scopeContext = context.CreateChildScope();
824-
827+
var stackPosition = scopeContext.StackPosition;
825828
foreach (var childNode in node.Nodes)
826829
{
827830
childNode.Accept(this, scopeContext);
828831
}
829832

830833
CompileConditionNode(node.ConditionNode, scopeContext, true);
831-
var a = scopeContext.HasCapturedLocalVariables ? scopeContext.StackPosition : (byte)0;
834+
var a = scopeContext.HasCapturedLocalVariables ? (byte)(stackPosition + 1) : (byte)0;
832835
scopeContext.PushInstruction(Instruction.Jmp(a, startIndex - scopeContext.Function.Instructions.Length - 1), node.Position);
833836
scopeContext.TryPushCloseUpValue(scopeContext.StackPosition, node.Position);
834837

@@ -848,6 +851,7 @@ public bool VisitWhileStatementNode(WhileStatementNode node, ScopeCompilationCon
848851
context.Function.LoopLevel++;
849852

850853
using var scopeContext = context.CreateChildScope();
854+
var stackPosition = scopeContext.StackPosition;
851855

852856
foreach (var childNode in node.Nodes)
853857
{
@@ -860,7 +864,7 @@ public bool VisitWhileStatementNode(WhileStatementNode node, ScopeCompilationCon
860864
scopeContext.Function.Instructions[conditionIndex].SBx = scopeContext.Function.Instructions.Length - 1 - conditionIndex;
861865

862866
CompileConditionNode(node.ConditionNode, scopeContext, false);
863-
var a = scopeContext.HasCapturedLocalVariables ? scopeContext.StackPosition : (byte)0;
867+
var a = scopeContext.HasCapturedLocalVariables ? (byte)(1 + stackPosition) : (byte)0;
864868
scopeContext.PushInstruction(Instruction.Jmp(a, conditionIndex - context.Function.Instructions.Length), node.Position);
865869
scopeContext.TryPushCloseUpValue(scopeContext.StackPosition, node.Position);
866870

src/Lua/Runtime/Closure.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Runtime.CompilerServices;
12
using Lua.Internal;
23

34
namespace Lua.Runtime;
@@ -16,30 +17,41 @@ public Closure(LuaState state, Chunk proto, LuaTable? environment = null)
1617
for (int i = 0; i < proto.UpValues.Length; i++)
1718
{
1819
var description = proto.UpValues[i];
19-
var upValue = GetUpValueFromDescription(state, environment == null ? state.EnvUpValue : UpValue.Closed(environment), proto, description, 1);
20+
var upValue = GetUpValueFromDescription(state, state.CurrentThread, environment == null ? state.EnvUpValue : UpValue.Closed(environment), description);
2021
upValues.Add(upValue);
2122
}
2223
}
2324

2425
public Chunk Proto => proto;
2526
public ReadOnlySpan<UpValue> UpValues => upValues.AsSpan();
2627

27-
static UpValue GetUpValueFromDescription(LuaState state, UpValue envUpValue, Chunk proto, UpValueInfo description, int depth)
28+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
29+
internal LuaValue GetUpValue(int index)
30+
{
31+
return upValues[index].GetValue();
32+
}
33+
34+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
35+
internal void SetUpValue(int index, LuaValue value)
36+
{
37+
upValues[index].SetValue(value);
38+
}
39+
40+
static UpValue GetUpValueFromDescription(LuaState state, LuaThread thread, UpValue envUpValue, UpValueInfo description)
2841
{
2942
if (description.IsInRegister)
3043
{
31-
var thread = state.CurrentThread;
32-
var callStack = thread.GetCallStackFrames();
33-
var frame = callStack[^depth];
34-
return state.GetOrAddUpValue(thread, frame.Base + description.Index);
44+
return state.GetOrAddUpValue(thread, thread.GetCallStackFrames()[^1].Base + description.Index);
3545
}
36-
else if (description.Index == -1) // -1 is global environment
46+
if (description.Index == -1) // -1 is global environment
3747
{
3848
return envUpValue;
3949
}
40-
else
50+
if (thread.GetCallStackFrames()[^1].Function is Closure parentClosure)
4151
{
42-
return GetUpValueFromDescription(state, envUpValue, proto.Parent!, proto.Parent!.UpValues[description.Index], depth + 1);
52+
return parentClosure.UpValues[description.Index];
4353
}
54+
55+
throw new Exception();
4456
}
4557
}

src/Lua/Runtime/LuaVirtualMachine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ internal async static ValueTask<int> ExecuteClosureAsync(LuaState state, CallSta
532532
pc += instruction.SBx;
533533
if (instruction.A != 0)
534534
{
535-
state.CloseUpValues(thread, instruction.A - 1);
535+
state.CloseUpValues(thread, frame.Base + instruction.A - 1);
536536
}
537537
break;
538538
case OpCode.Eq:

0 commit comments

Comments
 (0)