/// <summary> /// Rewrites the instructions in the target method body. /// </summary> /// <param name="method">The target method.</param> /// <param name="IL">The <see cref="CilWorker"/> instance that represents the method body.</param> /// <param name="oldInstructions">The IL instructions of the original method body.</param> protected override void RewriteMethodBody(MethodDefinition method, CilWorker IL, IEnumerable <Instruction> oldInstructions) { if (IsExcluded(method)) { AddOriginalInstructions(IL, oldInstructions); return; } VariableDefinition interceptionDisabled = method.AddLocal <bool>(); VariableDefinition invocationInfo = method.AddLocal <IInvocationInfo>(); VariableDefinition aroundInvokeProvider = method.AddLocal <IAroundInvokeProvider>(); VariableDefinition methodReplacementProvider = method.AddLocal <IMethodReplacementProvider>(); VariableDefinition returnValue = method.AddLocal <object>(); VariableDefinition classMethodReplacementProvider = method.AddLocal <IMethodReplacementProvider>(); Func <ModuleDefinition, MethodReference> getInstanceMethodReplacementProviderMethod = module => module.Import(typeof(IMethodReplacementHost).GetMethod("get_MethodBodyReplacementProvider")); var parameters = new MethodBodyRewriterParameters(IL, oldInstructions, interceptionDisabled, invocationInfo, returnValue, methodReplacementProvider, aroundInvokeProvider, classMethodReplacementProvider, getInstanceMethodReplacementProviderMethod, typeof(AroundMethodBodyRegistry)); var emitter = new InvocationInfoEmitter(true); IInstructionEmitter getMethodReplacementProvider = new GetMethodReplacementProvider(methodReplacementProvider, method, getInstanceMethodReplacementProviderMethod); IInstructionEmitter getInterceptionDisabled = new GetInterceptionDisabled(parameters); ISurroundMethodBody surroundMethodBody = new SurroundMethodBody(parameters, "AroundMethodBodyProvider"); IInstructionEmitter getClassMethodReplacementProvider = new GetClassMethodReplacementProvider(parameters, module => module.Import( typeof( MethodBodyReplacementProviderRegistry ). GetMethod ("GetProvider"))); IInstructionEmitter addMethodReplacement = new AddMethodReplacementImplementation(parameters); var rewriter = new InterceptAndSurroundMethodBody(emitter, getInterceptionDisabled, surroundMethodBody, getMethodReplacementProvider, getClassMethodReplacementProvider, addMethodReplacement, parameters); // Determine whether or not the method should be intercepted rewriter.Rewrite(method, IL, oldInstructions); }
/// <summary> /// Rewrites the instructions in the target method body. /// </summary> /// <param name="method">The target method.</param> /// <param name="IL">The <see cref="CilWorker"/> instance that represents the method body.</param> /// <param name="oldInstructions">The IL instructions of the original method body.</param> protected override void RewriteMethodBody(MethodDefinition method, CilWorker IL, IEnumerable<Instruction> oldInstructions) { if (IsExcluded(method)) { AddOriginalInstructions(IL, oldInstructions); return; } VariableDefinition interceptionDisabled = method.AddLocal<bool>(); VariableDefinition invocationInfo = method.AddLocal<IInvocationInfo>(); VariableDefinition aroundInvokeProvider = method.AddLocal<IAroundInvokeProvider>(); VariableDefinition methodReplacementProvider = method.AddLocal<IMethodReplacementProvider>(); VariableDefinition returnValue = method.AddLocal<object>(); VariableDefinition classMethodReplacementProvider = method.AddLocal<IMethodReplacementProvider>(); Func<ModuleDefinition, MethodReference> getInstanceMethodReplacementProviderMethod = module => module.Import(typeof (IMethodReplacementHost).GetMethod("get_MethodBodyReplacementProvider")); var parameters = new MethodBodyRewriterParameters(IL, oldInstructions, interceptionDisabled, invocationInfo, returnValue, aroundInvokeProvider, methodReplacementProvider, classMethodReplacementProvider, getInstanceMethodReplacementProviderMethod, typeof (AroundMethodBodyRegistry)); var emitter = new InvocationInfoEmitter(true); IInstructionEmitter getMethodReplacementProvider = new GetMethodReplacementProvider(methodReplacementProvider, method, getInstanceMethodReplacementProviderMethod); IInstructionEmitter getInterceptionDisabled = new GetInterceptionDisabled(parameters); ISurroundMethodBody surroundMethodBody = new SurroundMethodBody(parameters, "AroundMethodBodyProvider"); IInstructionEmitter getClassMethodReplacementProvider = new GetClassMethodReplacementProvider(parameters, module => module.Import( typeof ( MethodBodyReplacementProviderRegistry ). GetMethod ("GetProvider"))); IInstructionEmitter addMethodReplacement = new AddMethodReplacementImplementation(parameters); var rewriter = new InterceptAndSurroundMethodBody(emitter, getInterceptionDisabled, surroundMethodBody, getMethodReplacementProvider, getClassMethodReplacementProvider, addMethodReplacement, parameters); // Determine whether or not the method should be intercepted rewriter.Rewrite(method, IL, oldInstructions); }
/// <summary> /// Rewrites the instructions in the target method body to support dynamic exception handling. /// </summary> /// <param name="targetMethod">The target method.</param> /// <param name="IL">The <see cref="CilWorker"/> instance that represents the method body.</param> /// <param name="oldInstructions">The IL instructions of the original method body.</param> protected override void RewriteMethodBody(MethodDefinition targetMethod, CilWorker IL, IEnumerable <Instruction> oldInstructions) { var endOfOriginalInstructionBlock = IL.Create(OpCodes.Nop); var addOriginalInstructions = new AddOriginalInstructions(oldInstructions, endOfOriginalInstructionBlock); var endLabel = IL.Create(OpCodes.Nop); var tryStart = IL.Emit(OpCodes.Nop); var tryEnd = IL.Emit(OpCodes.Nop); var catchStart = IL.Emit(OpCodes.Nop); var catchEnd = IL.Emit(OpCodes.Nop); var module = IL.GetModule(); var handler = new ExceptionHandler(ExceptionHandlerType.Catch); var body = targetMethod.Body; body.ExceptionHandlers.Add(handler); handler.CatchType = module.ImportType <Exception>(); handler.TryStart = tryStart; handler.TryEnd = tryEnd; handler.HandlerStart = catchStart; handler.HandlerEnd = catchEnd; var emitter = new InvocationInfoEmitter(true); var returnType = targetMethod.ReturnType.ReturnType; // try { IL.Append(tryStart); addOriginalInstructions.Emit(IL); IL.Append(endOfOriginalInstructionBlock); if (returnType != _voidType && _returnValue != null) { IL.Emit(OpCodes.Stloc, _returnValue); } IL.Emit(OpCodes.Leave, endLabel); // } IL.Append(tryEnd); // catch (Exception ex) { IL.Append(catchStart); IL.Emit(OpCodes.Stloc, _exception); SaveExceptionInfo(targetMethod, emitter); IL.Emit(OpCodes.Ldloc, _exceptionInfo); var getHandlerMethodInfo = typeof(ExceptionHandlerRegistry).GetMethod("GetHandler"); var getHandlerMethod = module.Import(getHandlerMethodInfo); IL.Emit(OpCodes.Call, getHandlerMethod); IL.Emit(OpCodes.Stloc, _exceptionHandler); // if (exceptionHandler == null) // throw; var doRethrow = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Brfalse, doRethrow); // if (handler.CanCatch(exceptionInfo)) { var leaveBlock = IL.Create(OpCodes.Nop); var canCatch = module.ImportMethod <IExceptionHandler>("CanCatch"); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, canCatch); IL.Emit(OpCodes.Brfalse, doRethrow); var catchMethod = module.ImportMethod <IExceptionHandler>("Catch"); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, catchMethod); // } var getShouldSkipRethrow = module.ImportMethod <IExceptionHandlerInfo>("get_ShouldSkipRethrow"); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, getShouldSkipRethrow); IL.Emit(OpCodes.Brfalse, doRethrow); IL.Emit(OpCodes.Br, leaveBlock); IL.Append(doRethrow); IL.Emit(OpCodes.Rethrow); IL.Append(leaveBlock); IL.Emit(OpCodes.Leave, endLabel); IL.Append(catchEnd); // } IL.Append(endLabel); if (returnType != _voidType && _returnValue != null) { var returnOriginalValue = IL.Create(OpCodes.Nop); var getReturnValue = module.ImportMethod <IExceptionHandlerInfo>("get_ReturnValue"); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Brfalse, returnOriginalValue); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, getReturnValue); IL.Emit(OpCodes.Stloc, _returnValue); IL.Append(returnOriginalValue); IL.Emit(OpCodes.Ldloc, _returnValue); } IL.Emit(OpCodes.Ret); }
/// <summary> /// Rewrites the instructions in the target method body to support dynamic exception handling. /// </summary> /// <param name="targetMethod">The target method.</param> /// <param name="IL">The <see cref="CilWorker"/> instance that represents the method body.</param> /// <param name="oldInstructions">The IL instructions of the original method body.</param> protected override void RewriteMethodBody(MethodDefinition targetMethod, CilWorker IL, IEnumerable<Instruction> oldInstructions) { var endOfOriginalInstructionBlock = IL.Create(OpCodes.Nop); var addOriginalInstructions = new AddOriginalInstructions(oldInstructions, endOfOriginalInstructionBlock); var endLabel = IL.Create(OpCodes.Nop); var tryStart = IL.Emit(OpCodes.Nop); var tryEnd = IL.Emit(OpCodes.Nop); var catchStart = IL.Emit(OpCodes.Nop); var catchEnd = IL.Emit(OpCodes.Nop); var module = IL.GetModule(); var handler = new ExceptionHandler(ExceptionHandlerType.Catch); var body = targetMethod.Body; body.ExceptionHandlers.Add(handler); handler.CatchType = module.ImportType<Exception>(); handler.TryStart = tryStart; handler.TryEnd = tryEnd; handler.HandlerStart = catchStart; handler.HandlerEnd = catchEnd; var emitter = new InvocationInfoEmitter(true); var returnType = targetMethod.ReturnType.ReturnType; // try { IL.Append(tryStart); addOriginalInstructions.Emit(IL); IL.Append(endOfOriginalInstructionBlock); if (returnType != _voidType && _returnValue != null) { IL.Emit(OpCodes.Stloc, _returnValue); } IL.Emit(OpCodes.Leave, endLabel); // } IL.Append(tryEnd); // catch (Exception ex) { IL.Append(catchStart); IL.Emit(OpCodes.Stloc, _exception); SaveExceptionInfo(targetMethod, emitter); IL.Emit(OpCodes.Ldloc, _exceptionInfo); var getHandlerMethodInfo = typeof (ExceptionHandlerRegistry).GetMethod("GetHandler"); var getHandlerMethod = module.Import(getHandlerMethodInfo); IL.Emit(OpCodes.Call, getHandlerMethod); IL.Emit(OpCodes.Stloc, _exceptionHandler); // if (exceptionHandler == null) // throw; var doRethrow = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Brfalse, doRethrow); // if (handler.CanCatch(exceptionInfo)) { var leaveBlock = IL.Create(OpCodes.Nop); var canCatch = module.ImportMethod<IExceptionHandler>("CanCatch"); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, canCatch); IL.Emit(OpCodes.Brfalse, doRethrow); var catchMethod = module.ImportMethod<IExceptionHandler>("Catch"); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, catchMethod); // } var getShouldSkipRethrow = module.ImportMethod<IExceptionHandlerInfo>("get_ShouldSkipRethrow"); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, getShouldSkipRethrow); IL.Emit(OpCodes.Brfalse, doRethrow); IL.Emit(OpCodes.Br, leaveBlock); IL.Append(doRethrow); IL.Emit(OpCodes.Rethrow); IL.Append(leaveBlock); IL.Emit(OpCodes.Leave, endLabel); IL.Append(catchEnd); // } IL.Append(endLabel); if (returnType != _voidType && _returnValue != null) { var returnOriginalValue = IL.Create(OpCodes.Nop); var getReturnValue = module.ImportMethod<IExceptionHandlerInfo>("get_ReturnValue"); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Brfalse, returnOriginalValue); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, getReturnValue); IL.Emit(OpCodes.Stloc, _returnValue); IL.Append(returnOriginalValue); IL.Emit(OpCodes.Ldloc, _returnValue); } IL.Emit(OpCodes.Ret); }
/// <summary> /// Initializes the class with the default values. /// </summary> public MethodBodyEmitter() { InvocationInfoEmitter = new InvocationInfoEmitter(); }