ScopeCompilationContext.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using System.Collections.Concurrent;
  2. using System.Runtime.CompilerServices;
  3. using Lua.Internal;
  4. using Lua.Runtime;
  5. namespace Lua.CodeAnalysis.Compilation;
  6. public class ScopeCompilationContext : IDisposable
  7. {
  8. static class Pool
  9. {
  10. static ConcurrentStack<ScopeCompilationContext> stack = new();
  11. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  12. public static ScopeCompilationContext Rent()
  13. {
  14. if (!stack.TryPop(out var context))
  15. {
  16. context = new();
  17. }
  18. return context;
  19. }
  20. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  21. public static void Return(ScopeCompilationContext context)
  22. {
  23. context.Reset();
  24. stack.Push(context);
  25. }
  26. }
  27. readonly Dictionary<ReadOnlyMemory<char>, LocalVariableDescription> localVariables = new(256, Utf16StringMemoryComparer.Default);
  28. readonly Dictionary<ReadOnlyMemory<char>, LabelDescription> labels = new(32, Utf16StringMemoryComparer.Default);
  29. byte lastLocalVariableIndex;
  30. public byte StackStartPosition { get; private set; }
  31. public byte StackPosition { get; set; }
  32. public byte StackTopPosition
  33. {
  34. get => (byte)(StackPosition - 1);
  35. }
  36. public bool HasCapturedLocalVariables { get; internal set; }
  37. /// <summary>
  38. /// Function context
  39. /// </summary>
  40. public FunctionCompilationContext Function { get; internal set; } = default!;
  41. /// <summary>
  42. /// Parent scope context
  43. /// </summary>
  44. public ScopeCompilationContext? Parent { get; private set; }
  45. public ScopeCompilationContext CreateChildScope()
  46. {
  47. var childScope = Pool.Rent();
  48. childScope.Parent = this;
  49. childScope.Function = Function;
  50. childScope.StackStartPosition = StackPosition;
  51. childScope.StackPosition = StackPosition;
  52. return childScope;
  53. }
  54. public FunctionCompilationContext CreateChildFunction()
  55. {
  56. var context = FunctionCompilationContext.Create(this);
  57. return context;
  58. }
  59. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  60. public void PushInstruction(in Instruction instruction, SourcePosition position, bool incrementStackPosition = false)
  61. {
  62. Function.PushOrMergeInstruction(lastLocalVariableIndex, instruction, position, ref incrementStackPosition);
  63. if (incrementStackPosition)
  64. {
  65. StackPosition++;
  66. }
  67. }
  68. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  69. public void TryPushCloseUpValue(byte top, SourcePosition position)
  70. {
  71. if (HasCapturedLocalVariables && top != 0)
  72. {
  73. Function.PushInstruction(Instruction.Jmp(top, 0), position);
  74. }
  75. }
  76. /// <summary>
  77. /// Add new local variable.
  78. /// </summary>
  79. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  80. public void AddLocalVariable(ReadOnlyMemory<char> name, LocalVariableDescription description, bool markAsLastLocalVariable = true)
  81. {
  82. localVariables[name] = description;
  83. lastLocalVariableIndex = description.RegisterIndex;
  84. }
  85. /// <summary>
  86. /// Gets the local variable in scope.
  87. /// </summary>
  88. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  89. public bool TryGetLocalVariable(ReadOnlyMemory<char> name, out LocalVariableDescription description)
  90. {
  91. if (localVariables.TryGetValue(name, out description)) return true;
  92. // Find local variables defined in the same function
  93. if (Parent != null)
  94. {
  95. return Parent.TryGetLocalVariable(name, out description);
  96. }
  97. return false;
  98. }
  99. /// <summary>
  100. /// Gets the local variable in this scope.
  101. /// </summary>
  102. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  103. public bool TryGetLocalVariableInThisScope(ReadOnlyMemory<char> name, out LocalVariableDescription description)
  104. {
  105. return localVariables.TryGetValue(name, out description);
  106. }
  107. /// <summary>
  108. /// Add new label.
  109. /// </summary>
  110. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  111. public void AddLabel(LabelDescription description)
  112. {
  113. labels.Add(description.Name, description);
  114. }
  115. /// <summary>
  116. /// Gets the label in scope.
  117. /// </summary>
  118. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  119. public bool TryGetLabel(ReadOnlyMemory<char> name, out LabelDescription description)
  120. {
  121. if (labels.TryGetValue(name, out description)) return true;
  122. // Find labels defined in the same function
  123. if (Parent != null)
  124. {
  125. return Parent.TryGetLabel(name, out description);
  126. }
  127. return false;
  128. }
  129. /// <summary>
  130. /// Resets the values ​​held in the context.
  131. /// </summary>
  132. public void Reset()
  133. {
  134. Parent = null;
  135. StackStartPosition = 0;
  136. StackPosition = 0;
  137. HasCapturedLocalVariables = false;
  138. localVariables.Clear();
  139. labels.Clear();
  140. lastLocalVariableIndex = 0;
  141. }
  142. /// <summary>
  143. /// Returns the context object to the pool.
  144. /// </summary>
  145. public void Dispose()
  146. {
  147. Function = null!;
  148. Pool.Return(this);
  149. }
  150. }