/// <summary> /// Initializes a new instance of the <see cref="MethodBodyRewriterParameters"/> class. /// </summary> /// <param name="IL">The CilWorker that is responsible for the current method body.</param> /// <param name="oldInstructions">The value indicating the list of old instructions in the current method body.</param> /// <param name="interceptionDisabled">The value that determines whether or not interception is disabled.</param> /// <param name="invocationInfo">The local variable that will store the <see cref="IInvocationInfo"/> instance.</param> /// <param name="returnValue">The value indicating the local variable that will store the return value.</param> /// <param name="methodReplacementProvider">The <see cref="IMethodReplacementProvider"/> instance.</param> /// <param name="aroundInvokeProvider">The <see cref="IAroundInvokeProvider"/> instance.</param> /// <param name="classMethodReplacementProvider">The class-level<see cref="IMethodReplacementProvider"/> instance.</param> /// <param name="getMethodReplacementProviderMethod">The functor that resolves the GetMethodReplacementProvider method.</param> /// <param name="registryType">The interception registry type that will be responsible for handling class-level interception events.</param> public MethodBodyRewriterParameters(CilWorker IL, IEnumerable<Instruction> oldInstructions, VariableDefinition interceptionDisabled, VariableDefinition invocationInfo, VariableDefinition returnValue, VariableDefinition methodReplacementProvider, VariableDefinition aroundInvokeProvider, VariableDefinition classMethodReplacementProvider, Func<ModuleDefinition, MethodReference> getMethodReplacementProviderMethod, Type registryType) { if (methodReplacementProvider.VariableType.FullName != typeof(IMethodReplacementProvider).FullName) throw new ArgumentException("methodReplacementProvider"); if (aroundInvokeProvider.VariableType.FullName != typeof(IAroundInvokeProvider).FullName) throw new ArgumentException("aroundInvokeProvider"); _cilWorker = IL; _oldInstructions = oldInstructions; _interceptionDisabled = interceptionDisabled; _invocationInfo = invocationInfo; _returnValue = returnValue; _methodReplacementProvider = methodReplacementProvider; _aroundInvokeProvider = aroundInvokeProvider; _classMethodReplacementProvider = classMethodReplacementProvider; _getMethodReplacementProviderMethod = getMethodReplacementProviderMethod; _registryType = registryType; }
public void Emit(CilWorker IL) { var module = IL.GetModule(); var modifiableType = module.ImportType<IModifiableType>(); var getInterceptionDisabledMethod = module.ImportMethod<IModifiableType>("get_IsInterceptionDisabled"); if (!_hostMethod.HasThis) { IL.Emit(OpCodes.Ldc_I4_0); IL.Emit(OpCodes.Stloc, _interceptionDisabled); return; } var skipLabel = IL.Create(OpCodes.Nop); // var interceptionDisabled = this.IsInterceptionDisabled; IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, modifiableType); IL.Emit(OpCodes.Brfalse, skipLabel); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, modifiableType); IL.Emit(OpCodes.Callvirt, getInterceptionDisabledMethod); IL.Emit(OpCodes.Stloc, _interceptionDisabled); IL.Append(skipLabel); }
/// <summary> /// Rewrites a target method using the given CilWorker. /// </summary> /// <param name="method">The target method.</param> /// <param name="IL">The CilWorker that will be used to rewrite the target method.</param> /// <param name="oldInstructions">The original instructions from the target method body.</param> public void Rewrite(MethodDefinition method, CilWorker IL, IEnumerable<Instruction> oldInstructions) { var declaringType = method.DeclaringType; var module = declaringType.Module; // Interfaces and Enums cannot be modified if (declaringType.IsInterface || declaringType.IsEnum) return; ImportReferences(module); AddLocals(method); if (!_modifiedTypes.Contains(declaringType)) { AddAdditionalMembers(declaringType); _modifiedTypes.Add(declaringType); } var newInstructions = new Queue<Instruction>(); foreach (var instruction in oldInstructions) { // Intercept only the load field and the load static field instruction if (!ShouldReplace(instruction, method)) { IL.Append(instruction); continue; } Replace(instruction, method, IL); } }
/// <summary> /// Rewrites a target method using the given CilWorker. /// </summary> /// <param name="method">The target method.</param> /// <param name="IL">The CilWorker that will be used to rewrite the target method.</param> /// <param name="oldInstructions">The original instructions from the target method body.</param> public void Rewrite(MethodDefinition method, CilWorker IL, IEnumerable<Instruction> oldInstructions) { if (!ShouldRewrite(method)) return; var declaringType = method.DeclaringType; var body = IL.GetBody(); body.InitLocals = true; var module = declaringType.Module; // Interfaces and Enums cannot be modified if (declaringType.IsInterface || declaringType.IsEnum) return; ImportReferences(module); AddLocals(method); if (!_modifiedTypes.Contains(declaringType)) { AddAdditionalMembers(declaringType); _modifiedTypes.Add(declaringType); } RewriteMethodBody(method, IL, oldInstructions); }
/// <summary> /// Adds the original instructions to a given method body. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> responsible for the target method body.</param> public void Emit(CilWorker IL) { var originalInstructions = new List<Instruction>(_oldInstructions); Instruction lastInstruction = originalInstructions.LastOrDefault(); if (lastInstruction != null && lastInstruction.OpCode == OpCodes.Ret) { // HACK: Convert the Ret instruction into a Nop // instruction so that the code will // fall through to the epilog lastInstruction.OpCode = OpCodes.Br; lastInstruction.Operand = _endLabel; } foreach (Instruction instruction in (IEnumerable<Instruction>) originalInstructions) { if (instruction.OpCode != OpCodes.Ret || instruction == lastInstruction) continue; if (lastInstruction == null) continue; // HACK: Modify all ret instructions to call // the epilog after execution instruction.OpCode = OpCodes.Br; instruction.Operand = lastInstruction; } // Emit the original instructions foreach (Instruction instruction in originalInstructions) { IL.Append(instruction); } }
/// <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> /// Emits the call to the <see cref="IAfterInvoke"/> instance. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> that points to the current method body.</param> public void Emit(CilWorker IL) { ModuleDefinition module = IL.GetModule(); // instanceAroundInvoke.AfterInvoke(info, returnValue); Emit(IL, module, _surroundingImplementation, _invocationInfo, _returnValue); // classAroundInvoke.AfterInvoke(info, returnValue); Emit(IL, module, _surroundingClassImplementation, _invocationInfo, _returnValue); }
/// <summary> /// Emits the instructions that obtain the <see cref="IAroundInvoke"/> instance. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> that points to the current method body.</param> public void Emit(CilWorker IL) { var method = IL.GetMethod(); var declaringType = method.DeclaringType; var module = declaringType.Module; var getSurroundingImplementation = module.Import(_getSurroundingImplementationMethod); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Call, getSurroundingImplementation); IL.Emit(OpCodes.Stloc, _surroundingClassImplementation); }
/// <summary> /// Emits the instructions that obtain the <see cref="IAroundInvoke"/> instance. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> that points to the current method body.</param> public void Emit(CilWorker IL) { MethodDefinition method = IL.GetMethod(); TypeDefinition declaringType = method.DeclaringType; ModuleDefinition module = declaringType.Module; MethodReference getSurroundingImplementation = module.Import(_getSurroundingImplementationMethod); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Call, getSurroundingImplementation); IL.Emit(OpCodes.Stloc, _surroundingClassImplementation); }
public ParameterContext(CilWorker worker, TypeReference interfaceType, MethodReference currentMethod, VariableDefinition currentArguments, VariableDefinition currentArgument, TypeReference targetDependency, MethodDefinition adapterConstructor, ParameterReference param) { CilWorker = worker; CurrentArguments = currentArguments; CurrentArgument = currentArgument; TargetDependency = targetDependency; Parameter = param; InterfaceType = interfaceType; AdapterConstructor = adapterConstructor; CurrentMethod = currentMethod; }
/// <summary> /// Saves the return value from a given method call. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param> public void Emit(CilWorker IL) { ModuleDefinition module = IL.GetModule(); TypeReference voidType = module.ImportType(typeof (void)); bool returnTypeIsValueType = _returnType != voidType && _returnType.IsValueType; if (_returnType is GenericParameter || returnTypeIsValueType) IL.Create(OpCodes.Box, _returnType); if (_returnType != voidType) IL.Create(OpCodes.Stloc, _returnValue); }
/// <summary> /// Saves the return value from a given method call. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param> public void Emit(CilWorker IL) { var module = IL.GetModule(); var voidType = module.ImportType(typeof (void)); var returnTypeIsValueType = _returnType != voidType && _returnType.IsValueType; if (_returnType is GenericParameter || returnTypeIsValueType) IL.Create(OpCodes.Box, _returnType); if (_returnType != voidType) IL.Create(OpCodes.Stloc, _returnValue); }
public void EmitNewObject(MethodDefinition hostMethod, CilWorker IL, MethodReference targetConstructor, TypeReference concreteType) { ParameterDefinitionCollection parameters = targetConstructor.Parameters; Instruction skipInterception = IL.Create(OpCodes.Nop); SaveConstructorArguments(IL, parameters); EmitCreateMethodActivationContext(hostMethod, IL, concreteType); // Skip the interception if an activator cannot be found EmitGetActivator(hostMethod, IL, skipInterception); IL.Emit(OpCodes.Stloc, _currentActivator); IL.Emit(OpCodes.Ldloc, _currentActivator); IL.Emit(OpCodes.Brfalse, skipInterception); // Determine if the activator can instantiate the method from the // current context IL.Emit(OpCodes.Ldloc, _currentActivator); IL.Emit(OpCodes.Ldloc, _methodContext); IL.Emit(OpCodes.Callvirt, _canActivate); IL.Emit(OpCodes.Brfalse, skipInterception); // Use the activator to create the object instance EmitCreateInstance(IL); // } Instruction endCreate = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Br, endCreate); // else { IL.Append(skipInterception); // Restore the arguments that were popped off the stack // by the list of constructor arguments int parameterCount = parameters.Count; for (int index = 0; index < parameterCount; index++) { ParameterDefinition currentParameter = parameters[index]; IL.Emit(OpCodes.Ldloc, _constructorArguments); IL.Emit(OpCodes.Ldc_I4, index); IL.Emit(OpCodes.Callvirt, _getItem); IL.Emit(OpCodes.Unbox_Any, currentParameter.ParameterType); } IL.Emit(OpCodes.Newobj, targetConstructor); // } IL.Append(endCreate); }
protected override void RewriteMethodBody(MethodDefinition method, CilWorker IL, IEnumerable<Instruction> oldInstructions) { var newInstructions = new Queue<Instruction>(); foreach (var instruction in oldInstructions) { if (!ShouldReplace(instruction, method)) { IL.Append(instruction); continue; } Replace(instruction, method, IL); } }
public void Emit(CilWorker IL) { var module = IL.GetModule(); var method = IL.GetMethod(); var getProvider = _resolveGetProviderMethod(module); var pushThis = method.HasThis ? OpCodes.Ldarg_0 : OpCodes.Ldnull; IL.Emit(pushThis); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Call, getProvider); IL.Emit(OpCodes.Stloc, _classMethodReplacementProvider); }
public void Emit(CilWorker IL) { var module = IL.GetModule(); IL.Emit(OpCodes.Ldloc, _aroundInvokeProvider); IL.Emit(OpCodes.Brfalse, _skipGetSurroundingImplementation); // var surroundingImplementation = this.GetSurroundingImplementation(this, invocationInfo); var getSurroundingImplementation = module.ImportMethod<IAroundInvokeProvider>("GetSurroundingImplementation"); IL.Emit(OpCodes.Ldloc, _aroundInvokeProvider); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Callvirt, getSurroundingImplementation); IL.Emit(OpCodes.Stloc, _surroundingImplementation); }
protected override void Replace(Instruction currentInstruction, MethodDefinition method, CilWorker IL) { var constructor = (MethodReference) currentInstruction.Operand; TypeReference concreteType = constructor.DeclaringType; ParameterDefinitionCollection parameters = constructor.Parameters; if (!_emitter.ShouldIntercept(constructor, concreteType, method)) { // Reuse the old instruction instead of emitting a new one IL.Append(currentInstruction); return; } _emitter.EmitNewObject(method, IL, constructor, concreteType); }
public void AddEpilog(CilWorker IL) { var skipEpilog = IL.Create(OpCodes.Nop); // if (!IsInterceptionDisabled && surroundingImplementation != null) { IL.Emit(OpCodes.Ldloc, _interceptionDisabled); IL.Emit(OpCodes.Brtrue, skipEpilog); // surroundingImplementation.AfterInvoke(invocationInfo, returnValue); var emitAfterInvoke = new EmitAfterInvoke(_surroundingImplementation, _surroundingClassImplementation, _invocationInfo, _returnValue); emitAfterInvoke.Emit(IL); // } IL.Append(skipEpilog); }
/// <summary> /// Adds method body interception to the target method. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param> public void Emit(CilWorker IL) { MethodDefinition method = IL.GetMethod(); TypeReference returnType = method.ReturnType.ReturnType; Instruction endLabel = IL.Create(OpCodes.Nop); Instruction 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); Instruction 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> /// Emits the call to the <see cref="IAfterInvoke"/> instance. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> that points to the current method body.</param> public void Emit(CilWorker IL) { var targetMethod = IL.GetMethod(); var declaringType = targetMethod.DeclaringType; var module = declaringType.Module; var getSurroundingClassImplementation = new GetSurroundingClassImplementation(_invocationInfo, _surroundingClassImplementation, _registryType.GetMethod( "GetSurroundingImplementation")); // var classAroundInvoke = AroundInvokeRegistry.GetSurroundingImplementation(info); getSurroundingClassImplementation.Emit(IL); // classAroundInvoke.BeforeInvoke(info); var skipInvoke = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, _surroundingClassImplementation); IL.Emit(OpCodes.Brfalse, skipInvoke); var beforeInvoke = module.ImportMethod<IBeforeInvoke>("BeforeInvoke"); // surroundingImplementation.BeforeInvoke(invocationInfo); IL.Emit(OpCodes.Ldloc, _surroundingClassImplementation); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Callvirt, beforeInvoke); IL.Append(skipInvoke); // if (surroundingImplementation != null) { if (!targetMethod.HasThis) return; var skipInvoke1 = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, _surroundingImplementation); IL.Emit(OpCodes.Brfalse, skipInvoke1); var beforeInvoke1 = module.ImportMethod<IBeforeInvoke>("BeforeInvoke"); // surroundingImplementation.BeforeInvoke(invocationInfo); IL.Emit(OpCodes.Ldloc, _surroundingImplementation); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Callvirt, beforeInvoke1); IL.Append(skipInvoke1); // } }
public void AddProlog(CilWorker IL) { var method = IL.GetMethod(); _surroundingImplementation = method.AddLocal<IAroundInvoke>(); _surroundingClassImplementation = method.AddLocal<IAroundInvoke>(); var skipProlog = IL.Create(OpCodes.Nop); var declaringType = method.DeclaringType; var module = declaringType.Module; var modifiableType = module.ImportType<IModifiableType>(); if (method.HasThis) { IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, modifiableType); IL.Emit(OpCodes.Brfalse, skipProlog); } IL.Emit(OpCodes.Ldloc, _interceptionDisabled); IL.Emit(OpCodes.Brtrue, skipProlog); // var provider = this.MethodReplacementProvider; if (_getMethodReplacementProvider != null) _getMethodReplacementProvider.Emit(IL); var getAroundInvokeProvider = new GetAroundInvokeProvider(_aroundInvokeProvider); getAroundInvokeProvider.Emit(IL); // if (aroundInvokeProvider != null ) { var skipGetSurroundingImplementation = IL.Create(OpCodes.Nop); var getSurroundingImplementationInstance = new GetSurroundingImplementationInstance(_aroundInvokeProvider, _invocationInfo, _surroundingImplementation, skipGetSurroundingImplementation); getSurroundingImplementationInstance.Emit(IL); // } IL.Append(skipGetSurroundingImplementation); var emitBeforeInvoke = new EmitBeforeInvoke(_invocationInfo, _surroundingClassImplementation, _surroundingImplementation, _registryType); emitBeforeInvoke.Emit(IL); IL.Append(skipProlog); }
/// <summary> /// Emits the instructions that obtain the <see cref="IMethodReplacementProvider"/> instance. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> instance.</param> public void Emit(CilWorker IL) { MethodDefinition method = _hostMethod; TypeDefinition declaringType = method.DeclaringType; ModuleDefinition module = declaringType.Module; if (!method.HasThis) { IL.Emit(OpCodes.Ldnull); IL.Emit(OpCodes.Stloc, _methodReplacementProvider); return; } MethodReference getProvider = _resolveGetProviderMethod(module); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Callvirt, getProvider); IL.Emit(OpCodes.Stloc, _methodReplacementProvider); }
public void Emit(CilWorker IL) { var method = _hostMethod; var declaringType = method.DeclaringType; var module = declaringType.Module; if (!method.HasThis) { IL.Emit(OpCodes.Ldnull); IL.Emit(OpCodes.Stloc, _methodReplacementProvider); return; } var getProvider = _resolveGetProviderMethod(module); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Callvirt, getProvider); IL.Emit(OpCodes.Stloc, _methodReplacementProvider); }
public void Emit(CilWorker IL) { var method = IL.GetMethod(); var module = IL.GetModule(); // var aroundInvokeProvider = this.AroundInvokeProvider; var getAroundInvokeProvider = module.ImportMethod<IModifiableType>("get_AroundInvokeProvider"); if (!method.HasThis) { IL.Emit(OpCodes.Ldnull); IL.Emit(OpCodes.Stloc, _aroundInvokeProvider); return; } IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Callvirt, getAroundInvokeProvider); IL.Emit(OpCodes.Stloc, _aroundInvokeProvider); }
/// <summary> /// Rewrites a target method using the given CilWorker. /// </summary> /// <param name="method">The target method.</param> /// <param name="IL">The CilWorker that will be used to rewrite the target method.</param> /// <param name="oldInstructions">The original instructions from the target method body.</param> public void Rewrite(MethodDefinition method, CilWorker IL, IEnumerable<Instruction> oldInstructions) { MethodDefinition targetMethod = _parameters.TargetMethod; CilWorker worker = targetMethod.GetILGenerator(); ModuleDefinition module = worker.GetModule(); _getInterceptionDisabled.Emit(worker); // Construct the InvocationInfo instance Instruction skipInvocationInfo = worker.Create(OpCodes.Nop); worker.Emit(OpCodes.Ldloc, _parameters.InterceptionDisabled); worker.Emit(OpCodes.Brtrue, skipInvocationInfo); MethodDefinition interceptedMethod = targetMethod; _emitter.Emit(targetMethod, interceptedMethod, _parameters.InvocationInfo); Instruction skipGetReplacementProvider = IL.Create(OpCodes.Nop); // var provider = this.MethodReplacementProvider; IL.Emit(OpCodes.Ldloc, _interceptionDisabled); IL.Emit(OpCodes.Brtrue, skipGetReplacementProvider); _getInstanceMethodReplacementProvider.Emit(IL); _surroundMethodBody.AddProlog(worker); IL.Append(skipGetReplacementProvider); worker.Append(skipInvocationInfo); _getClassMethodReplacementProvider.Emit(worker); TypeReference returnType = targetMethod.ReturnType.ReturnType; _addMethodReplacement.Emit(worker); // Save the return value TypeReference voidType = module.Import(typeof (void)); _surroundMethodBody.AddEpilog(worker); //if (returnType != voidType) // worker.Emit(OpCodes.Ldloc, _parameters.ReturnValue); worker.Emit(OpCodes.Ret); }
/// <summary> /// Initializes a new instance of the <see cref="MethodBodyRewriterParameters"/> class. /// </summary> /// <param name="IL">The CilWorker that is responsible for the current method body.</param> /// <param name="oldInstructions">The value indicating the list of old instructions in the current method body.</param> /// <param name="interceptionDisabled">The value that determines whether or not interception is disabled.</param> /// <param name="invocationInfo">The local variable that will store the <see cref="IInvocationInfo"/> instance.</param> /// <param name="returnValue">The value indicating the local variable that will store the return value.</param> /// <param name="methodReplacementProvider">The <see cref="IMethodReplacementProvider"/> instance.</param> /// <param name="aroundInvokeProvider">The <see cref="IAroundInvokeProvider"/> instance.</param> /// <param name="classMethodReplacementProvider">The class-level<see cref="IMethodReplacementProvider"/> instance.</param> /// <param name="getMethodReplacementProviderMethod">The functor that resolves the GetMethodReplacementProvider method.</param> /// <param name="registryType">The interception registry type that will be responsible for handling class-level interception events.</param> public MethodBodyRewriterParameters(CilWorker IL, IEnumerable<Instruction> oldInstructions, VariableDefinition interceptionDisabled, VariableDefinition invocationInfo, VariableDefinition returnValue, VariableDefinition methodReplacementProvider, VariableDefinition aroundInvokeProvider, VariableDefinition classMethodReplacementProvider, Func<ModuleDefinition, MethodReference> getMethodReplacementProviderMethod, Type registryType) { _cilWorker = IL; _oldInstructions = oldInstructions; _interceptionDisabled = interceptionDisabled; _invocationInfo = invocationInfo; _returnValue = returnValue; _methodReplacementProvider = methodReplacementProvider; _aroundInvokeProvider = aroundInvokeProvider; _classMethodReplacementProvider = classMethodReplacementProvider; _getMethodReplacementProviderMethod = getMethodReplacementProviderMethod; _registryType = registryType; }
/// <summary> /// Emits the call to obtain the <see cref="IAroundInvokeProvider"/> instance. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param> public void Emit(CilWorker IL) { MethodDefinition method = IL.GetMethod(); ModuleDefinition module = IL.GetModule(); // var aroundInvokeProvider = this.AroundInvokeProvider; string propertyName = string.Format("get_{0}", _providerName); MethodReference getAroundInvokeProvider = module.ImportMethod<IAroundInvokeHost>(propertyName); if (!method.HasThis) { IL.Emit(OpCodes.Ldnull); IL.Emit(OpCodes.Stloc, _aroundInvokeProvider); return; } IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Callvirt, getAroundInvokeProvider); IL.Emit(OpCodes.Stloc, _aroundInvokeProvider); }
public void Emit(CilWorker IL) { var module = IL.GetModule(); var method = IL.GetMethod(); var returnType = method.ReturnType.ReturnType; var methodReplacement = MethodDefinitionExtensions.AddLocal(method, typeof(IInterceptor)); GetMethodReplacementInstance(method, IL, methodReplacement, _methodReplacementProvider, _invocationInfo); var skipGetClassMethodReplacement = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Brtrue, skipGetClassMethodReplacement); GetMethodReplacementInstance(method, IL, methodReplacement, _classMethodReplacementProvider, _invocationInfo); IL.Append(skipGetClassMethodReplacement); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Brfalse, _executeOriginalInstructions); // var returnValue = replacement.Intercept(info); InvokeInterceptor(module, IL, methodReplacement, returnType, _invocationInfo); }
private static void Emit(CilWorker IL, ModuleDefinition module, VariableDefinition surroundingImplementation, VariableDefinition invocationInfo, VariableDefinition returnValue) { Instruction skipInvoke = IL.Create(OpCodes.Nop); Instruction skipPrint = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, surroundingImplementation); IL.Emit(OpCodes.Brtrue, skipPrint); IL.Append(skipPrint); IL.Emit(OpCodes.Ldloc, surroundingImplementation); IL.Emit(OpCodes.Brfalse, skipInvoke); MethodReference aroundInvoke = module.ImportMethod<IAfterInvoke>("AfterInvoke"); IL.Emit(OpCodes.Ldloc, surroundingImplementation); IL.Emit(OpCodes.Ldloc, invocationInfo); IL.Emit(OpCodes.Ldloc, returnValue); IL.Emit(OpCodes.Callvirt, aroundInvoke); IL.Append(skipInvoke); }
private static void GetMethodReplacementInstance(MethodDefinition method, CilWorker IL, VariableDefinition methodReplacement, VariableDefinition methodReplacementProvider, VariableDefinition invocationInfo) { var declaringType = method.DeclaringType; var module = declaringType.Module; var pushInstance = method.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull); var getReplacement = module.ImportMethod<IMethodReplacementProvider>("GetMethodReplacement"); IL.Emit(OpCodes.Ldloc, methodReplacementProvider); var skipGetMethodReplacement = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Brfalse, skipGetMethodReplacement); IL.Emit(OpCodes.Ldloc, methodReplacementProvider); IL.Append(pushInstance); IL.Emit(OpCodes.Ldloc, invocationInfo); IL.Emit(OpCodes.Callvirt, getReplacement); IL.Emit(OpCodes.Stloc, methodReplacement); IL.Append(skipGetMethodReplacement); }
internal static MethodBody Clone(MethodBody body, MethodDefinition parent, ImportContext context) { MethodBody nb = new MethodBody(parent); nb.MaxStack = body.MaxStack; nb.InitLocals = body.InitLocals; nb.CodeSize = body.CodeSize; CilWorker worker = nb.CilWorker; if (body.HasVariables) { foreach (VariableDefinition var in body.Variables) { nb.Variables.Add(new VariableDefinition( var.Name, var.Index, parent, context.Import(var.VariableType))); } } foreach (Instruction instr in body.Instructions) { Instruction ni = new Instruction(instr.OpCode); switch (instr.OpCode.OperandType) { case OperandType.InlineParam: case OperandType.ShortInlineParam: if (instr.Operand == body.Method.This) { ni.Operand = nb.Method.This; } else { int param = body.Method.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = parent.Parameters [param]; } break; case OperandType.InlineVar: case OperandType.ShortInlineVar: int var = body.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = nb.Variables [var]; break; case OperandType.InlineField: ni.Operand = context.Import((FieldReference)instr.Operand); break; case OperandType.InlineMethod: ni.Operand = context.Import((MethodReference)instr.Operand); break; case OperandType.InlineType: ni.Operand = context.Import((TypeReference)instr.Operand); break; case OperandType.InlineTok: if (instr.Operand is TypeReference) { ni.Operand = context.Import((TypeReference)instr.Operand); } else if (instr.Operand is FieldReference) { ni.Operand = context.Import((FieldReference)instr.Operand); } else if (instr.Operand is MethodReference) { ni.Operand = context.Import((MethodReference)instr.Operand); } break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: case OperandType.InlineSwitch: break; default: ni.Operand = instr.Operand; break; } worker.Append(ni); } for (int i = 0; i < body.Instructions.Count; i++) { Instruction instr = nb.Instructions [i]; Instruction oldi = body.Instructions [i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { Instruction [] olds = (Instruction [])oldi.Operand; Instruction [] targets = new Instruction [olds.Length]; for (int j = 0; j < targets.Length; j++) { targets [j] = GetInstruction(body, nb, olds [j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetInstruction(body, nb, (Instruction)oldi.Operand); } } if (!body.HasExceptionHandlers) { return(nb); } foreach (ExceptionHandler eh in body.ExceptionHandlers) { ExceptionHandler neh = new ExceptionHandler(eh.Type); neh.TryStart = GetInstruction(body, nb, eh.TryStart); neh.TryEnd = GetInstruction(body, nb, eh.TryEnd); neh.HandlerStart = GetInstruction(body, nb, eh.HandlerStart); neh.HandlerEnd = GetInstruction(body, nb, eh.HandlerEnd); switch (eh.Type) { case ExceptionHandlerType.Catch: neh.CatchType = context.Import(eh.CatchType); break; case ExceptionHandlerType.Filter: neh.FilterStart = GetInstruction(body, nb, eh.FilterStart); neh.FilterEnd = GetInstruction(body, nb, eh.FilterEnd); break; } nb.ExceptionHandlers.Add(neh); } return(nb); }