PageRenderTime 80ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/src/System.Management.Automation/engine/interpreter/InterpretedFrame.cs

https://gitlab.com/unofficial-mirrors/PowerShell
C# | 337 lines | 253 code | 56 blank | 28 comment | 21 complexity | 55e64cbb8fa85869bb98e2aabb82667a MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !CLR2
  16. #else
  17. using Microsoft.Scripting.Ast;
  18. #endif
  19. using System.Collections.Generic;
  20. using System.Diagnostics;
  21. using System.Management.Automation.Language;
  22. using System.Reflection;
  23. using System.Runtime.CompilerServices;
  24. namespace System.Management.Automation.Interpreter
  25. {
  26. internal sealed class InterpretedFrame
  27. {
  28. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  29. public static readonly ThreadLocal<InterpretedFrame> CurrentFrame = new ThreadLocal<InterpretedFrame>();
  30. internal readonly Interpreter Interpreter;
  31. internal InterpretedFrame _parent;
  32. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
  33. private int[] _continuations;
  34. private int _continuationIndex;
  35. private int _pendingContinuation;
  36. private object _pendingValue;
  37. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
  38. public readonly object[] Data;
  39. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
  40. public readonly StrongBox<object>[] Closure;
  41. public int StackIndex;
  42. public int InstructionIndex;
  43. // When a ThreadAbortException is raised from interpreted code this is the first frame that caught it.
  44. // No handlers within this handler re-abort the current thread when left.
  45. public ExceptionHandler CurrentAbortHandler;
  46. internal InterpretedFrame(Interpreter interpreter, StrongBox<object>[] closure)
  47. {
  48. Interpreter = interpreter;
  49. StackIndex = interpreter.LocalCount;
  50. Data = new object[StackIndex + interpreter.Instructions.MaxStackDepth];
  51. int c = interpreter.Instructions.MaxContinuationDepth;
  52. if (c > 0)
  53. {
  54. _continuations = new int[c];
  55. }
  56. Closure = closure;
  57. _pendingContinuation = -1;
  58. _pendingValue = Interpreter.NoValue;
  59. }
  60. public DebugInfo GetDebugInfo(int instructionIndex)
  61. {
  62. return DebugInfo.GetMatchingDebugInfo(Interpreter._debugInfos, instructionIndex);
  63. }
  64. public string Name
  65. {
  66. get { return Interpreter._name; }
  67. }
  68. #region Data Stack Operations
  69. public void Push(object value)
  70. {
  71. Data[StackIndex++] = value;
  72. }
  73. public void Push(bool value)
  74. {
  75. Data[StackIndex++] = value ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  76. }
  77. public void Push(int value)
  78. {
  79. Data[StackIndex++] = ScriptingRuntimeHelpers.Int32ToObject(value);
  80. }
  81. public object Pop()
  82. {
  83. return Data[--StackIndex];
  84. }
  85. internal void SetStackDepth(int depth)
  86. {
  87. StackIndex = Interpreter.LocalCount + depth;
  88. }
  89. public object Peek()
  90. {
  91. return Data[StackIndex - 1];
  92. }
  93. public void Dup()
  94. {
  95. int i = StackIndex;
  96. Data[i] = Data[i - 1];
  97. StackIndex = i + 1;
  98. }
  99. public ExecutionContext ExecutionContext
  100. {
  101. get { return (ExecutionContext)Data[1]; }
  102. }
  103. public FunctionContext FunctionContext
  104. {
  105. get { return (FunctionContext)Data[0]; }
  106. }
  107. #endregion
  108. #region Stack Trace
  109. public InterpretedFrame Parent
  110. {
  111. get { return _parent; }
  112. }
  113. public static bool IsInterpretedFrame(MethodBase method)
  114. {
  115. //ContractUtils.RequiresNotNull(method, "method");
  116. return method.DeclaringType == typeof(Interpreter) && method.Name == "Run";
  117. }
  118. /// <summary>
  119. /// A single interpreted frame might be represented by multiple subsequent Interpreter.Run CLR frames.
  120. /// This method filters out the duplicate CLR frames.
  121. /// </summary>
  122. public static IEnumerable<StackFrame> GroupStackFrames(IEnumerable<StackFrame> stackTrace)
  123. {
  124. bool inInterpretedFrame = false;
  125. foreach (StackFrame frame in stackTrace)
  126. {
  127. if (InterpretedFrame.IsInterpretedFrame(frame.GetMethod()))
  128. {
  129. if (inInterpretedFrame)
  130. {
  131. continue;
  132. }
  133. inInterpretedFrame = true;
  134. }
  135. else
  136. {
  137. inInterpretedFrame = false;
  138. }
  139. yield return frame;
  140. }
  141. }
  142. public IEnumerable<InterpretedFrameInfo> GetStackTraceDebugInfo()
  143. {
  144. var frame = this;
  145. do
  146. {
  147. yield return new InterpretedFrameInfo(frame.Name, frame.GetDebugInfo(frame.InstructionIndex));
  148. frame = frame.Parent;
  149. } while (frame != null);
  150. }
  151. internal void SaveTraceToException(Exception exception)
  152. {
  153. if (exception.Data[typeof(InterpretedFrameInfo)] == null)
  154. {
  155. exception.Data[typeof(InterpretedFrameInfo)] = new List<InterpretedFrameInfo>(GetStackTraceDebugInfo()).ToArray();
  156. }
  157. }
  158. public static InterpretedFrameInfo[] GetExceptionStackTrace(Exception exception)
  159. {
  160. return exception.Data[typeof(InterpretedFrameInfo)] as InterpretedFrameInfo[];
  161. }
  162. #if DEBUG
  163. internal string[] Trace
  164. {
  165. get
  166. {
  167. var trace = new List<string>();
  168. var frame = this;
  169. do
  170. {
  171. trace.Add(frame.Name);
  172. frame = frame.Parent;
  173. } while (frame != null);
  174. return trace.ToArray();
  175. }
  176. }
  177. #endif
  178. internal ThreadLocal<InterpretedFrame>.StorageInfo Enter()
  179. {
  180. var currentFrame = InterpretedFrame.CurrentFrame.GetStorageInfo();
  181. _parent = currentFrame.Value;
  182. currentFrame.Value = this;
  183. return currentFrame;
  184. }
  185. internal void Leave(ThreadLocal<InterpretedFrame>.StorageInfo currentFrame)
  186. {
  187. currentFrame.Value = _parent;
  188. }
  189. #endregion
  190. #region Continuations
  191. internal bool IsJumpHappened()
  192. {
  193. return _pendingContinuation >= 0;
  194. }
  195. public void RemoveContinuation()
  196. {
  197. _continuationIndex--;
  198. }
  199. public void PushContinuation(int continuation)
  200. {
  201. _continuations[_continuationIndex++] = continuation;
  202. }
  203. public int YieldToCurrentContinuation()
  204. {
  205. var target = Interpreter._labels[_continuations[_continuationIndex - 1]];
  206. SetStackDepth(target.StackDepth);
  207. return target.Index - InstructionIndex;
  208. }
  209. /// <summary>
  210. /// Get called from the LeaveFinallyInstruction
  211. /// </summary>
  212. public int YieldToPendingContinuation()
  213. {
  214. Debug.Assert(_pendingContinuation >= 0);
  215. RuntimeLabel pendingTarget = Interpreter._labels[_pendingContinuation];
  216. // the current continuation might have higher priority (continuationIndex is the depth of the current continuation):
  217. if (pendingTarget.ContinuationStackDepth < _continuationIndex)
  218. {
  219. RuntimeLabel currentTarget = Interpreter._labels[_continuations[_continuationIndex - 1]];
  220. SetStackDepth(currentTarget.StackDepth);
  221. return currentTarget.Index - InstructionIndex;
  222. }
  223. SetStackDepth(pendingTarget.StackDepth);
  224. if (_pendingValue != Interpreter.NoValue)
  225. {
  226. Data[StackIndex - 1] = _pendingValue;
  227. }
  228. // Set the _pendingContinuation and _pendingValue to the default values if we finally gets to the Goto target
  229. _pendingContinuation = -1;
  230. _pendingValue = Interpreter.NoValue;
  231. return pendingTarget.Index - InstructionIndex;
  232. }
  233. internal void PushPendingContinuation()
  234. {
  235. Push(_pendingContinuation);
  236. Push(_pendingValue);
  237. _pendingContinuation = -1;
  238. _pendingValue = Interpreter.NoValue;
  239. }
  240. internal void PopPendingContinuation()
  241. {
  242. _pendingValue = Pop();
  243. _pendingContinuation = (int)Pop();
  244. }
  245. private static MethodInfo s_goto;
  246. private static MethodInfo s_voidGoto;
  247. internal static MethodInfo GotoMethod
  248. {
  249. get { return s_goto ?? (s_goto = typeof(InterpretedFrame).GetMethod("Goto")); }
  250. }
  251. internal static MethodInfo VoidGotoMethod
  252. {
  253. get { return s_voidGoto ?? (s_voidGoto = typeof(InterpretedFrame).GetMethod("VoidGoto")); }
  254. }
  255. public int VoidGoto(int labelIndex)
  256. {
  257. return Goto(labelIndex, Interpreter.NoValue, gotoExceptionHandler: false);
  258. }
  259. public int Goto(int labelIndex, object value, bool gotoExceptionHandler)
  260. {
  261. // TODO: we know this at compile time (except for compiled loop):
  262. RuntimeLabel target = Interpreter._labels[labelIndex];
  263. Debug.Assert(!gotoExceptionHandler || _continuationIndex == target.ContinuationStackDepth,
  264. "When it's time to jump to the exception handler, all previous finally blocks should already be processed");
  265. if (_continuationIndex == target.ContinuationStackDepth)
  266. {
  267. SetStackDepth(target.StackDepth);
  268. if (value != Interpreter.NoValue)
  269. {
  270. Data[StackIndex - 1] = value;
  271. }
  272. return target.Index - InstructionIndex;
  273. }
  274. // if we are in the middle of executing jump we forget the previous target and replace it by a new one:
  275. _pendingContinuation = labelIndex;
  276. _pendingValue = value;
  277. return YieldToCurrentContinuation();
  278. }
  279. #endregion
  280. }
  281. }