@@ -515,5 +515,96 @@ public static bool IsArrayAccessors(this IMethod method) {
515515 }
516516 return false ;
517517 }
518+
519+ /// <summary>
520+ /// Merges a specified call instruction into the body.
521+ /// </summary>
522+ /// <param name="targetBody">The target body</param>
523+ /// <param name="callInstruction">The instruction to merge in</param>
524+ public static void MergeCall ( this CilBody targetBody , Instruction callInstruction ) {
525+ if ( ! ( callInstruction . Operand is MethodDef methodToMerge ) )
526+ throw new ArgumentException ( "Call instruction has invalid operand" ) ;
527+ if ( ! methodToMerge . HasBody )
528+ throw new Exception ( "Method to merge has no body!" ) ;
529+
530+ var localParams = methodToMerge . Parameters . ToDictionary ( param => param . Index , param => new Local ( param . Type ) ) ;
531+ var localMap = methodToMerge . Body . Variables . ToDictionary ( local => local , local => new Local ( local . Type ) ) ;
532+ foreach ( var local in localParams )
533+ targetBody . Variables . Add ( local . Value ) ;
534+ foreach ( var local in localMap )
535+ targetBody . Variables . Add ( local . Value ) ;
536+
537+ // Nop the call
538+ int index = targetBody . Instructions . IndexOf ( callInstruction ) ;
539+ targetBody . Instructions [ index ++ ] . OpCode = OpCodes . Nop ;
540+ var afterIndex = targetBody . Instructions [ index ] ;
541+
542+ // Find Exception handler index
543+ int exIndex = 0 ;
544+ foreach ( var ex in targetBody . ExceptionHandlers ) {
545+ if ( targetBody . Instructions . IndexOf ( ex . TryStart ) < index )
546+ exIndex = targetBody . ExceptionHandlers . IndexOf ( ex ) ;
547+ }
548+
549+ // setup parameter locals
550+ foreach ( var paramLocal in localParams . Reverse ( ) ) {
551+ targetBody . Instructions . Insert ( index ++ , new Instruction ( OpCodes . Stloc , paramLocal . Value ) ) ;
552+ }
553+
554+ var instrMap = new Dictionary < Instruction , Instruction > ( ) ;
555+ var newInstrs = new List < Instruction > ( ) ;
556+
557+ // Transfer instructions to list
558+ foreach ( var instr in methodToMerge . Body . Instructions ) {
559+ Instruction newInstr ;
560+ if ( instr . OpCode == OpCodes . Ret ) {
561+ newInstr = new Instruction ( OpCodes . Br , afterIndex ) ;
562+ }
563+ else if ( instr . IsLdarg ( ) ) {
564+ localParams . TryGetValue ( instr . GetParameterIndex ( ) , out var lc ) ;
565+ newInstr = new Instruction ( OpCodes . Ldloc , lc ) ;
566+ }
567+ else if ( instr . IsStarg ( ) ) {
568+ localParams . TryGetValue ( instr . GetParameterIndex ( ) , out var lc ) ;
569+ newInstr = new Instruction ( OpCodes . Stloc , lc ) ;
570+ }
571+ else if ( instr . IsLdloc ( ) ) {
572+ localMap . TryGetValue ( instr . GetLocal ( methodToMerge . Body . Variables ) , out var lc ) ;
573+ newInstr = new Instruction ( OpCodes . Ldloc , lc ) ;
574+ }
575+ else if ( instr . IsStloc ( ) ) {
576+ localMap . TryGetValue ( instr . GetLocal ( methodToMerge . Body . Variables ) , out var lc ) ;
577+ newInstr = new Instruction ( OpCodes . Stloc , lc ) ;
578+ }
579+ else {
580+ newInstr = new Instruction ( instr . OpCode , instr . Operand ) ;
581+ }
582+
583+ newInstrs . Add ( newInstr ) ;
584+ instrMap [ instr ] = newInstr ;
585+ }
586+
587+ // Fix branch targets & add instructions
588+ foreach ( var instr in newInstrs ) {
589+ if ( instr . Operand != null && instr . Operand is Instruction instrOp && instrMap . ContainsKey ( instrOp ) )
590+ instr . Operand = instrMap [ instrOp ] ;
591+ else if ( instr . Operand is Instruction [ ] instructionArrayOp )
592+ instr . Operand = instructionArrayOp . Select ( target => instrMap [ target ] ) . ToArray ( ) ;
593+
594+ targetBody . Instructions . Insert ( index ++ , instr ) ;
595+ }
596+
597+ // Add Exception Handlers
598+ foreach ( var eh in methodToMerge . Body . ExceptionHandlers ) {
599+ targetBody . ExceptionHandlers . Insert ( ++ exIndex , new ExceptionHandler ( eh . HandlerType ) {
600+ CatchType = eh . CatchType ,
601+ TryStart = instrMap [ eh . TryStart ] ,
602+ TryEnd = instrMap [ eh . TryEnd ] ,
603+ HandlerStart = instrMap [ eh . HandlerStart ] ,
604+ HandlerEnd = instrMap [ eh . HandlerEnd ] ,
605+ FilterStart = eh . FilterStart == null ? null : instrMap [ eh . FilterStart ]
606+ } ) ;
607+ }
608+ }
518609 }
519610}
0 commit comments