/// <summary> /// Adds method body interception to the target method. /// </summary> /// <param name="IL">The <see cref="ILProcessor" /> pointing to the target method body.</param> public void Emit(ILProcessor IL) { var method = IL.Body.Method; var returnType = method.ReturnType; var endLabel = IL.Create(OpCodes.Nop); var executeOriginalInstructions = IL.Create(OpCodes.Nop); // Execute the method body replacement if and only if // interception is enabled IL.Emit(OpCodes.Ldloc, _interceptionDisabled); IL.Emit(OpCodes.Brtrue, executeOriginalInstructions); var invokeReplacement = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, _methodReplacementProvider); IL.Emit(OpCodes.Brtrue, invokeReplacement); IL.Emit(OpCodes.Ldloc, _classMethodReplacementProvider); IL.Emit(OpCodes.Brtrue, invokeReplacement); IL.Emit(OpCodes.Br, executeOriginalInstructions); IL.Append(invokeReplacement); // This is equivalent to the following code: // var replacement = provider.GetMethodReplacement(info); var invokeMethodReplacement = new InvokeMethodReplacement(executeOriginalInstructions, _methodReplacementProvider, _classMethodReplacementProvider, _invocationInfo); invokeMethodReplacement.Emit(IL); IL.Emit(OpCodes.Br, endLabel); IL.Append(executeOriginalInstructions); var addOriginalInstructions = new AddOriginalInstructions(_oldInstructions, endLabel); addOriginalInstructions.Emit(IL); // Mark the end of the method body IL.Append(endLabel); var saveReturnValue = new SaveReturnValue(returnType, _returnValue); saveReturnValue.Emit(IL); }
public void Emit(CilWorker IL) { var method = IL.GetMethod(); var returnType = method.ReturnType.ReturnType; var endLabel = IL.Create(OpCodes.Nop); var executeOriginalInstructions = IL.Create(OpCodes.Nop); // Execute the method body replacement if and only if // interception is enabled IL.Emit(OpCodes.Ldloc, _interceptionDisabled); IL.Emit(OpCodes.Brtrue, executeOriginalInstructions); var invokeReplacement = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, _methodReplacementProvider); IL.Emit(OpCodes.Brtrue, invokeReplacement); IL.Emit(OpCodes.Ldloc, _classMethodReplacementProvider); IL.Emit(OpCodes.Brtrue, invokeReplacement); IL.Emit(OpCodes.Br, executeOriginalInstructions); IL.Append(invokeReplacement); // This is equivalent to the following code: // var replacement = provider.GetMethodReplacement(info); var invokeMethodReplacement = new InvokeMethodReplacement(executeOriginalInstructions, _methodReplacementProvider, _classMethodReplacementProvider, _invocationInfo); invokeMethodReplacement.Emit(IL); IL.Emit(OpCodes.Br, endLabel); #region The original instruction block IL.Append(executeOriginalInstructions); var addOriginalInstructions = new AddOriginalInstructions(_oldInstructions, endLabel); addOriginalInstructions.Emit(IL); #endregion // Mark the end of the method body IL.Append(endLabel); var saveReturnValue = new SaveReturnValue(returnType, _returnValue); saveReturnValue.Emit(IL); }
/// <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); }