private void ProcessIlEmitMethodCall(Instruction emitCallInstruction, out Instruction?nextInstruction) { var emittedInstruction = CreateInstructionToEmit(); _il.Replace(emitCallInstruction, emittedInstruction); if (emittedInstruction.OpCode.OpCodeType == OpCodeType.Prefix) { _il.RemoveNopsAfter(emittedInstruction); } var sequencePoint = _sequencePoints.MapSequencePoint(emitCallInstruction, emittedInstruction); if (emittedInstruction.Previous?.OpCode.OpCodeType == OpCodeType.Prefix) { _sequencePoints.MergeWithPreviousSequencePoint(sequencePoint); } nextInstruction = emittedInstruction.NextSkipNops(); switch (emittedInstruction.OpCode.Code) { case Code.Ret: case Code.Endfinally: case Code.Endfilter: { if (nextInstruction?.OpCode == emittedInstruction.OpCode) { _il.Remove(emittedInstruction); _log.Debug($"Removed duplicate {emittedInstruction.OpCode}"); } break; } case Code.Leave: case Code.Leave_S: case Code.Throw: case Code.Rethrow: { if (nextInstruction?.OpCode == OpCodes.Leave || nextInstruction?.OpCode == OpCodes.Leave_S) { _il.RemoveNopsAfter(emittedInstruction); _il.Remove(emittedInstruction); _il.Replace(nextInstruction, emittedInstruction); _log.Debug($"Replaced {nextInstruction.OpCode} with emitted {emittedInstruction.OpCode}"); nextInstruction = emittedInstruction.NextSkipNops(); } break; } } Instruction CreateInstructionToEmit() { var method = (MethodReference)emitCallInstruction.Operand; var opCode = OpCodeMap.FromCecilFieldName(method.Name); var args = _il.GetArgumentPushInstructionsInSameBasicBlock(emitCallInstruction); switch (opCode.OperandType) { case OperandType.InlineNone: if (args.Length != 0) { throw new InstructionWeavingException(emitCallInstruction, "Unexpected operand argument"); } return(_il.Create(opCode)); case OperandType.InlineI: case OperandType.ShortInlineI: case OperandType.InlineI8: case OperandType.InlineR: case OperandType.ShortInlineR: return(_il.CreateConst(opCode, _consumer.ConsumeArgConst(args.Single()))); case OperandType.InlineString: return(_il.CreateConst(opCode, _consumer.ConsumeArgString(args.Single()))); case OperandType.InlineType: { if (method.IsGenericInstance) { return(_il.Create(opCode, ((GenericInstanceMethod)method).GenericArguments[0])); } return(_il.Create(opCode, _consumer.ConsumeArgTypeRef(args.Single()))); } case OperandType.InlineMethod: return(_il.Create(opCode, _consumer.ConsumeArgMethodRef(args.Single()))); case OperandType.InlineField: return(_il.Create(opCode, _consumer.ConsumeArgFieldRef(args.Single()))); case OperandType.InlineTok: { if (method.IsGenericInstance) { return(_il.Create(opCode, ((GenericInstanceMethod)method).GenericArguments[0])); } return(method.Parameters[0].ParameterType.FullName switch { KnownNames.Full.TypeRefType => _il.Create(opCode, _consumer.ConsumeArgTypeRef(args.Single())), KnownNames.Full.MethodRefType => _il.Create(opCode, _consumer.ConsumeArgMethodRef(args.Single())), KnownNames.Full.FieldRefType => _il.Create(opCode, _consumer.ConsumeArgFieldRef(args.Single())), _ => throw new InstructionWeavingException(emitCallInstruction, $"Unexpected argument type: {method.Parameters[0].ParameterType.FullName}") }); }
private TypeRefBuilder ConsumeArgTypeRefBuilder(Instruction instruction) { if (instruction.OpCode.FlowControl != FlowControl.Call || !(instruction.Operand is MethodReference method)) { throw UnexpectedInstruction(instruction, "a method call"); } switch (method.FullName) { case "System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)": { var ldToken = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single(); if (ldToken.OpCode != OpCodes.Ldtoken) { throw UnexpectedInstruction(ldToken, OpCodes.Ldtoken); } var builder = new TypeRefBuilder(Module, (TypeReference)ldToken.Operand); _il.Remove(ldToken); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.TypeRef::op_Implicit(System.Type)": case "System.Void InlineIL.TypeRef::.ctor(System.Type)": { var builder = ConsumeArgTypeRefBuilder(_il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single()); _il.Remove(instruction); return(builder); } case "System.Void InlineIL.TypeRef::.ctor(System.String,System.String)": { var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction); var assemblyName = ConsumeArgString(args[0]); var typeName = ConsumeArgString(args[1]); var builder = new TypeRefBuilder(Module, assemblyName, typeName); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.GenericParameters::get_Item(System.Int32)": { var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction); var genericParameterType = ConsumeArgGenericParameterType(args[0]); var genericParameterIndex = ConsumeArgInt32(args[1]); var builder = new TypeRefBuilder(Module, genericParameterType, genericParameterIndex); _il.Remove(instruction); return(builder); } case "System.Type System.Type::MakeGenericMethodParameter(System.Int32)": { var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction); var genericParameterIndex = ConsumeArgInt32(args[0]); var builder = new TypeRefBuilder(Module, GenericParameterType.Method, genericParameterIndex); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.TypeRef::MakePointerType()": case "System.Type System.Type::MakePointerType()": { var builder = ConsumeArgTypeRefBuilder(_il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single()); builder.MakePointerType(); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.TypeRef::MakeByRefType()": case "System.Type System.Type::MakeByRefType()": { var builder = ConsumeArgTypeRefBuilder(_il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single()); builder.MakeByRefType(); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.TypeRef::MakeArrayType()": case "System.Type System.Type::MakeArrayType()": { var builder = ConsumeArgTypeRefBuilder(_il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single()); builder.MakeArrayType(1); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.TypeRef::MakeArrayType(System.Int32)": case "System.Type System.Type::MakeArrayType(System.Int32)": { var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction); var builder = ConsumeArgTypeRefBuilder(args[0]); var rank = ConsumeArgInt32(args[1]); builder.MakeArrayType(rank); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.TypeRef::MakeGenericType(InlineIL.TypeRef[])": case "System.Type System.Type::MakeGenericType(System.Type[])": { var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction); var builder = ConsumeArgTypeRefBuilder(args[0]); var genericArgs = ConsumeArgArray(args[1], ConsumeArgTypeRefBuilder); builder.MakeGenericType(genericArgs); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.TypeRef::WithOptionalModifier(InlineIL.TypeRef)": { var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction); var builder = ConsumeArgTypeRefBuilder(args[0]); var modifierType = ConsumeArgTypeRef(args[1]); builder.AddOptionalModifier(modifierType); _il.Remove(instruction); return(builder); } case "InlineIL.TypeRef InlineIL.TypeRef::WithRequiredModifier(InlineIL.TypeRef)": { var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction); var builder = ConsumeArgTypeRefBuilder(args[0]); var modifierType = ConsumeArgTypeRef(args[1]); builder.AddRequiredModifier(modifierType); _il.Remove(instruction); return(builder); } default: throw UnexpectedInstruction(instruction, "a type reference"); } }