/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LocalAccess.cs

https://github.com/dotnet/runtime · C# · 465 lines · 372 code · 88 blank · 5 comment · 12 complexity · 7a70f1525a77961814e5174f33787cae MD5 · raw file

  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Dynamic.Utils;
  6. using System.Reflection;
  7. using System.Runtime.CompilerServices;
  8. namespace System.Linq.Expressions.Interpreter
  9. {
  10. internal interface IBoxableInstruction
  11. {
  12. Instruction? BoxIfIndexMatches(int index);
  13. }
  14. internal abstract class LocalAccessInstruction : Instruction
  15. {
  16. internal readonly int _index;
  17. protected LocalAccessInstruction(int index)
  18. {
  19. _index = index;
  20. }
  21. public override string ToDebugString(int instructionIndex, object? cookie, Func<int, int> labelIndexer, IReadOnlyList<object>? objects)
  22. {
  23. return cookie == null ?
  24. InstructionName + "(" + _index + ")" :
  25. InstructionName + "(" + cookie + ": " + _index + ")";
  26. }
  27. }
  28. #region Load
  29. internal sealed class LoadLocalInstruction : LocalAccessInstruction, IBoxableInstruction
  30. {
  31. internal LoadLocalInstruction(int index)
  32. : base(index)
  33. {
  34. }
  35. public override int ProducedStack => 1;
  36. public override string InstructionName => "LoadLocal";
  37. public override int Run(InterpretedFrame frame)
  38. {
  39. frame.Data[frame.StackIndex++] = frame.Data[_index];
  40. return 1;
  41. }
  42. public Instruction? BoxIfIndexMatches(int index)
  43. {
  44. return (index == _index) ? InstructionList.LoadLocalBoxed(index) : null;
  45. }
  46. }
  47. internal sealed class LoadLocalBoxedInstruction : LocalAccessInstruction
  48. {
  49. internal LoadLocalBoxedInstruction(int index)
  50. : base(index)
  51. {
  52. }
  53. public override int ProducedStack => 1;
  54. public override string InstructionName => "LoadLocalBox";
  55. public override int Run(InterpretedFrame frame)
  56. {
  57. var box = (IStrongBox)frame.Data[_index]!;
  58. frame.Data[frame.StackIndex++] = box.Value;
  59. return 1;
  60. }
  61. }
  62. internal sealed class LoadLocalFromClosureInstruction : LocalAccessInstruction
  63. {
  64. internal LoadLocalFromClosureInstruction(int index)
  65. : base(index)
  66. {
  67. }
  68. public override int ProducedStack => 1;
  69. public override string InstructionName => "LoadLocalClosure";
  70. public override int Run(InterpretedFrame frame)
  71. {
  72. IStrongBox box = frame.Closure![_index];
  73. frame.Data[frame.StackIndex++] = box.Value;
  74. return 1;
  75. }
  76. }
  77. internal sealed class LoadLocalFromClosureBoxedInstruction : LocalAccessInstruction
  78. {
  79. internal LoadLocalFromClosureBoxedInstruction(int index)
  80. : base(index)
  81. {
  82. }
  83. public override int ProducedStack => 1;
  84. public override string InstructionName => "LoadLocal";
  85. public override int Run(InterpretedFrame frame)
  86. {
  87. IStrongBox box = frame.Closure![_index];
  88. frame.Data[frame.StackIndex++] = box;
  89. return 1;
  90. }
  91. }
  92. #endregion
  93. #region Store, Assign
  94. internal sealed class AssignLocalInstruction : LocalAccessInstruction, IBoxableInstruction
  95. {
  96. internal AssignLocalInstruction(int index)
  97. : base(index)
  98. {
  99. }
  100. public override int ConsumedStack => 1;
  101. public override int ProducedStack => 1;
  102. public override string InstructionName => "AssignLocal";
  103. public override int Run(InterpretedFrame frame)
  104. {
  105. frame.Data[_index] = frame.Peek();
  106. return 1;
  107. }
  108. public Instruction? BoxIfIndexMatches(int index)
  109. {
  110. return (index == _index) ? InstructionList.AssignLocalBoxed(index) : null;
  111. }
  112. }
  113. internal sealed class StoreLocalInstruction : LocalAccessInstruction, IBoxableInstruction
  114. {
  115. internal StoreLocalInstruction(int index)
  116. : base(index)
  117. {
  118. }
  119. public override int ConsumedStack => 1;
  120. public override string InstructionName => "StoreLocal";
  121. public override int Run(InterpretedFrame frame)
  122. {
  123. frame.Data[_index] = frame.Pop();
  124. return 1;
  125. }
  126. public Instruction? BoxIfIndexMatches(int index)
  127. {
  128. return (index == _index) ? InstructionList.StoreLocalBoxed(index) : null;
  129. }
  130. }
  131. internal sealed class AssignLocalBoxedInstruction : LocalAccessInstruction
  132. {
  133. internal AssignLocalBoxedInstruction(int index)
  134. : base(index)
  135. {
  136. }
  137. public override int ConsumedStack => 1;
  138. public override int ProducedStack => 1;
  139. public override string InstructionName => "AssignLocalBox";
  140. public override int Run(InterpretedFrame frame)
  141. {
  142. var box = (IStrongBox)frame.Data[_index]!;
  143. box.Value = frame.Peek();
  144. return 1;
  145. }
  146. }
  147. internal sealed class StoreLocalBoxedInstruction : LocalAccessInstruction
  148. {
  149. internal StoreLocalBoxedInstruction(int index)
  150. : base(index)
  151. {
  152. }
  153. public override int ConsumedStack => 1;
  154. public override string InstructionName => "StoreLocalBox";
  155. public override int Run(InterpretedFrame frame)
  156. {
  157. var box = (IStrongBox)frame.Data[_index]!;
  158. box.Value = frame.Data[--frame.StackIndex];
  159. return 1;
  160. }
  161. }
  162. internal sealed class AssignLocalToClosureInstruction : LocalAccessInstruction
  163. {
  164. internal AssignLocalToClosureInstruction(int index)
  165. : base(index)
  166. {
  167. }
  168. public override int ConsumedStack => 1;
  169. public override int ProducedStack => 1;
  170. public override string InstructionName => "AssignLocalClosure";
  171. public override int Run(InterpretedFrame frame)
  172. {
  173. IStrongBox box = frame.Closure![_index];
  174. box.Value = frame.Peek();
  175. return 1;
  176. }
  177. }
  178. internal sealed class ValueTypeCopyInstruction : Instruction
  179. {
  180. public static readonly ValueTypeCopyInstruction Instruction = new ValueTypeCopyInstruction();
  181. public override int ConsumedStack => 1;
  182. public override int ProducedStack => 1;
  183. public override string InstructionName => "ValueTypeCopy";
  184. public override int Run(InterpretedFrame frame)
  185. {
  186. object? o = frame.Pop();
  187. frame.Push(o == null ? o : RuntimeHelpers.GetObjectValue(o));
  188. return 1;
  189. }
  190. }
  191. #endregion
  192. #region Initialize
  193. internal abstract class InitializeLocalInstruction : LocalAccessInstruction
  194. {
  195. internal InitializeLocalInstruction(int index)
  196. : base(index)
  197. {
  198. }
  199. internal sealed class Reference : InitializeLocalInstruction, IBoxableInstruction
  200. {
  201. internal Reference(int index)
  202. : base(index)
  203. {
  204. }
  205. public override int Run(InterpretedFrame frame)
  206. {
  207. frame.Data[_index] = null;
  208. return 1;
  209. }
  210. public Instruction? BoxIfIndexMatches(int index)
  211. {
  212. return (index == _index) ? InstructionList.InitImmutableRefBox(index) : null;
  213. }
  214. public override string InstructionName => "InitRef";
  215. }
  216. internal sealed class ImmutableValue : InitializeLocalInstruction, IBoxableInstruction
  217. {
  218. private readonly object _defaultValue;
  219. internal ImmutableValue(int index, object defaultValue)
  220. : base(index)
  221. {
  222. Debug.Assert(defaultValue != null);
  223. _defaultValue = defaultValue;
  224. }
  225. public override int Run(InterpretedFrame frame)
  226. {
  227. frame.Data[_index] = _defaultValue;
  228. return 1;
  229. }
  230. public Instruction? BoxIfIndexMatches(int index)
  231. {
  232. return (index == _index) ? new ImmutableBox(index, _defaultValue) : null;
  233. }
  234. public override string InstructionName => "InitImmutableValue";
  235. }
  236. internal sealed class ImmutableBox : InitializeLocalInstruction
  237. {
  238. // immutable value:
  239. private readonly object _defaultValue;
  240. internal ImmutableBox(int index, object defaultValue)
  241. : base(index)
  242. {
  243. _defaultValue = defaultValue;
  244. }
  245. public override int Run(InterpretedFrame frame)
  246. {
  247. frame.Data[_index] = new StrongBox<object>(_defaultValue);
  248. return 1;
  249. }
  250. public override string InstructionName => "InitImmutableBox";
  251. }
  252. internal sealed class ImmutableRefBox : InitializeLocalInstruction
  253. {
  254. // immutable value:
  255. internal ImmutableRefBox(int index)
  256. : base(index)
  257. {
  258. }
  259. public override int Run(InterpretedFrame frame)
  260. {
  261. frame.Data[_index] = new StrongBox<object>();
  262. return 1;
  263. }
  264. public override string InstructionName => "InitImmutableBox";
  265. }
  266. internal sealed class ParameterBox : InitializeLocalInstruction
  267. {
  268. public ParameterBox(int index)
  269. : base(index)
  270. {
  271. }
  272. public override int Run(InterpretedFrame frame)
  273. {
  274. frame.Data[_index] = new StrongBox<object?>(frame.Data[_index]);
  275. return 1;
  276. }
  277. public override string InstructionName => "InitParameterBox";
  278. }
  279. internal sealed class Parameter : InitializeLocalInstruction, IBoxableInstruction
  280. {
  281. internal Parameter(int index)
  282. : base(index)
  283. {
  284. }
  285. public override int Run(InterpretedFrame frame)
  286. {
  287. // nop
  288. return 1;
  289. }
  290. public Instruction? BoxIfIndexMatches(int index)
  291. {
  292. if (index == _index)
  293. {
  294. return InstructionList.ParameterBox(index);
  295. }
  296. return null;
  297. }
  298. public override string InstructionName => "InitParameter";
  299. }
  300. internal sealed class MutableValue : InitializeLocalInstruction, IBoxableInstruction
  301. {
  302. private readonly Type _type;
  303. internal MutableValue(int index, Type type)
  304. : base(index)
  305. {
  306. _type = type;
  307. }
  308. public override int Run(InterpretedFrame frame)
  309. {
  310. try
  311. {
  312. frame.Data[_index] = Activator.CreateInstance(_type);
  313. }
  314. catch (TargetInvocationException e)
  315. {
  316. ExceptionHelpers.UnwrapAndRethrow(e);
  317. throw ContractUtils.Unreachable;
  318. }
  319. return 1;
  320. }
  321. public Instruction? BoxIfIndexMatches(int index)
  322. {
  323. return (index == _index) ? new MutableBox(index, _type) : null;
  324. }
  325. public override string InstructionName => "InitMutableValue";
  326. }
  327. internal sealed class MutableBox : InitializeLocalInstruction
  328. {
  329. private readonly Type _type;
  330. internal MutableBox(int index, Type type)
  331. : base(index)
  332. {
  333. _type = type;
  334. }
  335. public override int Run(InterpretedFrame frame)
  336. {
  337. object? value;
  338. try
  339. {
  340. value = Activator.CreateInstance(_type);
  341. }
  342. catch (TargetInvocationException e)
  343. {
  344. ExceptionHelpers.UnwrapAndRethrow(e);
  345. throw ContractUtils.Unreachable;
  346. }
  347. frame.Data[_index] = new StrongBox<object?>(value);
  348. return 1;
  349. }
  350. public override string InstructionName => "InitMutableBox";
  351. }
  352. }
  353. #endregion
  354. #region RuntimeVariables
  355. internal sealed class RuntimeVariablesInstruction : Instruction
  356. {
  357. private readonly int _count;
  358. public RuntimeVariablesInstruction(int count)
  359. {
  360. _count = count;
  361. }
  362. public override int ProducedStack => 1;
  363. public override int ConsumedStack => _count;
  364. public override string InstructionName => "GetRuntimeVariables";
  365. public override int Run(InterpretedFrame frame)
  366. {
  367. var ret = new IStrongBox[_count];
  368. for (int i = ret.Length - 1; i >= 0; i--)
  369. {
  370. ret[i] = (IStrongBox)frame.Pop()!;
  371. }
  372. frame.Push(RuntimeVariables.Create(ret));
  373. return 1;
  374. }
  375. }
  376. #endregion
  377. }