internal DebugFrame CreateFrameForGenerator(FunctionInfo func) { DebugThread thread = GetCurrentThread(); DebugFrame frame = new DebugFrame(thread, func); return(frame); }
public void TestDecode() { ShortHeaderPacket shp = new ShortHeaderPacket(); shp.PacketNumber = 42; shp.DCID = new byte[] { 0x00, 0x00, 0x00, 0x7b }; shp.AddFrame(new DebugFrame { Message = "Message" }); byte[] pack = shp.Encode(); Packet p = Packet.Unpack(pack); Assert.AreEqual(p.GetType(), typeof(ShortHeaderPacket)); ShortHeaderPacket sh = p as ShortHeaderPacket; CollectionAssert.AreEqual(sh.DCID, new byte[] { 0x00, 0x00, 0x00, 0x7b }); Assert.AreEqual(sh.PacketNumber, (UInt64)42); Assert.AreEqual(sh.Spin, false); Assert.AreEqual(sh.KeyPhase, false); Assert.AreEqual(sh.PacketNumberLength, (UInt32)4); foreach (Frame f in p.Frames) { Assert.AreEqual(f.Type, 0x1e); DebugFrame fd = f as DebugFrame; Assert.AreEqual(fd.Message, "Message"); } }
static public void Push(String strName) { lock ( _stackDebugFrames ) { Debug.WriteLine(strName + " {"); Debug.Indent(); //Debug.Flush(); DebugFrame frame = new DebugFrame(strName); _stackDebugFrames.Push(frame); } }
internal void DispatchDebugEvent(DebugThread thread, int debugMarker, TraceEventKind eventKind, object payload) { DebugFrame leafFrame = null; bool hasFrameObject = false; FunctionInfo functionInfo; int stackDepth; if (eventKind != TraceEventKind.ThreadExit) { functionInfo = thread.GetLeafFrameFunctionInfo(out stackDepth); } else { stackDepth = Int32.MaxValue; functionInfo = null; } if (eventKind == TraceEventKind.Exception || eventKind == TraceEventKind.ExceptionUnwind) { thread.ThrownException = (Exception)payload; } thread.IsInTraceback = true; try { // Fire the event IDebugCallback traceHook = _traceHook; if (traceHook != null) { traceHook.OnDebugEvent(eventKind, thread, functionInfo, debugMarker, stackDepth, payload); } // Check if the frame object is created after the traceback. If it's created - then we need // to check if we need to remap hasFrameObject = thread.TryGetLeafFrame(ref leafFrame); if (hasFrameObject) { Debug.Assert(!leafFrame.InGeneratorLoop || (leafFrame.InGeneratorLoop && !leafFrame.ForceSwitchToGeneratorLoop)); if (leafFrame.ForceSwitchToGeneratorLoop && !leafFrame.InGeneratorLoop) { throw new ForceToGeneratorLoopException(); } } } finally { if (hasFrameObject) { leafFrame.IsInTraceback = false; } thread.IsInTraceback = false; thread.ThrownException = null; } }
private void SerialReplication(ProcedureNode procNode, ref int exeblock, int ci, int fi, DebugFrame debugFrame = null) { // TODO: Decide where to insert this common code block for Serial mode and Debugging - pratapa if (core.Options.ExecutionMode == ProtoCore.ExecutionMode.Serial || core.Options.IDEDebugMode) { RX = CallSite.PerformReturnTypeCoerce(procNode, core, RX); core.ContinuationStruct.RunningResult.Add(RX); core.ContinuationStruct.Result = RX; pc = core.ContinuationStruct.InitialPC; if (core.ContinuationStruct.Done) { RX = HeapUtils.StoreArray(core.ContinuationStruct.RunningResult.ToArray(), null, core); GCUtils.GCRetain(RX, core); core.ContinuationStruct.RunningResult.Clear(); core.ContinuationStruct.IsFirstCall = true; if (core.Options.IDEDebugMode) { // If stepping over function call in debug mode if (core.DebugProps.RunMode == Runmode.StepNext) { // if stepping over outermost function call if (!core.DebugProps.DebugStackFrameContains(DebugProperties.StackFrameFlagOptions.IsFunctionStepOver)) { core.DebugProps.SetUpStepOverFunctionCalls(core, procNode, debugFrame.ExecutingGraphNode, debugFrame.HasDebugInfo); } } // The DebugFrame passed here is the previous one that was popped off before this call // In the case of Dot call the debugFrame obtained here is the one for the member function // for both Break and non Break cases - pratapa DebugPerformCoercionAndGC(debugFrame); // If call returns to Dot Call, restore debug props for Dot call debugFrame = core.DebugProps.DebugStackFrame.Peek(); if (debugFrame.IsDotCall) { List<Instruction> instructions = istream.instrList; bool wasPopped = RestoreDebugPropsOnReturnFromBuiltIns(ref exeblock, ref instructions); if (wasPopped) { executingBlock = exeblock; core.DebugProps.CurrentBlockId = exeblock; } else { core.DebugProps.RestoreCallrForNoBreak(core, procNode, false); } DebugPerformCoercionAndGC(debugFrame); } //core.DebugProps.DebugEntryPC = currentPC; } // Perform return type coercion, GC and/or GC for Dot methods for Non-debug, Serial mode replication case else { // If member function // 1. Release array arguments to Member function // 2. Release this pointer bool isBaseCall = false; StackValue? thisPtr = null; if (thisPtr != null) { // Replicating member function PerformCoercionAndGC(null, false, thisPtr, core.ContinuationStruct.InitialArguments, core.ContinuationStruct.InitialDotCallDimensions); // Perform coercion and GC for Dot call ProcedureNode dotCallprocNode = null; List<StackValue> dotCallArgs = new List<StackValue>(); List<StackValue> dotCallDimensions = new List<StackValue>(); PerformCoercionAndGC(dotCallprocNode, false, null, dotCallArgs, dotCallDimensions); } else { PerformCoercionAndGC(procNode, isBaseCall, null, core.ContinuationStruct.InitialArguments, core.ContinuationStruct.InitialDotCallDimensions); } } pc++; return; } else { // Jump back to Callr to call ResolveForReplication and recompute fep with next argument core.ContinuationStruct.IsFirstCall = false; ReturnToCallSiteForReplication(procNode, ci, fi); return; } } }
/// <summary> /// Restores Debug properties from function call and/or from Dot call /// </summary> /// <param name="currentPC"></param> /// <param name="exeblock"></param> /// <param name="ci"></param> /// <param name="fi"></param> /// <param name="isReplicating"></param> /// <returns></returns> private bool DebugReturnFromFunctionCall(int currentPC, ref int exeblock, out int ci, out int fi, out bool isReplicating, out DebugFrame debugFrame) { DebugFrame tempFrame = null; tempFrame = core.DebugProps.DebugStackFrame.Peek(); List<Instruction> instructions = istream.instrList; bool waspopped = RestoreDebugPropsOnReturnFromFunctionCall(ref exeblock, ref instructions, out ci, out fi, out isReplicating, out debugFrame); // TODO: If return from previous function calls "_Dispose", and we have stepped into it, // we need to restore the caller stackframe - pratapa if (tempFrame.IsDisposeCall) { // TODO: If we have stepped inside _Dispose and are resuming from it - pratapa if (!terminate) { // 1. Call everything after RETURNSITEGC in OpCode.RETURN/ OpCode.RETC // 2. Call RestoreDebugPropsOnReturnFromFunctionCall() for caller function // 3. Return address from _Dispose is one more than the correct value and therefore needs to be fixed } // TODO: This works assuming debugging inside _Dispose functions is disabled // ie stepping over _Dispose - pratapa core.DebugProps.DebugEntryPC = core.DebugProps.ReturnPCFromDispose; //break; } else { #if __DEBUG_REPLICATE // When debugging replication, we must pop off the DebugFrame for the Dot call only after replication is complete // (after ContinuationStruct.Done == true) - pratapa if (!isReplicating) #endif { debugFrame = core.DebugProps.DebugStackFrame.Peek(); // If call returns to Dot Call, restore debug props for Dot call if (debugFrame.IsDotCall) { waspopped = RestoreDebugPropsOnReturnFromBuiltIns(ref exeblock, ref instructions); } } core.DebugProps.DebugEntryPC = currentPC; } return waspopped; }
bool RestoreDebugPropsOnReturnFromFunctionCall(ref int exeblock, ref List<Instruction> instructions, out int ci, out int fi, out bool isReplicating, out DebugFrame debugFrame) { // // TODO: Aparajit, Jun - Determine an alternative to the waspopped flag // bool waspopped = false; Validity.Assert(core.DebugProps.DebugStackFrame.Count > 0); debugFrame = core.DebugProps.DebugStackFrame.Peek(); isReplicating = debugFrame.IsReplicating; #if !__DEBUG_REPLICATE if (!isReplicating) #endif { bool isResume = debugFrame.IsResume; // Comment Jun: Since we dont step into _Dispose() calls, then its debugframe should not be popped off here. bool isDispose = debugFrame.IsDisposeCall; // RestoreCallrForNoBreak and PerformReturnTypeCoerce are NOT called if this is true // or for base class ctor calls and therefore need to be taken care of here if ((isResume || debugFrame.IsBaseCall) && !isDispose) { debugFrame = core.DebugProps.DebugStackFrame.Pop(); waspopped = true; if (isResume) { if (core.DebugProps.DebugStackFrame.Count > 1) { DebugFrame frame = core.DebugProps.DebugStackFrame.Peek(); frame.IsResume = true; } } #if __DEBUG_REPLICATE // Return type coercion and function call GC for replicating case takes place separately // in SerialReplication() when ContinuationStruct.Done == true - pratapa if (!isReplicating) #endif { DebugPerformCoercionAndGC(debugFrame); } // Restore registers except RX on popping of function stackframe ResumeRegistersFromStackExceptRX(); terminate = false; } Properties.executingGraphNode = debugFrame.ExecutingGraphNode; if (core.DebugProps.RunMode.Equals(Runmode.StepOut) && pc == core.DebugProps.StepOutReturnPC) { core.Breakpoints.Clear(); core.Breakpoints.AddRange(core.DebugProps.AllbreakPoints); } } // Restore return address and lang block pc = (int)rmem.GetAtRelative(StackFrame.kFrameIndexReturnAddress).opdata; exeblock = (int)rmem.GetAtRelative(StackFrame.kFrameIndexFunctionCallerBlock).opdata; istream = exe.instrStreamList[exeblock]; instructions = istream.instrList; executingLanguage = istream.language; ci = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; fi = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; int localCount = 0; int paramCount = 0; int blockId = (int)rmem.GetAtRelative(StackFrame.kFrameIndexFunctionBlock).opdata; GetLocalAndParamCount(blockId, ci, fi, out localCount, out paramCount); // Pop function stackframe as this is not allowed in Ret/Retc in debug mode rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize + localCount + paramCount); ResumeRegistersFromStackExceptRX(); //StackValue svFrameType = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexCallerStackFrameType); StackValue svFrameType = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexStackFrameType); StackFrameType frametype = (StackFrameType)svFrameType.opdata; if (frametype == StackFrameType.kTypeLanguage) { bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; } return waspopped; }
/// <summary> /// Performs type coercion of returned value and GC of arguments, this ptr and Dot methods /// </summary> /// <param name="finalFep"></param> /// <param name="debugFrame"></param> /// <param name="Arguments"></param> /// <param name="DotCallDimensions"></param> private void DebugPerformCoercionAndGC(DebugFrame debugFrame) { ProcedureNode procNode = debugFrame.FinalFepChosen != null ? debugFrame.FinalFepChosen.procedureNode : null; PerformCoercionAndGC(procNode, debugFrame.IsBaseCall, debugFrame.ThisPtr, debugFrame.Arguments, debugFrame.DotCallDimensions); }
internal DebugFrame CreateFrameForGenerator(FunctionInfo func) { DebugThread thread = GetCurrentThread(); DebugFrame frame = new DebugFrame(thread, func); return frame; }
bool RestoreDebugPropsOnReturnFromFunctionCall(ref int exeblock, ref List<Instruction> instructions, out int ci, out int fi, out bool isReplicating, out DebugFrame debugFrame) { // // TODO: Aparajit, Jun - Determine an alternative to the waspopped flag // bool waspopped = false; Validity.Assert(runtimeCore.DebugProps.DebugStackFrame.Count > 0); debugFrame = runtimeCore.DebugProps.DebugStackFrame.Peek(); isReplicating = debugFrame.IsReplicating; if (!isReplicating) { bool isResume = debugFrame.IsResume; // Comment Jun: Since we dont step into _Dispose() calls, then its debugframe should not be popped off here. bool isDispose = debugFrame.IsDisposeCall; // RestoreCallrForNoBreak and PerformReturnTypeCoerce are NOT called if this is true // or for base class ctor calls and therefore need to be taken care of here if ((isResume || debugFrame.IsBaseCall) && !isDispose) { debugFrame = runtimeCore.DebugProps.DebugStackFrame.Pop(); waspopped = true; if (isResume) { if (runtimeCore.DebugProps.DebugStackFrame.Count > 1) { DebugFrame frame = runtimeCore.DebugProps.DebugStackFrame.Peek(); frame.IsResume = true; } } DebugPerformCoercionAndGC(debugFrame); // Restore registers except RX on popping of function stackframe ResumeRegistersFromStackExceptRX(); terminate = false; } Properties.executingGraphNode = debugFrame.ExecutingGraphNode; if (runtimeCore.DebugProps.RunMode.Equals(Runmode.StepOut) && pc == runtimeCore.DebugProps.StepOutReturnPC) { runtimeCore.Breakpoints.Clear(); runtimeCore.Breakpoints.AddRange(runtimeCore.DebugProps.AllbreakPoints); } } // Restore return address and lang block pc = (int)rmem.GetAtRelative(StackFrame.FrameIndexReturnAddress).IntegerValue; exeblock = rmem.GetAtRelative(StackFrame.FrameIndexCallerBlockIndex).BlockIndex; istream = exe.instrStreamList[exeblock]; instructions = istream.instrList; executingLanguage = istream.language; ci = rmem.GetAtRelative(StackFrame.FrameIndexClassIndex).ClassIndex; fi = rmem.GetAtRelative(StackFrame.FrameIndexFunctionIndex).FunctionIndex; int localCount; int paramCount; int blockId = rmem.GetAtRelative(StackFrame.FrameIndexFunctionBlockIndex).BlockIndex; GetLocalAndParamCount(blockId, ci, fi, out localCount, out paramCount); // Get execution states List<bool> execStateRestore = new List<bool>(); execStateRestore = RetrieveExecutionStatesFromStack(localCount, paramCount); // Pop function stackframe as this is not allowed in Ret/Retc in debug mode rmem.FramePointer = (int)rmem.GetAtRelative(StackFrame.FrameIndexFramePointer).IntegerValue; rmem.PopFrame(StackFrame.StackFrameSize + localCount + paramCount + execStateRestore.Count); ResumeRegistersFromStackExceptRX(); //StackValue svFrameType = rmem.GetAtRelative(StackFrame.kFrameIndexCallerStackFrameType); StackValue svFrameType = rmem.GetAtRelative(StackFrame.FrameIndexStackFrameType); StackFrameType frametype = svFrameType.FrameType; if (frametype == StackFrameType.LanguageBlock) { bounceType = TX.BounceType; } return waspopped; }
/// <summary> /// Performs type coercion of returned value and GC of arguments, this ptr and Dot methods /// </summary> private void DebugPerformCoercionAndGC(DebugFrame debugFrame) { ProcedureNode procNode = debugFrame.FinalFepChosen != null ? debugFrame.FinalFepChosen.procedureNode : null; if (!debugFrame.IsBaseCall) { RX = CallSite.PerformReturnTypeCoerce(procNode, runtimeCore, RX); if (debugFrame.ThisPtr == null && CoreUtils.IsDotMethod(procNode.Name)) { RX = IndexIntoArray(RX, debugFrame.DotCallDimensions); rmem.PopFrame(Constants.kDotCallArgCount); } } }
internal object GeneratorLoopProc(DebugFrame frame, out bool moveNext) { Debug.Assert(frame.Generator != null); moveNext = true; bool skipTraceEvent = true; object retVal; if (frame.ForceSwitchToGeneratorLoop) { // Reset ForceSwitchToGeneratorLoop flag frame.ForceSwitchToGeneratorLoop = false; } while (true) { if (!skipTraceEvent) { if (frame.FunctionInfo.SequencePoints[frame.CurrentLocationCookie].SourceFile.DebugMode == DebugMode.FullyEnabled || frame.FunctionInfo.SequencePoints[frame.CurrentLocationCookie].SourceFile.DebugMode == DebugMode.TracePoints && frame.FunctionInfo.GetTraceLocations()[frame.CurrentLocationCookie]) { Debug.Assert(((IEnumerator)frame.Generator).Current == DebugYieldValue); frame.InGeneratorLoop = true; try { DispatchDebugEvent(frame.Thread, frame.CurrentLocationCookie, TraceEventKind.TracePoint, null); } #if DEBUG catch (ForceToGeneratorLoopException) { Debug.Assert(false, "ForceToGeneratorLoopException thrown in generator loop"); throw; } #endif finally { frame.InGeneratorLoop = false; } } } else { skipTraceEvent = false; } // Advance to next yield try { moveNext = ((IEnumerator)frame.Generator).MoveNext(); object current = ((IEnumerator)frame.Generator).Current; // Update the last known marker if (frame.Generator.YieldMarkerLocation != Int32.MaxValue) { frame.LastKnownGeneratorYieldMarker = frame.Generator.YieldMarkerLocation; } // Check if this was a user-code yield or a debug yield if (current != DebugYieldValue || !moveNext) { if (moveNext) { retVal = current; } else { retVal = null; } break; } } catch (ForceToGeneratorLoopException) { // We land here when an exception is thrown from a nested catch block and if that exception is being cancelled. skipTraceEvent = true; } catch (Exception ex) { if (frame.DebugContext.DebugMode != DebugMode.Disabled) { try { frame.InGeneratorLoop = true; DispatchDebugEvent(frame.Thread, frame.CurrentLocationCookie, TraceEventKind.ExceptionUnwind, ex); } finally { frame.InGeneratorLoop = false; } } else { throw; } // Rethrow if the exception is not cancelled if (frame.ThrownException != null) { throw; } skipTraceEvent = true; } } Debug.Assert(retVal != DebugYieldValue); return(retVal); }
internal object GeneratorLoopProc(DebugFrame frame, out bool moveNext) { Debug.Assert(frame.Generator != null); moveNext = true; bool skipTraceEvent = true; object retVal; if (frame.ForceSwitchToGeneratorLoop) { // Reset ForceSwitchToGeneratorLoop flag frame.ForceSwitchToGeneratorLoop = false; } while (true) { if (!skipTraceEvent) { if (frame.FunctionInfo.SequencePoints[frame.CurrentLocationCookie].SourceFile.DebugMode == DebugMode.FullyEnabled || frame.FunctionInfo.SequencePoints[frame.CurrentLocationCookie].SourceFile.DebugMode == DebugMode.TracePoints && frame.FunctionInfo.GetTraceLocations()[frame.CurrentLocationCookie]) { Debug.Assert(((IEnumerator)frame.Generator).Current == DebugYieldValue); frame.InGeneratorLoop = true; try { DispatchDebugEvent(frame.Thread, frame.CurrentLocationCookie, TraceEventKind.TracePoint, null); } #if DEBUG catch (ForceToGeneratorLoopException) { Debug.Assert(false, "ForceToGeneratorLoopException thrown in generator loop"); throw; } #endif finally { frame.InGeneratorLoop = false; } } } else { skipTraceEvent = false; } // Advance to next yield try { moveNext = ((IEnumerator)frame.Generator).MoveNext(); object current = ((IEnumerator)frame.Generator).Current; // Update the last known marker if (frame.Generator.YieldMarkerLocation != Int32.MaxValue) frame.LastKnownGeneratorYieldMarker = frame.Generator.YieldMarkerLocation; // Check if this was a user-code yield or a debug yield if (current != DebugYieldValue || !moveNext) { if (moveNext) { retVal = current; } else { retVal = null; } break; } } catch (ForceToGeneratorLoopException) { // We land here when an exception is thrown from a nested catch block and if that exception is being cancelled. skipTraceEvent = true; } catch (Exception ex) { if (frame.DebugContext.DebugMode != DebugMode.Disabled) { try { frame.InGeneratorLoop = true; DispatchDebugEvent(frame.Thread, frame.CurrentLocationCookie, TraceEventKind.ExceptionUnwind, ex); } finally { frame.InGeneratorLoop = false; } } else { throw; } // Rethrow if the exception is not cancelled if (frame.ThrownException != null) throw; skipTraceEvent = true; } } Debug.Assert(retVal != DebugYieldValue); return retVal; }
static public void Pop() { lock ( _stackDebugFrames ) { Debug.Assert(_stackDebugFrames.Count > 0); DebugFrame frame = (DebugFrame)_stackDebugFrames.Pop(); float fMilliseconds = 0; if (_showTime) { fMilliseconds = frame.GetElapsedMillisecs(); } long memoryDelta = 0; if (_showMemory) { memoryDelta = frame.GetMemoryDelta(); } Debug.Unindent(); StringBuilder stringBuilder = new StringBuilder(50); stringBuilder.Append('}'); if (_showTime || _showMemory) { stringBuilder.Append(" ["); } if (_showTime) { stringBuilder.Append(" "); if (fMilliseconds < 1000) { stringBuilder.Append(fMilliseconds); stringBuilder.Append(" ms"); } else if (fMilliseconds < 60000) { stringBuilder.Append(fMilliseconds / 1000); stringBuilder.Append(" secs"); } else { stringBuilder.Append(fMilliseconds / 60000); stringBuilder.Append(" mins"); } stringBuilder.Append(" "); } if (_showMemory) { stringBuilder.Append(" "); if (Math.Abs(memoryDelta) < 1000) { stringBuilder.Append(memoryDelta); stringBuilder.Append(" Bytes"); } else if (Math.Abs(memoryDelta) < 1000000) { stringBuilder.Append(((int)memoryDelta / 10) / 100f); stringBuilder.Append(" KB"); } else { stringBuilder.Append(((int)memoryDelta / 10000) / 100f); stringBuilder.Append(" MB"); } stringBuilder.Append(" "); } if (_showTime || _showMemory) { stringBuilder.Append("]"); } Debug.WriteLine(stringBuilder.ToString()); //Debug.Flush(); } }