private static Instruction FindNextConstructionMethod(MethodDefinition method, Instruction instruction) { var cursor = instruction; //the description object should be on the stack, and nothing on top of it. int stackDepth = 1; while (cursor.Next != null) { cursor = cursor.Next; var result = CecilHelpers.MatchesDelegateProducingPattern(method, cursor, CecilHelpers.DelegateProducingPattern.MatchSide.Start); if (result != null) { cursor = result.Instructions.Last(); stackDepth += 1; continue; } if (CecilHelpers.IsUnsupportedBranch(cursor)) { UserError.DC0010(method, cursor).Throw(); } if (cursor.OpCode == OpCodes.Call && cursor.Operand is MethodReference mr && IsLambdaJobDescriptionConstructionMethod(mr)) { return(cursor); } stackDepth -= cursor.GetPopDelta(); if (stackDepth < 1) { UserError.DC0011(method, cursor).Throw(); } stackDepth += cursor.GetPushDelta(); } return(null); }
public static Instruction FindInstructionThatPushedArg(MethodDefinition containingMethod, int argNumber, Instruction callInstructionsWhoseArgumentsWeWantToFind) { containingMethod.Body.EnsurePreviousAndNextAreSet(); var cursor = callInstructionsWhoseArgumentsWeWantToFind.Previous; int stackSlotWhoseWriteWeAreLookingFor = argNumber; int stackSlotWhereNextPushWouldBeWrittenTo = InstructionExtensions.GetPopDelta(callInstructionsWhoseArgumentsWeWantToFind); var seenInstructions = new HashSet <Instruction>() { callInstructionsWhoseArgumentsWeWantToFind, cursor }; while (cursor != null) { var pushAmount = cursor.GetPushDelta(); var popAmount = cursor.GetPopDelta(); var result = CecilHelpers.MatchesDelegateProducingPattern(containingMethod, cursor, CecilHelpers.DelegateProducingPattern.MatchSide.End); if (result != null) { //so we are crawling backwards through isntructions. if we find a "this is roslyn caching a delegate" sequence, //we're going to pretend it is a single instruction, that pushes the delegate on the stack, and pops nothing. cursor = result.Instructions.First(); pushAmount = 1; popAmount = 0; } else if (cursor.IsBranch()) { var target = (Instruction)cursor.Operand; if (!seenInstructions.Contains(target)) { if (IsUnsupportedBranch(cursor)) { UserError.DC0010(containingMethod, cursor).Throw(); } } } for (int i = 0; i != pushAmount; i++) { stackSlotWhereNextPushWouldBeWrittenTo--; if (stackSlotWhereNextPushWouldBeWrittenTo == stackSlotWhoseWriteWeAreLookingFor) { return(cursor); } } for (int i = 0; i != popAmount; i++) { stackSlotWhereNextPushWouldBeWrittenTo++; } cursor = cursor.Previous; seenInstructions.Add(cursor); } return(null); }