private void SplitSinglePointOfReturn() { if (!Module.IsDebugBuild()) { return; } var lastRetInstruction = Instructions.LastOrDefault(); if (lastRetInstruction?.OpCode != OpCodes.Ret) { return; } var ldlocInstruction = lastRetInstruction.Previous; if (ldlocInstruction?.OpCode != OpCodes.Ldloc) { return; } var refsToLdloc = Instructions.Where(i => i.Operand == ldlocInstruction).ToList(); var leaveOriginalReturnPoint = false; var insertedRet = 0; foreach (var brInstruction in refsToLdloc) { var stlocInstruction = brInstruction.Previous; if (brInstruction.OpCode == OpCodes.Br && stlocInstruction != null && stlocInstruction.OpCode == OpCodes.Stloc && stlocInstruction.Operand == ldlocInstruction.Operand) { _il.Remove(stlocInstruction); _il.Replace(brInstruction, Instruction.Create(OpCodes.Ret)); ++insertedRet; } else { leaveOriginalReturnPoint = true; } } if (!leaveOriginalReturnPoint) { // If the compiler ever stops emitting no-op branch instructions var stlocInstruction = ldlocInstruction.PrevSkipNops(); if (stlocInstruction != null && stlocInstruction.OpCode == OpCodes.Stloc && stlocInstruction.Operand == ldlocInstruction.Operand) { _il.Remove(stlocInstruction); } _il.RemoveNopsAround(ldlocInstruction); _il.Remove(ldlocInstruction); if (lastRetInstruction.Previous?.OpCode == OpCodes.Ret) { _il.Remove(lastRetInstruction); } } if (insertedRet > 0) { _log.Debug($"Split single point of return: {insertedRet} ret inserted, original {(leaveOriginalReturnPoint ? "left" : "removed")}"); } }
public string ConsumeArgString(Instruction instruction) { switch (instruction.OpCode.Code) { case Code.Ldstr: _il.Remove(instruction); return((string)instruction.Operand); case Code.Ldnull: throw new InstructionWeavingException(instruction, "A non-null string literal is expected"); default: throw UnexpectedInstruction(instruction, "a string literal"); } }