MethodBuilder CreateIsland(TypeBuilder typeBuilder, State state, bool withPrimingTest, Dictionary<string, byte[]>checksumCache) { MethodBuilder methodbuilder = this.CreateMethodBuilder(typeBuilder, threadWorkerControllerType, state, withPrimingTest); ILGenerator ilGenerator = methodbuilder.GetILGenerator(); const int lineHidden = 0xFeeFee; // #line hidden directive // Island: // void MethodName(Manager m) // { // .line // nop // call Worker(m) // ret; // } SourceLocation stateLocation = state.Location; ISymbolDocumentWriter document = this.GetSourceDocument(stateLocation.FileName, stateLocation.Checksum, checksumCache); Label islandWorkerLabel = ilGenerator.DefineLabel(); // Hide all the opcodes before the real source line. // This is needed for Island which is called during priming (Attach to Process): // It should skip the line directive during priming, thus it won't break at user's // breakpoints at the beginning during priming the callstack. if (withPrimingTest) { ilGenerator.MarkSequencePoint(document, lineHidden, 1, lineHidden, 100); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Brtrue, islandWorkerLabel); } // Emit sequence point before the IL instructions to map it to a source location. ilGenerator.MarkSequencePoint(document, stateLocation.StartLine, stateLocation.StartColumn, stateLocation.EndLine, stateLocation.EndColumn); ilGenerator.Emit(OpCodes.Nop); ilGenerator.MarkLabel(islandWorkerLabel); ilGenerator.Emit(OpCodes.Ldarg_1); ilGenerator.EmitCall(OpCodes.Call, islandWorkerMethodInfo, null); ilGenerator.Emit(OpCodes.Ret); return methodbuilder; }
public MethodInfo GetIsland(State state, bool isPriming) { MethodInfo island = null; if (isPriming) { if (!islandsWithPriming.TryGetValue(state, out island)) { island = state.GetMethodInfo(true); islandsWithPriming[state] = island; } } else { if (!islands.TryGetValue(state, out island)) { island = state.GetMethodInfo(false); islands[state] = island; } } return island; }
public State DefineState(SourceLocation location, string name, LocalsItemDescription[] earlyLocals, int numberOfEarlyLocals) { State state; lock (this) { if (!this.stateMap.TryGetValue(location, out state)) { lock (this) { state = new State(location, name, earlyLocals, numberOfEarlyLocals); this.stateMap.Add(location, state); this.states.Add(state); } } } return state; }
internal MethodBuilder CreateMethodBuilder(TypeBuilder typeBuilder, Type typeIslandArguments, State state, bool withPriming) { // create the method string methodName = (state.Name != null ? state.Name : ("Line_" + state.Location.StartLine)); if (withPriming) { methodName = MethodWithPrimingPrefix + methodName; } // Parameters to the islands: // 1. Args // 2. IDict of late-bound locals. // 3 ... N. list of early bound locals. const int numberOfBaseArguments = 2; IEnumerable<LocalsItemDescription> earlyLocals = state.EarlyLocals; int numberOfEarlyLocals = state.NumberOfEarlyLocals; Type[] parameterTypes = new Type[numberOfBaseArguments + numberOfEarlyLocals]; parameterTypes[0] = typeof(bool); parameterTypes[1] = typeIslandArguments; if (numberOfEarlyLocals > 0) { int i = numberOfBaseArguments; foreach (LocalsItemDescription localsItemDescription in earlyLocals) { parameterTypes[i] = localsItemDescription.Type; i++; } } Type returnType = typeof(void); MethodBuilder methodbuilder = typeBuilder.DefineMethod( methodName, MethodAttributes.Static | MethodAttributes.Public, returnType, parameterTypes); // Need to define parameter here, otherwise EE cannot get the correct IDebugContainerField // for debugInfo. methodbuilder.DefineParameter(1, ParameterAttributes.None, "isPriming"); methodbuilder.DefineParameter(2, ParameterAttributes.None, "typeIslandArguments"); // Define the parameter names // Note that we can hide implementation-specific arguments from VS by not defining parameter // info for them. Eg., the StepInTarget argument doesn't appear to show up in VS at all. if (numberOfEarlyLocals > 0) { int i = numberOfBaseArguments + 1; foreach (LocalsItemDescription localsItemDescription in earlyLocals) { methodbuilder.DefineParameter(i, ParameterAttributes.None, localsItemDescription.Name); i++; } } return methodbuilder; }
public void LeaveState(State state) { if (this.callStack.Count > 0) { VirtualStackFrame stackFrame = this.callStack.Pop(); Fx.Assert( (state == null && stackFrame == null) || (stackFrame != null && stackFrame.State == state), "Unmatched LeaveState: " + ((state == null) ? "null" : state.Name) + " with top stack frame: " + ((stackFrame == null || stackFrame.State == null) ? "null" : stackFrame.State.Name)); if (stackFrame != null) // Matches with an uninstrumented Activity. { this.controller.LeaveState(); } } else { Fx.Assert("Unmatched LeaveState: " + ((state != null) ? state.Name : "null")); } }
// Pop the state most recently pushed by EnterState. internal void LeaveState(int threadIndex, State state) { Fx.Assert(threadIndex < this.threads.Count, "Index out of range for thread"); Fx.Assert(this.threads[threadIndex] != null, "LogicalThread is null"); this.threads[threadIndex].LeaveState(state); }
// Push the state onto the virtual callstack, with no locals. // State is the state to push onto stack. //internal void EnterState(int threadIndex, State state) //{ // this.EnterState(threadIndex, state, null); //} // Enter a state and push it onto the 'virtual callstack'. // If the user set a a breakpoint at the source location associated with // this state, this call will hit that breakpoint. // Call LeaveState when the interpretter is finished with this state. // // State is state to enter. // "locals" is local variables (both early-bound and late-bound) associated with this state. // Early-bound locals match by name with the set passed into DefineState. // Late-bound will be displayed read-only to the user in the watch window.</param> // // EnterState can be called reentrantly. If code calls Enter(A); Enter(B); Enter(C); // Then on the call to Enter(C), the virtual callstack will be A-->B-->C. // Each call to Enter() will rebuild the virtual callstack. // internal void EnterState(int threadIndex, State state, IDictionary<string, object> locals) { this.EnterState(threadIndex, new VirtualStackFrame(state, locals)); }
public VirtualStackFrame(State state) : this(state, null) { Fx.Assert(state.NumberOfEarlyLocals == 0, "should start with empty locals"); }
public VirtualStackFrame(State state, IDictionary<string, object> locals) { this.state = state; this.locals = locals; }