/// <summary> /// Create an advice that runs before the advised method. /// </summary> /// <param name="reflection">Reflection</param> /// <param name="advice">Delegate used to emit code to be invoked before the advised method</param> /// <returns>Advice</returns> static public Advice Before(this Advice.Style.IReflection reflection, Action <ILGenerator> advice) { return(new Advice((_Method, _Pointer, _Boundary) => { var _signature = _Method.Signature(); var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); if (_Boundary != null) //TODO dynamic implementation of boundary will avoid redirection overhead. { _body.Emit(advice); _body.Emit(OpCodes.Ret); _method.Prepare(); var _action = new DynamicMethod(string.Empty, Runtime.Void, new Type[] { Metadata <object> .Type, Metadata <object> .Type, Metadata <object[]> .Type }, true); var _redirection = _action.GetILGenerator(); if (_signature.Instance != null) { _redirection.Emit(OpCodes.Ldarg_1); if (_signature.Instance.IsValueType) { _redirection.Emit(OpCodes.Unbox_Any, _signature.Instance); } else { _redirection.Emit(OpCodes.Castclass, _signature.Instance); } } for (var _index = 0; _index < _signature.Length; _index++) { var _parameter = _signature[_index]; _redirection.Emit(OpCodes.Ldarg_2); _redirection.Emit(OpCodes.Ldc_I4, _index); //TODO shortcut _redirection.Emit(OpCodes.Ldelem_Ref); if (_parameter.IsValueType) { _redirection.Emit(OpCodes.Unbox_Any, _parameter); } else { _redirection.Emit(OpCodes.Castclass, _parameter); } } _redirection.Emit(OpCodes.Call, _method); _redirection.Emit(OpCodes.Ret); _action.Prepare(); return _Boundary.Combine(new Advice.Boundary.Advanced.Before.Singleton(_Method, _action.CreateDelegate(Metadata <Action <object, object[]> > .Type, null) as Action <object, object[]>)); } else { _body.Emit(advice); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; } })); }
/// <summary> /// Create an advice that runs after the advised method regardless of its outcome. /// </summary> /// <param name="reflection">Reflection</param> /// <param name="advice">Delegate used to emit code to be invoked after the advised method</param> /// <returns>Advice</returns> static public IAdvice After(this Advisor.IReflection reflection, Action <ILGenerator> advice) { return(new Advice((_Method, _Pointer) => { var _type = _Method.Type(); var _signature = _Method.Signature(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); if (_type == Metadata.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginFinallyBlock(); _body.Emit(advice); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_0); _body.BeginFinallyBlock(); _body.Emit(advice); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_0); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs before and after the advised method. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Delegate used to produce an expression of code to be invoked instaed of the advised method : Func(Expression = [expression of target instance of advised method call], IEnumerable(Expression) = [enumerable of expression of argument used to call advised method], Expression = [expression of advised method body]) return an expression to invoke instead of the advised method</param> /// <returns>Advice</returns> static public IAdvice Around(this Advisor.ILinq linq, Func <Expression, IEnumerable <Expression>, Expression, Expression> advice) { return(new Advice((_Method, _Pointer) => { var _type = _Method.Type(); var _signature = _Method.Signature(); var _parameters = new Collection <ParameterExpression>(_signature.Select(_Type => Expression.Parameter(_Type)).ToArray()); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Ret); var _advice = _signature.Instance == null ? advice(null, _parameters, Expression.Call(_method, _parameters)) : advice(_parameters[0], _parameters.Skip(1), Expression.Call(_method, _parameters)); if (_advice == null) { return null; } _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(OpCodes.Call, Expression.Lambda(_advice, _parameters).CompileToMethod()); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it completes successfully. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Expression (void) of code to be invoked after the advised method</param> /// <returns>Advice</returns> static public Advice Returning(this Advice.Style.Linq.IAfter linq, Expression advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(new Advice.Boundary.Basic.After.Returning.Singleton(Expression.Lambda <Action>(advice).Compile())); } var _signature = _Method.Signature(); if (advice == null) { return null; } if (advice.Type != Runtime.Void) { throw new NotSupportedException(); } var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
private IntPtr Override(MethodBase method, IntPtr pointer) { var _type = method.ReturnType(); var _signature = method.Signature(); var _parameters = new Collection <ParameterExpression>(_signature.Select(_Type => Expression.Parameter(_Type)).ToArray()); var _method = new DynamicMethod(string.Empty, _type, _signature, method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(pointer, _type, _signature); _body.Emit(OpCodes.Ret); var _invocation = _signature.Instance == null?this.Override(method, null, _parameters, Expression.Call(_method, _parameters)) : this.Override(method, _parameters[0], _parameters.Skip(1), Expression.Call(_method, _parameters)); if (_invocation == null) { return(pointer); } _method = new DynamicMethod(string.Empty, _type, _signature, method.DeclaringType, true); _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(OpCodes.Call, Expression.Lambda(_invocation, _parameters).CompileToMethod()); _body.Emit(OpCodes.Ret); _method.Prepare(); return(_method.GetFunctionPointer()); }
/// <summary> /// Create an advice that runs before the advised method. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked before the advised method : Action(object = [target instance of advised method call], object[] = [boxed arguments used to call advised method])</param> /// <returns>Advice</returns> static public Advice Before(this Advice.Style.IBasic basic, Action <object, object[]> advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(new Advice.Boundary.Advanced.Before.Singleton(_Method, advice)); } var _signature = _Method.Signature(); var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(OpCodes.Call, advice.Method); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs before the advised method. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked before the advised method</param> /// <returns>Advice</returns> static public Advice Before(this Advice.Style.IBasic basic, Action advice) { //TODO : test if asynchronous! if true, emit Boundary inheritor => if advice.Target == null && method is public => call directly method, other else, stora delegate as field and call it in before method. return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(new Advice.Boundary.Basic.Before.Singleton(advice)); } var _signature = _Method.Signature(); var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(OpCodes.Call, advice.Method); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it completes successfully. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Delegate used to produce an expression of code to be invoked after the advised method : Func(Expression = [expression of target instance of advised method call], IEnumerable<Expression> = [enumerable of expression of argument used to call advised method]) return an expression(void) of code to invoke after the advised method</param> /// <returns>Advice</returns> static public IAdvice Returning(this Advisor.Linq.IAfter linq, Func <Expression, IEnumerable <Expression>, Expression> advice) { return(new Advice((_Method, _Pointer) => { var _signature = _Method.Signature(); var _parameters = _signature.Select(_Type => Expression.Parameter(_Type)).ToArray(); var _advice = _signature.Instance == null ? advice(null, _parameters) : advice(_parameters[0], _parameters.Skip(1)); if (_advice == null) { return _Method; } if (_advice.Type != Metadata.Void) { throw new NotSupportedException(); } var _type = _Method.ReturnType; var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(_Pointer, _Method.ReturnType, _signature); _body.Emit(_signature, false); _body.Emit(OpCodes.Call, Expression.Lambda(_advice, _parameters).CompileToMethod()); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it exits by throwing an exception. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked after the advised method : Action(object = [target instance of advised method call], object[] = [boxed arguments used to call advised method], Exception = [exception thrown])</param> /// <returns>Advice</returns> static public Advice Throwing(this Advice.Style.Basic.IAfter basic, Action <object, object[], Exception> advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return new Advice.Boundary.Sequence.Factory(_Boundary, new Advice.Boundary.Advanced.After.Throwing.Singleton(_Method, advice)); } var _signature = _Method.Signature(); var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); _body.DeclareLocal(Metadata <Exception> .Type); if (_type == Runtime.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_0); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Call, advice.Method); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_1); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_0); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Call, advice.Method); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_1); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
static private MethodInfo Method(MethodBase method, IntPtr pointer) { var _type = method.Type(); var _signature = method.Signature(); var _method = new DynamicMethod(string.Empty, _type, _signature, method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(pointer, _type, _signature); _body.Emit(OpCodes.Ret); _method.Prepare(); return(_method); }
/// <summary> /// Create an advice that runs after the advised method only if it exits by throwing an exception. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked after the advised method : Action(object = [target instance of advised method call], object[] = [boxed arguments used to call advised method], Exception = [exception thrown])</param> /// <returns>Advice</returns> static public IAdvice Throwing(this Advisor.Basic.IAfter basic, Action <object, object[], Exception> advice) { return(new Advice((_Method, _Pointer) => { var _signature = _Method.Signature(); var _type = _Method.Type(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.DeclareLocal(Metadata <Exception> .Type); if (_type == Metadata.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_0); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advisor.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Call, advice.Method); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_1); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_0); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advisor.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Call, advice.Method); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_1); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it exits by throwing an exception. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Expression (void) of code to invoke after the advised method</param> /// <returns>Advice</returns> static public Advice Throwing(this Advice.Style.Linq.IAfter linq, Expression advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(new Advice.Boundary.Basic.After.Throwing.Singleton(Expression.Lambda <Action>(advice).Compile())); } var _signature = _Method.Signature(); var _exception = Expression.Parameter(Metadata <Exception> .Type); if (advice == null) { return null; } if (advice.Type != Runtime.Void) { throw new NotSupportedException(); } var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); if (_type == Runtime.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_0); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_0); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it exits by throwing an exception. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Delegate used to produce an expression of code to be invoked after the advised method : Func(Expression = [expression of target instance of advised method call], IEnumerable(Expression) = [enumerable of expression of argument used to call advised method]) return an expression(void) of code to invoke after the advised method</param> /// <returns>Advice</returns> static public IAdvice Throwing(this Advisor.Linq.IAfter linq, Func <Expression, IEnumerable <Expression>, Expression> advice) { return(new Advice((_Method, _Pointer) => { var _signature = _Method.Signature(); var _parameters = new Collection <ParameterExpression>(_signature.Select(_Type => Expression.Parameter(_Type)).ToArray()); var _exception = Expression.Parameter(Metadata <Exception> .Type); var _advice = _signature.Instance == null ? advice(null, _parameters) : advice(_parameters[0], _parameters.Skip(1)); if (_advice == null) { return null; } if (_advice.Type != Metadata.Void) { throw new NotSupportedException(); } var _type = _Method.Type(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); if (_type == Metadata.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(_signature, false); _body.Emit(OpCodes.Call, Expression.Lambda(_advice, _parameters).CompileToMethod()); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_0); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(_signature, false); _body.Emit(OpCodes.Call, Expression.Lambda(_advice, _parameters).CompileToMethod()); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_0); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs before the advised method. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Delegate used to produce an expression of code to be invoked before the advised method : Func(Expression = [expression of target instance of advised method call], IEnumerable(Expression) = [enumerable of expression of argument used to call advised method]) return an expression(void) of code to invoke before the advised method</param> /// <returns>Advice</returns> static public Advice Before(this Advice.Style.ILinq linq, Func <Expression, IEnumerable <Expression>, Expression> advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (advice == null) { return null; } var _signature = _Method.Signature(); if (_Boundary != null) { //TODO dynamic implementation will be faster by avoiding boxing/casting var _instance = Expression.Parameter(Metadata <object> .Type); var _arguments = Expression.Parameter(Metadata <object[]> .Type); var _advice = advice(_signature.Instance == null ? null : _signature.Instance.IsValueType ? Expression.Convert(_instance, _signature.Instance) : Expression.TypeAs(_instance, _signature.Instance), new Collection <Expression>(_signature.Parameters.Select((_Parameter, _Index) => _Parameter.IsValueType ? Expression.Convert(Expression.ArrayIndex(_arguments, Expression.Constant(_Index, Metadata <int> .Type)), _Parameter) : Expression.TypeAs(Expression.ArrayIndex(_arguments, Expression.Constant(_Index, Metadata <int> .Type)), _Parameter)).ToArray())); if (_advice == null) { return null; } if (_advice.Type != Runtime.Void) { throw new NotSupportedException(); } return _Boundary.Combine(new Advice.Boundary.Advanced.Before.Singleton(_Method, Expression.Lambda <Action <object, object[]> >(_advice, _instance, _arguments).Compile())); } else { var _parameters = new Collection <ParameterExpression>(_signature.Select(_Type => Expression.Parameter(_Type)).ToArray()); var _advice = _signature.Instance == null ? advice(null, _parameters) : advice(_parameters[0], _parameters.Skip(1)); if (_advice == null) { return null; } if (_advice.Type != Runtime.Void) { throw new NotSupportedException(); } var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(OpCodes.Call, Expression.Lambda(_advice, _parameters).CompileToMethod()); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; } })); }
/// <summary> /// Create an advice that runs before the advised method. /// </summary> /// <param name="reflection">Reflection</param> /// <param name="advice">Delegate used to emit code to be invoked before the advised method</param> /// <returns>Advice</returns> static public IAdvice Before(this Advisor.IReflection reflection, Action <ILGenerator> advice) { return(new Advice((_Method, _Pointer) => { var _signature = _Method.Signature(); var _method = new DynamicMethod(string.Empty, _Method.ReturnType, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.Emit(advice); _body.Emit(_signature, false); _body.Emit(_Pointer, _Method.ReturnType, _signature); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it exits by throwing an exception. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Expression (void) of code to invoke after the advised method</param> /// <returns>Advice</returns> static public IAdvice Throwing(this Advisor.Linq.IAfter linq, Expression advice) { return(new Advice((_Method, _Pointer) => { var _signature = _Method.Signature(); var _exception = Expression.Parameter(Metadata <Exception> .Type); if (advice == null) { return null; } if (advice.Type != Metadata.Void) { throw new NotSupportedException(); } var _type = _Method.Type(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); if (_type == Metadata.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_0); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_0); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs before and after the advised method. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked instead of the advised method : Action(object = [target instance of advised method call], object[] = [boxed arguments used to call advised method], Action = [delegate that invokes the advised method body])</param> /// <returns>Advice</returns> static public IAdvice Around(this Advisor.IBasic basic, Action <object, object[], Action> advice) { return(new Advice((_Method, _Pointer) => { var _type = _Method.Type(); var _signature = _Method.Signature(); var _routine = new Closure.Routine(_Pointer, _signature, _type); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); if (_type == Metadata.Void) { if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advisor.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(_signature, false); _body.Emit(OpCodes.Newobj, _routine.Constructor); _body.Emit(OpCodes.Ldftn, _routine.Method); _body.Emit(OpCodes.Newobj, Metadata <Action> .Type.GetConstructors().Single()); _body.Emit(OpCodes.Call, advice.Method); } else { _body.DeclareLocal(_routine.Type); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advisor.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(_signature, false); _body.Emit(OpCodes.Newobj, _routine.Constructor); _body.Emit(OpCodes.Stloc_0); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldftn, _routine.Method); _body.Emit(OpCodes.Newobj, Metadata <Action> .Type.GetConstructors().Single()); _body.Emit(OpCodes.Call, advice.Method); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldfld, _routine.Value); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it completes successfully. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked after the advised method : Action(object = [target instance of advised method call], object[] = [boxed arguments used to call advised method], object = [return value (null if return type is void)])</param> /// <returns>Advice</returns> static public Advice Returning(this Advice.Style.Basic.IAfter basic, Action <object, object[], object> advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(new Advice.Boundary.Advanced.After.Returning.Singleton(_Method, advice)); } var _signature = _Method.Signature(); var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); _body.DeclareLocal(Metadata <object> .Type); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); if (_type == Runtime.Void) { _body.Emit(OpCodes.Ldnull); } else { _body.Emit(OpCodes.Dup); if (_type.IsValueType) { _body.Emit(OpCodes.Box, _type); } else if (_type != Metadata <object> .Type) { _body.Emit(OpCodes.Castclass, Metadata <object> .Type); } } _body.Emit(OpCodes.Stloc_0); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Call, advice.Method); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs before the advised method. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked before the advised method</param> /// <returns>Advice</returns> static public IAdvice Before(this Advisor.IBasic basic, Action advice) { return(new Advice((_Method, _Pointer) => { var _signature = _Method.Signature(); var _method = new DynamicMethod(string.Empty, _Method.ReturnType, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advisor.Module.DefineField(advice.Target)); } _body.Emit(OpCodes.Call, advice.Method); _body.Emit(_signature, false); _body.Emit(_Pointer, _Method.ReturnType, _signature); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs before and after the advised method. /// </summary> /// <typeparam name="T">Resource to create before and dispose after method execution</typeparam> /// <param name="basic">Basic</param> /// <returns>Advice</returns> static public IAdvice Around <T>(this Advisor.IBasic basic) where T : class, IDisposable, new() { return(new Advice((_Method, _Pointer) => { var _type = _Method.Type(); var _signature = _Method.Signature(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.DeclareLocal(Metadata <T> .Type); if (_type == Metadata.Void) { _body.BeginExceptionBlock(); _body.Emit(OpCodes.Newobj, Metadata.Constructor(() => new T())); _body.Emit(OpCodes.Stloc_0); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginFinallyBlock(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IDisposable> .Method(_Disposable => _Disposable.Dispose())); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(OpCodes.Newobj, Metadata.Constructor(() => new T())); _body.Emit(OpCodes.Stloc_0); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_1); _body.BeginFinallyBlock(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IDisposable> .Method(_Disposable => _Disposable.Dispose())); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_1); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs before the advised method. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Expression of code to be invoked before the advised method</param> /// <returns>Advice</returns> static public IAdvice Before(this Advisor.ILinq linq, Expression advice) { return(new Advice((_Method, _Pointer) => { var _signature = _Method.Signature(); if (advice == null) { return null; } var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs before and after the advised method. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked instead of the advised method : Func(object = [target instance of advised method call], object[] = [boxed arguments used to call advised method], Func() = [delegate that invokes advised method body (return boxed return value or null if return type is void)]) return boxed return value (null if return type is void)</param> /// <returns>Advice</returns> static public IAdvice Around(this Advisor.IBasic basic, Func <object, object[], Func <object>, object> advice) { return(new Advice((_Method, _Pointer) => { var _type = _Method.Type(); var _signature = _Method.Signature(); var _function = new Closure.Function(_Pointer, _signature, _type); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advisor.Module.DefineField(advice.Target)); } _body.Emit(_signature, true); _body.Emit(_signature, false); _body.Emit(OpCodes.Newobj, _function.Constructor); _body.Emit(OpCodes.Ldftn, _function.Method); _body.Emit(OpCodes.Newobj, Metadata <Func <object> > .Type.GetConstructors().Single()); _body.Emit(OpCodes.Call, advice.Method); if (_type == Metadata.Void) { _body.Emit(OpCodes.Pop); } else { if (_type.IsValueType) { _body.Emit(OpCodes.Unbox_Any, _type); } else { _body.Emit(OpCodes.Castclass, _type); } } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it completes successfully. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Expression (void) of code to be invoked after the advised method</param> /// <returns>Advice</returns> static public IAdvice Returning(this Advisor.Linq.IAfter linq, Expression advice) { return(new Advice((_Method, _Pointer) => { var _signature = _Method.Signature(); if (advice == null) { return _Method; } if (advice.Type != Metadata.Void) { throw new NotSupportedException(); } var _type = _Method.ReturnType; var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(_Pointer, _Method.ReturnType, _signature); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it exits by throwing an exception. /// </summary> /// <param name="reflection">Reflection</param> /// <param name="advice">Delegate used to emit code to be invoked after the advised method</param> /// <returns>Advice</returns> static public Advice Throwing(this Advice.Style.Reflection.IAfter reflection, Action <ILGenerator> advice) { return(new Advice((_Method, _Pointer, _Boundary) => { var _type = _Method.ReturnType(); var _signature = _Method.Signature(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); if (_Boundary != null) //TODO dynamic implementation of boundary will avoid redirection overhead. { var _action = new DynamicMethod(string.Empty, Runtime.Void, new Type[] { Metadata <object> .Type, Metadata <object> .Type, Metadata <object[]> .Type, Metadata <Exception> .Type }, true); var _redirection = _action.GetILGenerator(); if (_signature.Instance != null) { _redirection.Emit(OpCodes.Ldarg_1); if (_signature.Instance.IsValueType) { _redirection.Emit(OpCodes.Unbox_Any, _signature.Instance); } else { _redirection.Emit(OpCodes.Castclass, _signature.Instance); } } for (var _index = 0; _index < _signature.Length; _index++) { var _parameter = _signature[_index]; _redirection.Emit(OpCodes.Ldarg_2); _redirection.Emit(OpCodes.Ldc_I4, _index); //TODO shortcut _redirection.Emit(OpCodes.Ldelem_Ref); if (_parameter.IsValueType) { _redirection.Emit(OpCodes.Unbox_Any, _parameter); } else { _redirection.Emit(OpCodes.Castclass, _parameter); } } if (_type != Runtime.Void) { var _exception = Advice.Module.DefineThreadField("<Exception>", Metadata <Exception> .Type); _redirection.Emit(OpCodes.Ldarg_3); _redirection.Emit(OpCodes.Stsfld, _exception); _body.Emit(OpCodes.Ldsfld, _exception); _body.Emit(OpCodes.Ldnull); _body.Emit(OpCodes.Stsfld, _exception); } _body.Emit(advice); _body.Emit(OpCodes.Ret); _method.Prepare(); _redirection.Emit(OpCodes.Call, _method); _redirection.Emit(OpCodes.Ret); _action.Prepare(); return _Boundary.Combine(new Advice.Boundary.Advanced.After.Throwing.Singleton(_Method, _action.CreateDelegate(Metadata <Action <object, object[], Exception> > .Type, null) as Action <object, object[], Exception>)); } else { if (_type == Runtime.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(advice); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_0); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(advice); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_0); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; } })); }
private MethodInfo Decorate(IntPtr pointer, Func <IAdvice> advise) { var _type = this.Method.ReturnType(); var _parameters = this.Method.GetParameters(); var _signature = this.Method.Signature(); var _method = new DynamicMethod(string.Empty, _type, _signature, this.Method.DeclaringType, true); var _body = _method.GetILGenerator(); var _factory = _body.DeclareLocal(Metadata <Func <IAdvice> > .Type); var _backup = _body.DeclareLocal(Metadata <Exception> .Type); var _exception = _body.DeclareLocal(Metadata <Exception> .Type); _body.Emit(OpCodes.Ldsfld, Aspect.Directory.Entry.Module.DefineField(Guid.NewGuid().ToString("N"), advise)); _body.Emit(OpCodes.Callvirt, Metadata <Func <IAdvice> > .Method(_Function => _Function.Invoke())); _body.Emit(OpCodes.Stloc_0); if (this.Method.IsStatic) { for (var _index = 0; _index < _signature.Length; _index++) { _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldarga_S, _index); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Argument(ref Metadata <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_parameters[_index].ParameterType)); } _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Begin())); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(pointer, _type, _signature); if (_type == Runtime.Void) { var _return = _body.DefineLabel(); var _leave = _body.DefineLabel(); var _rethrow = _body.DefineLabel(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Return())); _body.Emit(OpCodes.Leave, _return); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Stloc_2); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 2); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Throw(ref Metadata <Exception> .Value))); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Brfalse, _leave); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Beq, _rethrow); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Throw); _body.Emit(OpCodes.Br, _leave); _body.MarkLabel(_rethrow); _body.Emit(OpCodes.Rethrow); _body.MarkLabel(_leave); _body.Emit(OpCodes.Leave, _return); _body.BeginFinallyBlock(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Dispose())); _body.EndExceptionBlock(); _body.MarkLabel(_return); _body.Emit(OpCodes.Ret); } else { var _return = _body.DefineLabel(); var _leave = _body.DefineLabel(); var _rethrow = _body.DefineLabel(); _body.DeclareLocal(_type); _body.Emit(OpCodes.Stloc_3); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 3); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Return(ref Metadata <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_type)); _body.Emit(OpCodes.Leave, _return); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Stloc_2); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 2); _body.Emit(OpCodes.Ldloca_S, 3); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Throw(ref Metadata <Exception> .Value, ref Metadata <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_type)); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Brfalse, _leave); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Beq, _rethrow); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Throw); _body.Emit(OpCodes.Br, _leave); _body.MarkLabel(_rethrow); _body.Emit(OpCodes.Rethrow); _body.MarkLabel(_leave); _body.Emit(OpCodes.Leave, _return); _body.BeginFinallyBlock(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Dispose())); _body.EndExceptionBlock(); _body.MarkLabel(_return); _body.Emit(OpCodes.Ldloc_3); _body.Emit(OpCodes.Ret); } } else { _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldarg_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Instance(Metadata <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(this.Method.DeclaringType)); for (var _index = 0; _index < _parameters.Length; _index++) { _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldarga_S, _index + 1); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Argument(ref Metadata <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_parameters[_index].ParameterType)); } _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Begin())); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(pointer, _type, _signature); if (_type == Runtime.Void) { var _return = _body.DefineLabel(); var _leave = _body.DefineLabel(); var _rethrow = _body.DefineLabel(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Return())); _body.Emit(OpCodes.Leave, _return); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Stloc_2); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 2); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Throw(ref Metadata <Exception> .Value))); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Brfalse, _leave); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Beq, _rethrow); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Throw); _body.Emit(OpCodes.Br, _leave); _body.MarkLabel(_rethrow); _body.Emit(OpCodes.Rethrow); _body.MarkLabel(_leave); _body.Emit(OpCodes.Leave, _return); _body.BeginFinallyBlock(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Dispose())); _body.EndExceptionBlock(); _body.MarkLabel(_return); _body.Emit(OpCodes.Ret); } else { var _return = _body.DefineLabel(); var _leave = _body.DefineLabel(); var _rethrow = _body.DefineLabel(); _body.DeclareLocal(_type); _body.Emit(OpCodes.Stloc_3); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 3); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Return(ref Metadata <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_type)); _body.Emit(OpCodes.Leave, _return); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Stloc_2); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 2); _body.Emit(OpCodes.Ldloca_S, 3); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Throw(ref Metadata <Exception> .Value, ref Metadata <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_type)); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Brfalse, _leave); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Beq, _rethrow); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Throw); _body.Emit(OpCodes.Br, _leave); _body.MarkLabel(_rethrow); _body.Emit(OpCodes.Rethrow); _body.MarkLabel(_leave); _body.Emit(OpCodes.Leave, _return); _body.BeginFinallyBlock(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <IAdvice> .Method(_IAdvice => _IAdvice.Dispose())); _body.EndExceptionBlock(); _body.MarkLabel(_return); _body.Emit(OpCodes.Ldloc_3); _body.Emit(OpCodes.Ret); } } _method.Prepare(); return(_method); }
unsafe internal Entry(Type type, MethodInfo method, IntPtr pointer, Activity activity) { method.Prepare(); this.Type = type; this.Method = method; this.m_Pointer = pointer; this.Activity = activity; this.m_Aspectization = new LinkedList <IAspect>(); this.m_Dictionary = new Dictionary <IAspect, Activity>(); if (method.IsVirtual) { return; } var _type = Entry.m_Module.DefineType(string.Concat(Metadata <Delegate> .Type.Name, Guid.NewGuid().ToString("N")), TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract); switch (IntPtr.Size) { case 4: _type.DefineField(Metadata <Entry> .Field(_Activity => _Activity.m_Pointer).Name, Metadata <int> .Type, FieldAttributes.Static | FieldAttributes.Public); break; case 8: _type.DefineField(Metadata <Entry> .Field(_Activity => _Activity.m_Pointer).Name, Metadata <long> .Type, FieldAttributes.Static | FieldAttributes.Public); break; default: throw new NotSupportedException(); } var _field = _type.CreateType().GetFields(BindingFlags.Static | BindingFlags.Public).Single(); var _signature = this.Method.Signature(); var _method = new DynamicMethod(method.Name, this.Method.ReturnType, _signature, this.Method.DeclaringType, true); var _body = _method.GetILGenerator(); for (var _index = 0; _index < _signature.Length; _index++) { switch (_index) { case 0: _body.Emit(OpCodes.Ldarg_0); break; case 1: _body.Emit(OpCodes.Ldarg_1); break; case 2: _body.Emit(OpCodes.Ldarg_2); break; case 3: _body.Emit(OpCodes.Ldarg_3); break; default: _body.Emit(OpCodes.Ldarg_S, _index); break; } } _body.Emit(OpCodes.Ldsflda, _field); _body.Emit(OpCodes.Volatile); _body.Emit(OpCodes.Ldobj, _field.FieldType); _body.EmitCalli(OpCodes.Calli, CallingConventions.Standard, method.ReturnType, _signature, null); _body.Emit(OpCodes.Ret); _method.Prepare(); switch (IntPtr.Size) { case 4: *((int *)(this.m_Pointer)) = _method.Pointer().ToInt32(); this.m_Setup = Expression.Lambda <Action <IntPtr> >(Expression.Assign(Expression.Field(null, _field), Expression.Call(Parameter <IntPtr> .Expression, Metadata <IntPtr> .Method(_Pointer => _Pointer.ToInt32()))), Parameter <IntPtr> .Expression).Compile(); break; case 8: *((long *)(this.m_Pointer)) = _method.Pointer().ToInt64(); this.m_Setup = Expression.Lambda <Action <IntPtr> >(Expression.Assign(Expression.Field(null, _field), Expression.Call(Parameter <IntPtr> .Expression, Metadata <IntPtr> .Method(_Pointer => _Pointer.ToInt64()))), Parameter <IntPtr> .Expression).Compile(); break; default: throw new NotSupportedException(); } this.m_Setup(activity.Pointer); }
/// <summary> /// Create an advice that runs after the advised method regardless of its outcome. /// </summary> /// <param name="basic">Basic</param> /// <param name="advice">Delegate to be invoked after the advised method</param> /// <returns>Advice</returns> static public Advice After(this Advice.Style.IBasic basic, Action advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(new Advice.Boundary.Basic.After.Singleton(advice)); } var _type = _Method.ReturnType(); var _signature = _Method.Signature(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); _body.DeclareLocal(Metadata <bool> .Type); var _realized = _body.DefineLabel(); if (_type == Runtime.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Ldc_I4_1); _body.Emit(OpCodes.Stloc_0); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(OpCodes.Call, advice.Method); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Brtrue, _realized); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(OpCodes.Call, advice.Method); _body.MarkLabel(_realized); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldc_I4_1); _body.Emit(OpCodes.Stloc_0); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(OpCodes.Call, advice.Method); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Brtrue, _realized); if (advice.Target != null) { _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(advice.Target)); } _body.Emit(OpCodes.Call, advice.Method); _body.MarkLabel(_realized); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_1); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
static public Advice Boundary(this Advice.Style.IBasic basic, Advice.Boundary.IFactory factory) { //TODO missing dispose call! return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(factory); } var _type = _Method.ReturnType(); var _parameters = _Method.GetParameters(); var _signature = _Method.Signature(); var _routine = new Closure.Routine(_Pointer, _signature, _type); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.DeclaringType, true); var _body = _method.GetILGenerator(); var _boundary = _body.DeclareLocal(Metadata <Advice.IBoundary> .Type); var _backup = _body.DeclareLocal(Metadata <Exception> .Type); var _exception = _body.DeclareLocal(Metadata <Exception> .Type); _body.Emit(OpCodes.Ldsfld, Advice.Module.DefineField(Guid.NewGuid().ToString("N"), factory)); _body.Emit(OpCodes.Callvirt, Metadata <Advice.Boundary.IFactory> .Method(_Factory => _Factory.Create())); _body.Emit(OpCodes.Stloc_0); if (_Method.IsStatic) { for (var _index = 0; _index < _signature.Length; _index++) { _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldsfld, Runtime.Inventory.Parameter(_parameters[_index])); _body.Emit(OpCodes.Ldarga_S, _index); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Argument(Argument <ParameterInfo> .Value, ref Argument <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_parameters[_index].ParameterType)); } _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Begin())); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); if (_type == Runtime.Void) { var _return = _body.DefineLabel(); var _null = _body.DefineLabel(); var _rethrow = _body.DefineLabel(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Return())); _body.Emit(OpCodes.Leave, _return); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Stloc_2); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 2); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Throw(ref Argument <Exception> .Value))); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Brfalse, _null); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Beq, _rethrow); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Throw); _body.MarkLabel(_rethrow); _body.Emit(OpCodes.Rethrow); _body.MarkLabel(_null); _body.Emit(OpCodes.Leave, _return); _body.EndExceptionBlock(); _body.MarkLabel(_return); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Dispose())); _body.Emit(OpCodes.Ret); } else { var _return = _body.DefineLabel(); var _null = _body.DefineLabel(); var _rethrow = _body.DefineLabel(); _body.DeclareLocal(_type); _body.Emit(OpCodes.Stloc_3); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 3); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Return(ref Argument <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_type)); _body.Emit(OpCodes.Leave, _return); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Stloc_2); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 2); _body.Emit(OpCodes.Ldloca_S, 3); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Throw(ref Argument <Exception> .Value, ref Argument <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod()); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Brfalse, _null); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Beq, _rethrow); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Throw); _body.MarkLabel(_rethrow); _body.Emit(OpCodes.Rethrow); _body.MarkLabel(_null); _body.Emit(OpCodes.Leave, _return); _body.EndExceptionBlock(); _body.MarkLabel(_return); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Dispose())); _body.Emit(OpCodes.Ldloc_3); _body.Emit(OpCodes.Ret); } } else { _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldarg_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Instance(Argument <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_Method.DeclaringType)); for (var _index = 0; _index < _parameters.Length; _index++) { _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldsfld, Runtime.Inventory.Parameter(_parameters[_index])); _body.Emit(OpCodes.Ldarga_S, _index + 1); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Argument(Argument <ParameterInfo> .Value, ref Argument <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_parameters[_index].ParameterType)); } _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Begin())); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); if (_type == Runtime.Void) { var _return = _body.DefineLabel(); var _null = _body.DefineLabel(); var _rethrow = _body.DefineLabel(); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Return())); _body.Emit(OpCodes.Leave, _return); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Stloc_2); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 2); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Throw(ref Argument <Exception> .Value))); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Brfalse, _null); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Beq, _rethrow); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Throw); _body.MarkLabel(_rethrow); _body.Emit(OpCodes.Rethrow); _body.MarkLabel(_null); _body.Emit(OpCodes.Leave, _return); _body.EndExceptionBlock(); _body.MarkLabel(_return); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Dispose())); _body.Emit(OpCodes.Ret); } else { var _return = _body.DefineLabel(); var _null = _body.DefineLabel(); var _rethrow = _body.DefineLabel(); _body.DeclareLocal(_type); _body.Emit(OpCodes.Stloc_3); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 3); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Return(ref Argument <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_type)); _body.Emit(OpCodes.Leave, _return); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Stloc_1); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Stloc_2); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Ldloca_S, 2); _body.Emit(OpCodes.Ldloca_S, 3); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Throw(ref Argument <Exception> .Value, ref Argument <object> .Value)).GetGenericMethodDefinition().MakeGenericMethod(_type)); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Brfalse, _null); _body.Emit(OpCodes.Ldloc_1); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Beq, _rethrow); _body.Emit(OpCodes.Ldloc_2); _body.Emit(OpCodes.Throw); _body.MarkLabel(_rethrow); _body.Emit(OpCodes.Rethrow); _body.MarkLabel(_null); _body.Emit(OpCodes.Leave, _return); _body.EndExceptionBlock(); _body.MarkLabel(_return); _body.Emit(OpCodes.Ldloc_0); _body.Emit(OpCodes.Callvirt, Metadata <Advice.IBoundary> .Method(_IBoundary => _IBoundary.Dispose())); _body.Emit(OpCodes.Ldloc_3); _body.Emit(OpCodes.Ret); } } _method.Prepare(); return _method; })); }