PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/PythonTracebackListener.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 190 lines | 139 code | 29 blank | 22 comment | 30 complexity | 9dc34dbeefe5762dbc3adb433a5e2d47 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, 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 Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using Microsoft.Scripting;
  18. using Microsoft.Scripting.Runtime;
  19. using Microsoft.Scripting.Utils;
  20. using IronPython.Modules;
  21. using IronPython.Runtime.Exceptions;
  22. using IronPython.Runtime.Operations;
  23. using IronPython.Runtime.Types;
  24. using Debugging = Microsoft.Scripting.Debugging;
  25. using System.Diagnostics;
  26. namespace IronPython.Runtime {
  27. internal sealed class PythonTracebackListener : Debugging.ITraceCallback {
  28. private readonly PythonContext _pythonContext;
  29. [ThreadStatic] private static TracebackDelegate _globalTraceDispatch;
  30. [ThreadStatic] private static object _globalTraceObject;
  31. [ThreadStatic] internal static bool InTraceBack;
  32. private bool _exceptionThrown;
  33. #if PROFILE_SUPPORT
  34. private bool _profile;
  35. #endif
  36. internal PythonTracebackListener(PythonContext pythonContext) {
  37. _pythonContext = pythonContext;
  38. }
  39. internal PythonContext PythonContext {
  40. get {
  41. return _pythonContext;
  42. }
  43. }
  44. internal bool ExceptionThrown {
  45. get {
  46. return _exceptionThrown;
  47. }
  48. }
  49. internal static void SetTrace(object function, TracebackDelegate traceDispatch) {
  50. _globalTraceDispatch = traceDispatch;
  51. _globalTraceObject = function;
  52. }
  53. internal static object GetTraceObject() {
  54. return _globalTraceObject;
  55. }
  56. #if PROFILE_SUPPORT
  57. internal void SetProfile(TracebackDelegate traceDispatch) {
  58. _globalTraceDispatch = traceDispatch;
  59. _profile = true;
  60. }
  61. #endif
  62. #region ITraceCallback Members
  63. public void OnTraceEvent(Debugging.TraceEventKind kind, string name, string sourceFileName, SourceSpan sourceSpan, Func<IAttributesCollection> scopeCallback, object payload, object customPayload) {
  64. if (kind == Debugging.TraceEventKind.ThreadExit || // We don't care about thread-exit events
  65. #if PROFILER_SUPPORT
  66. (_profile && kind == Debugging.TraceEventKind.TracePoint) || // Ignore code execute tracebacks when in profile mode
  67. #endif
  68. kind == Debugging.TraceEventKind.ExceptionUnwind) { // and we always have a try/catch so we don't care about methods unwinding.
  69. return;
  70. }
  71. TracebackDelegate traceDispatch = null;
  72. object traceDispatchObject = null;
  73. var thread = PythonOps.GetFunctionStack();
  74. TraceBackFrame pyFrame;
  75. if (InTraceBack) {
  76. return;
  77. }
  78. try {
  79. if (kind == Debugging.TraceEventKind.FrameEnter) {
  80. traceDispatch = _globalTraceDispatch;
  81. traceDispatchObject = _globalTraceObject;
  82. var properties = (PythonDebuggingPayload)customPayload;
  83. // push the new frame
  84. pyFrame = new TraceBackFrame(
  85. this,
  86. properties.Code,
  87. thread.Count == 0 ? null : thread[thread.Count - 1].Frame,
  88. properties,
  89. scopeCallback
  90. );
  91. thread.Add(new FunctionStack(pyFrame));
  92. if (traceDispatchObject == null) {
  93. return;
  94. }
  95. pyFrame.Setf_trace(traceDispatchObject);
  96. } else {
  97. if (thread.Count == 0) {
  98. return;
  99. }
  100. pyFrame = thread[thread.Count - 1].Frame;
  101. if (pyFrame == null) {
  102. // force creation of the Python frame
  103. pyFrame = SysModule._getframeImpl(thread[thread.Count - 1].Context, 0);
  104. }
  105. traceDispatch = pyFrame.TraceDelegate;
  106. traceDispatchObject = pyFrame.Getf_trace();
  107. }
  108. // Update the current line
  109. if (kind != Debugging.TraceEventKind.FrameExit) {
  110. pyFrame._lineNo = sourceSpan.Start.Line;
  111. }
  112. if (traceDispatchObject != null && !_exceptionThrown) {
  113. DispatchTrace(thread, kind, payload, traceDispatch, traceDispatchObject, pyFrame);
  114. }
  115. } finally {
  116. if (kind == Debugging.TraceEventKind.FrameExit && thread.Count > 0) {
  117. // don't pop frames we didn't push
  118. if (thread[thread.Count - 1].Code == ((PythonDebuggingPayload)customPayload).Code) {
  119. thread.RemoveAt(thread.Count - 1);
  120. }
  121. }
  122. }
  123. }
  124. #endregion
  125. private void DispatchTrace(List<FunctionStack> thread, Debugging.TraceEventKind kind, object payload, TracebackDelegate traceDispatch, object traceDispatchObject, TraceBackFrame pyFrame) {
  126. object args = null;
  127. // Prepare the event
  128. string traceEvent = String.Empty;
  129. switch (kind) {
  130. case Debugging.TraceEventKind.FrameEnter: traceEvent = "call"; break;
  131. case Debugging.TraceEventKind.TracePoint: traceEvent = "line"; break;
  132. case Debugging.TraceEventKind.Exception:
  133. traceEvent = "exception";
  134. object pyException = PythonExceptions.ToPython((Exception)payload);
  135. object pyType = ((IPythonObject)pyException).PythonType;
  136. args = PythonTuple.MakeTuple(pyType, pyException, null);
  137. break;
  138. case Debugging.TraceEventKind.FrameExit:
  139. traceEvent = "return";
  140. args = payload;
  141. break;
  142. }
  143. bool traceDispatchThrew = true;
  144. InTraceBack = true;
  145. try {
  146. TracebackDelegate dlg = traceDispatch(pyFrame, traceEvent, args);
  147. traceDispatchThrew = false;
  148. pyFrame.Setf_trace(dlg);
  149. } finally {
  150. InTraceBack = false;
  151. if (traceDispatchThrew) {
  152. // We're matching CPython's behavior here. If the trace dispatch throws any exceptions
  153. // we don't re-enable tracebacks. We need to leave the trace callback in place though
  154. // so that we can pop our frames.
  155. _globalTraceObject = _globalTraceDispatch = null;
  156. _exceptionThrown = true;
  157. }
  158. }
  159. }
  160. }
  161. }