PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/Runtime/Microsoft.Dynamic/Debugging/DebugFrame.cs

http://github.com/IronLanguages/main
C# | 416 lines | 289 code | 72 blank | 55 comment | 78 complexity | 8265fb04c5a277d1f7b4672f1a169295 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  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. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Globalization;
  20. using System.Reflection;
  21. using System.Runtime.CompilerServices;
  22. using Microsoft.Scripting.Debugging.CompilerServices;
  23. using Microsoft.Scripting.Runtime;
  24. namespace Microsoft.Scripting.Debugging {
  25. [DebuggerDisplay("FunctionInfo = {_funcInfo.Name}, CurrentSequencePointIndex = {CurrentSequencePointIndex}")]
  26. public sealed class DebugFrame {
  27. private readonly DebugThread _thread;
  28. private FunctionInfo _funcInfo;
  29. private int _stackDepth;
  30. private Exception _thrownException;
  31. private IRuntimeVariables _liftedLocals;
  32. private IDebuggableGenerator _generator;
  33. private int _lastKnownGeneratorYieldMarker = Int32.MaxValue;
  34. private bool _inTraceBack;
  35. private bool _inGeneratorLoop;
  36. private bool _forceToGeneratorLoop;
  37. private Dictionary<IList<VariableInfo>, ScopeData> _variables;
  38. // Symbol used to set "$exception" variable when exceptions are thrown
  39. private const string _exceptionVariableSymbol = "$debugException";
  40. internal DebugFrame(
  41. DebugThread thread,
  42. FunctionInfo funcInfo) {
  43. _thread = thread;
  44. _funcInfo = funcInfo;
  45. _variables = new Dictionary<IList<VariableInfo>, ScopeData>();
  46. }
  47. internal DebugFrame(
  48. DebugThread thread,
  49. FunctionInfo funcInfo,
  50. IRuntimeVariables liftedLocals,
  51. int frameOrder)
  52. : this(thread, funcInfo) {
  53. _liftedLocals = liftedLocals;
  54. _stackDepth = frameOrder;
  55. }
  56. #region Internal members
  57. /// <summary>
  58. /// Thread
  59. /// </summary>
  60. internal DebugThread Thread {
  61. get { return _thread; }
  62. }
  63. /// <summary>
  64. /// FrameOrder
  65. /// </summary>
  66. internal int StackDepth {
  67. get { return _stackDepth; }
  68. set { _stackDepth = value; }
  69. }
  70. /// <summary>
  71. /// Variables
  72. /// </summary>
  73. internal VariableInfo[] Variables {
  74. get {
  75. ScopeData scopeData = CurrentScopeData;
  76. VariableInfo[] variables;
  77. if (_thrownException == null) {
  78. variables = scopeData.VarInfos;
  79. } else {
  80. variables = scopeData.VarInfosWithException;
  81. }
  82. if (variables == null) {
  83. List<VariableInfo> visibleInfos = new List<VariableInfo>();
  84. List<VariableInfo> visibleInfosWithException;
  85. // Add parameters
  86. foreach (VariableInfo varInfo in _funcInfo.Variables) {
  87. if (varInfo.IsParameter && !varInfo.Hidden) {
  88. visibleInfos.Add(varInfo);
  89. }
  90. }
  91. // Add locals
  92. foreach (VariableInfo varInfo in LocalsInCurrentScope) {
  93. if (!varInfo.Hidden) {
  94. visibleInfos.Add(varInfo);
  95. }
  96. }
  97. visibleInfosWithException = new List<VariableInfo>(visibleInfos);
  98. visibleInfosWithException.Add(new VariableInfo(_exceptionVariableSymbol, typeof(Exception), false, false, false));
  99. scopeData.VarInfos = visibleInfos.ToArray();
  100. scopeData.VarInfosWithException = visibleInfosWithException.ToArray();
  101. if (_thrownException == null) {
  102. variables = scopeData.VarInfos;
  103. } else {
  104. variables = scopeData.VarInfosWithException;
  105. }
  106. }
  107. return variables;
  108. }
  109. }
  110. /// <summary>
  111. /// CurrentSequencePointIndex
  112. /// </summary>
  113. internal int CurrentSequencePointIndex {
  114. get {
  115. int debugMarker = CurrentLocationCookie;
  116. if (debugMarker >= _funcInfo.SequencePoints.Length) {
  117. #if !SILVERLIGHT
  118. Debug.Assert(false, "DebugMarker doesn't match any location");
  119. #endif
  120. debugMarker = 0;
  121. }
  122. return debugMarker;
  123. }
  124. set {
  125. if (value < 0 || value >= _funcInfo.SequencePoints.Length) {
  126. throw new ArgumentOutOfRangeException("value");
  127. }
  128. // The location can only be changed in leaf frames which are inside trace events
  129. if (!_inTraceBack) {
  130. Debug.Assert(false, "frame not in trace event");
  131. throw new InvalidOperationException(ErrorStrings.JumpNotAllowedInNonLeafFrames);
  132. }
  133. bool needsGenerator = (value != CurrentLocationCookie || _thrownException != null);
  134. // Remap to a generator if we're changing to a different location or if there's a thrown exception
  135. if (_generator == null && needsGenerator) {
  136. RemapToGenerator(_funcInfo.Version);
  137. Debug.Assert(_generator != null);
  138. }
  139. // change location only if really needed
  140. if (value != CurrentLocationCookie) {
  141. Debug.Assert(_generator != null);
  142. _generator.YieldMarkerLocation = value;
  143. }
  144. // Regardless of whether the location is changed or not, the pending
  145. // exception needs to be canceled.
  146. ThrownException = null;
  147. // If the current event is not coming from the generator loop,
  148. // we need to force it to go into the loop.
  149. if (!_inGeneratorLoop && needsGenerator)
  150. _forceToGeneratorLoop = true;
  151. }
  152. }
  153. internal void RemapToLatestVersion() {
  154. RemapToGenerator(Int32.MaxValue);
  155. // Force to generator loop
  156. if (!_inGeneratorLoop)
  157. _forceToGeneratorLoop = true;
  158. }
  159. internal FunctionInfo FunctionInfo {
  160. get {
  161. return _funcInfo;
  162. }
  163. }
  164. internal Exception ThrownException {
  165. get { return _thrownException; }
  166. set {
  167. if (_thrownException != null && value == null) {
  168. _thrownException = null;
  169. GetLocalsScope().Remove(_exceptionVariableSymbol);
  170. } else if (value != null && !GetLocalsScope().ContainsKey(_exceptionVariableSymbol)) {
  171. _thrownException = value;
  172. GetLocalsScope()[_exceptionVariableSymbol] = _thrownException;
  173. }
  174. }
  175. }
  176. internal IDebuggableGenerator Generator {
  177. get { return _generator; }
  178. }
  179. internal bool IsInTraceback {
  180. get { return _inTraceBack; }
  181. set { _inTraceBack = value; }
  182. }
  183. internal bool InGeneratorLoop {
  184. get { return _inGeneratorLoop; }
  185. set { _inGeneratorLoop = value; }
  186. }
  187. internal bool ForceSwitchToGeneratorLoop {
  188. get { return _forceToGeneratorLoop; }
  189. set { _forceToGeneratorLoop = value; }
  190. }
  191. internal DebugContext DebugContext {
  192. get { return _thread.DebugContext; }
  193. }
  194. internal int CurrentLocationCookie {
  195. get {
  196. Debug.Assert(_generator != null || _liftedLocals is IDebugRuntimeVariables);
  197. return (_generator == null ? ((IDebugRuntimeVariables)_liftedLocals).DebugMarker :
  198. (_generator.YieldMarkerLocation != Int32.MaxValue ? _generator.YieldMarkerLocation : _lastKnownGeneratorYieldMarker));
  199. }
  200. }
  201. internal int LastKnownGeneratorYieldMarker {
  202. get { return _lastKnownGeneratorYieldMarker; }
  203. set { _lastKnownGeneratorYieldMarker = value; }
  204. }
  205. /// <summary>
  206. /// // This method is called from the generator to update the frame with generator's locals
  207. /// </summary>
  208. internal void ReplaceLiftedLocals(IRuntimeVariables liftedLocals) {
  209. Debug.Assert(_liftedLocals == null || liftedLocals.Count >= _liftedLocals.Count);
  210. IRuntimeVariables oldLiftecLocals = _liftedLocals;
  211. // Replace the list of IStrongBoxes with the new list
  212. _liftedLocals = liftedLocals;
  213. if (oldLiftecLocals != null) {
  214. for (int i = 0; i < oldLiftecLocals.Count; i++) {
  215. if (!_funcInfo.Variables[i].IsParameter && i < _liftedLocals.Count)
  216. _liftedLocals[i] = oldLiftecLocals[i];
  217. }
  218. }
  219. // Null out scope/variable states to force creation of new ones
  220. _variables.Clear();
  221. }
  222. /// <summary>
  223. /// Remaps the frame's state to use the generator for execution.
  224. /// </summary>
  225. /// <param name="version">Int32.MaxValue to map to latest version</param>
  226. internal void RemapToGenerator(int version) {
  227. Debug.Assert(_generator == null || _funcInfo.Version != version);
  228. // Try to find the target FunctionInfo for the specified version
  229. FunctionInfo targetFuncInfo = GetFunctionInfo(version);
  230. if (targetFuncInfo == null) {
  231. throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ErrorStrings.InvalidFunctionVersion, version));
  232. }
  233. // Create the new generator
  234. CreateGenerator(targetFuncInfo);
  235. // Run to the first yield point
  236. ((IEnumerator)_generator).MoveNext();
  237. }
  238. internal IDictionary<object, object> GetLocalsScope() {
  239. ScopeData scopeData = CurrentScopeData;
  240. IDictionary<object, object> scope = scopeData.Scope;
  241. if (scope == null) {
  242. Debug.Assert(_liftedLocals != null);
  243. List<string> visibleSymbols = new List<string>();
  244. List<VariableInfo> visibleLocals = new List<VariableInfo>();
  245. // Add parameters
  246. for (int i = 0; i < _funcInfo.Variables.Count; i++) {
  247. if (_funcInfo.Variables[i].IsParameter && !_funcInfo.Variables[i].Hidden) {
  248. visibleSymbols.Add(_funcInfo.Variables[i].Name);
  249. visibleLocals.Add(_funcInfo.Variables[i]);
  250. }
  251. }
  252. // Add locals
  253. foreach (VariableInfo varInfo in LocalsInCurrentScope) {
  254. if (!varInfo.Hidden) {
  255. visibleSymbols.Add(varInfo.Name);
  256. visibleLocals.Add(varInfo);
  257. }
  258. }
  259. IRuntimeVariables scopedLocals = new ScopedRuntimeVariables(visibleLocals, _liftedLocals);
  260. scope = new LocalsDictionary(scopedLocals, visibleSymbols.ToArray());
  261. scopeData.Scope = scope;
  262. }
  263. return scope;
  264. }
  265. #endregion
  266. #region Private helpers
  267. private void CreateGenerator(FunctionInfo targetFuncInfo) {
  268. object[] paramValues = GetParamValuesForGenerator();
  269. _generator = (IDebuggableGenerator)targetFuncInfo.GeneratorFactory.GetType().GetMethod("Invoke").Invoke(targetFuncInfo.GeneratorFactory, paramValues);
  270. // Update funcInfo to the new version
  271. if (_funcInfo != targetFuncInfo) {
  272. _funcInfo = targetFuncInfo;
  273. }
  274. }
  275. private object[] GetParamValuesForGenerator() {
  276. List<object> paramValues = new List<object>();
  277. // First parameter is frame
  278. paramValues.Add(this);
  279. for (int i = 0; i < _funcInfo.Variables.Count; i++) {
  280. if (_funcInfo.Variables[i].IsParameter) {
  281. paramValues.Add(_liftedLocals[i]);
  282. }
  283. }
  284. return paramValues.ToArray();
  285. }
  286. private FunctionInfo GetFunctionInfo(int version) {
  287. if (version == _funcInfo.Version)
  288. return _funcInfo;
  289. FunctionInfo funcInfo = _funcInfo;
  290. FunctionInfo lastFuncInfo = null;
  291. while (funcInfo != null) {
  292. if (funcInfo.Version == version) {
  293. return funcInfo;
  294. }
  295. lastFuncInfo = funcInfo;
  296. if (version > funcInfo.Version) {
  297. funcInfo = funcInfo.NextVersion;
  298. } else {
  299. funcInfo = funcInfo.PreviousVersion;
  300. }
  301. }
  302. // if version is Int32.MaxValue return the latest factory
  303. if (version == Int32.MaxValue)
  304. return lastFuncInfo;
  305. return null;
  306. }
  307. private ScopeData CurrentScopeData {
  308. get {
  309. IList<VariableInfo> scopedVars = CurrentLocationCookie < _funcInfo.VariableScopeMap.Length ? _funcInfo.VariableScopeMap[CurrentLocationCookie] : null;
  310. if (scopedVars == null) {
  311. #if !SILVERLIGHT
  312. Debug.Assert(false, "DebugMarker doesn't match any scope");
  313. #endif
  314. // We use null as a key into the tuple that holds variables for "invalid" locations
  315. scopedVars = _funcInfo.VariableScopeMap[0];
  316. }
  317. ScopeData scopeData;
  318. if (!_variables.TryGetValue(scopedVars, out scopeData)) {
  319. scopeData = new ScopeData();
  320. _variables.Add(scopedVars, scopeData);
  321. }
  322. return scopeData;
  323. }
  324. }
  325. private IList<VariableInfo> LocalsInCurrentScope {
  326. get {
  327. IList<VariableInfo> locals = CurrentLocationCookie < _funcInfo.VariableScopeMap.Length ? _funcInfo.VariableScopeMap[CurrentLocationCookie] : null;
  328. if (locals == null) {
  329. #if !SILVERLIGHT
  330. Debug.Assert(false, "DebugMarker doesn't match any scope");
  331. #endif
  332. locals = _funcInfo.VariableScopeMap[0];
  333. }
  334. return locals;
  335. }
  336. }
  337. #endregion
  338. private class ScopeData {
  339. public VariableInfo[] VarInfos;
  340. public VariableInfo[] VarInfosWithException;
  341. public IDictionary<object, object> Scope;
  342. }
  343. }
  344. }