Beispiel #1
0
    /// <summary>
    /// Create an adhoc variable used to retain an instance of an attribute.
    /// </summary>
    /// <param name="method">The method weaver.</param>
    /// <param name="attribute">The attribute.</param>
    /// <param name="member">The member.</param>
    /// <returns></returns>
    public Variable CreateAttributeAdhoc(MethodEmitter method, CustomAttribute attribute, MemberReference member)
    {
        var type     = attribute.AttributeType;
        var variable = method.EmitLocal(type);
        var il       = method.GetIL();

        foreach (var arg in attribute.ConstructorArguments)
        {
            CreateAttributeParameter(method, attribute, arg);
        }

        il.Emit(Codes.Create(attribute.Constructor));
        il.Emit(Codes.Store(variable));

        if (attribute.HasInterface(Context.Finder.IInstanceAware) && !method.Target.IsStatic)
        {
            il.Emit(Codes.Load(variable));
            il.Emit(Codes.This);
            il.Emit(Codes.Invoke(Context.Finder.InstanceAwareInstanceSet));
        }

        foreach (var prop in attribute.Properties)
        {
            CreateAttributeProperty(method, attribute, variable, prop);
        }

        CreateAttributeRequirements(il, attribute, member, variable, false);

        return(variable);
    }
Beispiel #2
0
    /// <summary>
    /// Copies the values of an array of parameter values into the corresponding parameters.
    /// </summary>
    /// <param name="method">The method.</param>
    /// <param name="array">The array.</param>
    public void CopyArgumentArrayToParameters(MethodEmitter method, Variable array)
    {
        var parameters = method.Target.Parameters;
        var count      = parameters.Count;

        var il = method.GetIL();

        for (int i = 0; i < count; i++)
        {
            var p        = parameters[i];
            var variable = new Variable(p);
            var type     = p.ParameterType;

            if (type.IsByReference || p.IsOut)
            {
                continue;
            }

            il.Emit(Codes.Load(array));
            il.Emit(Codes.Int(i));
            il.Emit(Codes.LoadArray);
            il.Emit(Codes.Unbox(type));
            il.Emit(Codes.Store(variable));
        }

        CopyArgumentArrayToReferences(method, array);
    }
Beispiel #3
0
    /// <summary>
    /// Creates a reference to a parameter used in a custom attribute.
    /// </summary>
    /// <param name="emitter">The emitter.</param>
    /// <param name="attribute">The attribute.</param>
    /// <param name="arg">The argument.</param>
    public void CreateAttributeParameter(MethodEmitter emitter, CustomAttribute attribute, CustomAttributeArgument arg)
    {
        var il = emitter.GetIL();

        if (arg.Value == null)
        {
            il.Emit(Codes.Null);
            return;
        }

        var type = arg.Type;

        if (type.IsArray)
        {
            var elements = (arg.Value as IEnumerable).Cast <CustomAttributeArgument>().ToArray();

            il.Emit(Codes.Int(elements.Length));
            il.Emit(Codes.CreateArray(type.GetElementType()));

            if (elements.Length == 0)
            {
                return;
            }

            il.Emit(Codes.Duplicate);

            for (int i = 0, count = elements.Length; i < count; i++)
            {
                il.Emit(Codes.Int(i));

                if (elements[i].Value == null)
                {
                    il.Emit(Codes.Null);
                    il.Emit(Codes.StoreArray);
                }
                else
                {
                    il.Emit(Codes.Load(elements[i].Value));
                    il.Emit(Codes.StoreArray);
                }

                if (i + 1 < count)
                {
                    il.Emit(Codes.Duplicate);
                }
            }
        }
        else
        {
            il.Emit(Codes.Load(arg.Value));
        }
    }
Beispiel #4
0
    /// <summary>
    /// Creates a reference to a property used in a custom attribute.
    /// </summary>
    /// <param name="emitter">The emitter.</param>
    /// <param name="attribute">The attribute.</param>
    /// <param name="field">The attribute variable.</param>
    /// <param name="property">The property.</param>
    public void CreateAttributeProperty(MethodEmitter emitter, CustomAttribute attribute, Variable field, Mono.Cecil.CustomAttributeNamedArgument property)
    {
        var il     = emitter.GetIL();
        var member = field.Type.Resolve().Properties.FirstOrDefault(p => p.Name == property.Name)?.SetMethod;

        if (member == null)
        {
            throw new MissingMemberException($"Cannot resolve property {property.Name} of {attribute.AttributeType.Name} as there is no setter");
        }

        il.Emit(Codes.ThisIf(field));
        il.Emit(Codes.Load(field));
        CreateAttributeParameter(emitter, attribute, property.Argument);
        il.Emit(Codes.Invoke(member.Import()));
    }
Beispiel #5
0
    /// <summary>
    /// Weaves the return instructions of the provided method to leave to a new instruction.
    /// </summary>
    /// <param name="weaver">The method weaver.</param>
    /// <param name="storage">The storage variable for any captured return value.</param>
    /// <param name="hasMethodInterceptors">Whether method interceptors are present which could change the return value.</param>
    /// <returns>The instruction now located at the tail of the method.</returns>
    public Instruction WeaveMethodReturnsRoute(MethodEmitter weaver, Variable storage, bool hasMethodInterceptors)
    {
        var il          = weaver.Body.Instructions;
        var pos         = weaver.GetIL().Position;
        var instruction = (Instruction)null;

        if (weaver.Target.IsReturn())
        {
            instruction = hasMethodInterceptors ? Codes.Nop : Codes.Load(storage);

            il.Add(instruction);
            il.Add(Codes.Return);

            for (int i = 0; i < il.Count - 2; i++)
            {
                if (il[i].OpCode == OpCodes.Ret)
                {
                    var store = Codes.Store(storage);

                    il[i].OpCode  = store.OpCode;
                    il[i].Operand = store.Operand;

                    weaver.Body.GetILProcessor().InsertAfter(il[i], Codes.Leave(instruction));
                }
            }
        }
        else
        {
            instruction = Codes.Return;
            il.Add(instruction);

            for (int i = 0, count = il.Count - 1; i < count; i++)
            {
                var ix = il[i];

                if (ix.OpCode == OpCodes.Ret)
                {
                    ix.OpCode  = OpCodes.Leave;
                    ix.Operand = instruction;
                }
            }
        }

        return(instruction);
    }
Beispiel #6
0
    /// <summary>
    /// Copies the values of an array of parameter values into the required references.
    /// </summary>
    /// <param name="method">The method.</param>
    /// <param name="array">The array.</param>
    public void CopyArgumentArrayToReferences(MethodEmitter method, Variable array)
    {
        var parameters = method.Target.Parameters;
        var count      = parameters.Count;

        var il = method.GetIL();

        for (int i = 0; i < count; i++)
        {
            var p    = parameters[i];
            var type = p.ParameterType;

            if (!type.IsByReference || p.IsOut)
            {
                continue;
            }

            var spec     = (TypeSpecification)type;
            var unboxing = true;

            il.Emit(Codes.Arg(p));
            il.Emit(Codes.Load(array));
            il.Emit(Codes.Int(i));
            il.Emit(Codes.LoadArray);

            var code = OpCodes.Nop;

            switch (spec.ElementType.MetadataType)
            {
            case MetadataType.Boolean:
            case MetadataType.SByte:
            case MetadataType.Byte:
                code = OpCodes.Stind_I1;
                break;

            case MetadataType.Int16:
            case MetadataType.UInt16:
                code = OpCodes.Stind_I2;
                break;

            case MetadataType.Int32:
            case MetadataType.UInt32:
                code = OpCodes.Stind_I4;
                break;

            case MetadataType.Int64:
            case MetadataType.UInt64:
                code = OpCodes.Stind_I8;
                break;

            case MetadataType.Single:
                code = OpCodes.Stind_R4;
                break;

            case MetadataType.Double:
                code = OpCodes.Stind_R8;
                break;

            case MetadataType.IntPtr:
            case MetadataType.UIntPtr:
                code = OpCodes.Stind_I;
                break;

            default:
                if (spec.ElementType.IsValueType)
                {
                    il.Emit(Instruction.Create(OpCodes.Stobj, spec.ElementType));
                }
                else
                {
                    code     = OpCodes.Stind_Ref;
                    unboxing = false;
                }
                break;
            }

            if (unboxing)
            {
                il.Emit(Codes.Unbox(spec.ElementType));
            }

            if (code != OpCodes.Nop)
            {
                il.Emit(code);
            }
        }
    }
Beispiel #7
0
    /// <summary>
    /// Create an array variable containing the arguments of the method invocation.
    /// </summary>
    /// <param name="method">The method weaver.</param>
    /// <returns></returns>
    public Variable CreateArgumentArray(MethodEmitter method)
    {
        var parameters = method.Target.Parameters;
        var count      = parameters.Count;

        var array = method.EmitLocal(Context.Finder.ObjectArray);
        var il    = method.GetIL();

        il.Emit(Codes.Nop);
        il.Emit(Codes.Int(count));
        il.Emit(Codes.CreateArray(TypeSystem.ObjectReference));
        il.Emit(Codes.Store(array));

        for (int i = 0; i < count; i++)
        {
            var p    = parameters[i];
            var type = p.ParameterType;

            il.Emit(Codes.Load(array));
            il.Emit(Codes.Int(i));

            if (p.IsOut)
            {
                var spec = (TypeSpecification)type;

                if (spec.ElementType.IsValueType)
                {
                    il.Emit(Codes.Init(spec.ElementType));
                }
                else
                {
                    il.Emit(Codes.Null);
                    il.Emit(Codes.StoreArray);
                }

                continue;
            }

            il.Emit(Codes.Arg(p));

            if (type.IsByReference)
            {
                var spec   = (TypeSpecification)type;
                var boxing = true;

                switch (spec.ElementType.MetadataType)
                {
                case MetadataType.SByte:
                    il.Emit(OpCodes.Ldind_I1);
                    break;

                case MetadataType.Int16:
                    il.Emit(OpCodes.Ldind_I2);
                    break;

                case MetadataType.Int32:
                    il.Emit(OpCodes.Ldind_I4);
                    break;

                case MetadataType.Int64:
                case MetadataType.UInt64:
                    il.Emit(OpCodes.Ldind_I8);
                    break;

                case MetadataType.Boolean:
                case MetadataType.Byte:
                    il.Emit(OpCodes.Ldind_U1);
                    break;

                case MetadataType.UInt16:
                    il.Emit(OpCodes.Ldind_U2);
                    break;

                case MetadataType.UInt32:
                    il.Emit(OpCodes.Ldind_U4);
                    break;

                case MetadataType.Single:
                    il.Emit(OpCodes.Ldind_R4);
                    break;

                case MetadataType.Double:
                    il.Emit(OpCodes.Ldind_R8);
                    break;

                case MetadataType.IntPtr:
                case MetadataType.UIntPtr:
                    il.Emit(OpCodes.Ldind_I);
                    break;

                default:
                    if (spec.ElementType.IsValueType)
                    {
                        il.Emit(Instruction.Create(OpCodes.Ldobj, spec.ElementType));
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                        boxing = false;
                    }
                    break;
                }

                if (boxing)
                {
                    il.Emit(Codes.Box(spec.ElementType));
                }
            }
            else
            {
                il.Emit(Codes.Box(p.ParameterType));
            }

            il.Emit(Codes.StoreArray);
        }

        return(array);
    }
Beispiel #8
0
    /// <summary>
    /// Weaves the interception logic of a method.
    /// </summary>
    /// <param name="weaver">The method weaver.</param>
    /// <param name="item">The method information.</param>
    public void WeaveMethodInterceptors(MethodEmitter weaver, MethodInterceptorInfo item)
    {
        weaver.Body.SimplifyMacros();

        var pAttributes = item.Parameters.SelectMany(p => p.Attributes.Select(a => new { p.Index, Attribute = a })).ToArray();
        var mAttributes = item.MethodInterceptors;
        var rAttributes = item.ReturnInterceptors;

        var pInterceptors = new Variable[pAttributes.Length];
        var mInterceptors = new Variable[item.MethodInterceptors.Length];
        var rInterceptors = new Variable[rAttributes.Length];

        var needsEnter   = mAttributes.Any(m => m.HasRequiredMethod(Context.Finder.MethodInterceptorOnEnter));
        var needsCatch   = mAttributes.Any(m => m.HasRequiredMethod(Context.Finder.MethodInterceptorOnException));
        var needsExit    = mAttributes.Any(m => m.HasRequiredMethod(Context.Finder.MethodInterceptorOnExit));
        var needsParams  = pAttributes.Any(m => m.Attribute.HasRequiredMethod(Context.Finder.ParameterInterceptorOnEnter));
        var needsReturns = rAttributes.Any(m => m.HasRequiredMethod(Context.Finder.MethodReturnInterceptorOnReturn));

        var needsMethodArgs = mAttributes.Any(m =>
        {
            return(m.AttributeType.GetMethod(Context.Finder.MethodInterceptorOnEnter).UsesParameter(0) ||
                   m.AttributeType.GetMethod(Context.Finder.MethodInterceptorOnException).UsesParameter(0) ||
                   m.AttributeType.GetMethod(Context.Finder.MethodInterceptorOnExit).UsesParameter(0));
        });

        var needsParamArgs   = pAttributes.Any(m => m.Attribute.AttributeType.GetMethod(Context.Finder.ParameterInterceptorOnEnter).UsesParameter(0));
        var needsReturnsArgs = rAttributes.Any(m => m.AttributeType.GetMethod(Context.Finder.MethodReturnInterceptorOnReturn).UsesParameter(0));

        var needsMethodCopyArgs = mAttributes.Any(m => m.GetAttribute(Context.Finder.CompilationOptionsAttribute)?.GetProperty("CopyArguments", notFound: false) ?? false);

        if (!needsEnter && !needsCatch && !needsExit && !needsParams && !needsReturns)
        {
            return;
        }

        var method = weaver.Target;
        var il     = weaver.GetIL();

        il.Position = il.GetFirst();
        il.Insert   = CodeInsertion.Before;

        var result = (Variable)null;

        if (weaver.Target.IsReturn())
        {
            var type = weaver.Target.ReturnType;

            result = weaver.EmitLocal(type);

            if (type.IsValueType)
            {
                il.Emit(Codes.Address(result));
                il.Emit(Codes.Init(type));
            }
            else
            {
                il.Emit(Codes.Null);
                il.Emit(Codes.Store(result));
            }
        }

        var leave  = WeaveMethodReturnsRoute(weaver, result, mInterceptors.Length > 0);
        var cancel = il.EmitLabel();

        for (int i = 0, count = pInterceptors.Length; i < count; i++)
        {
            pInterceptors[i] = CreateAttribute(weaver, pAttributes[i].Attribute);
        }

        for (int i = 0, count = mInterceptors.Length; i < count; i++)
        {
            mInterceptors[i] = CreateAttribute(weaver, mAttributes[i]);
        }

        for (int i = 0, count = rInterceptors.Length; i < count; i++)
        {
            rInterceptors[i] = CreateAttribute(weaver, rAttributes[i]);
        }

        foreach (var attribute in mAttributes)
        {
            weaver.Target.CustomAttributes.Remove(attribute);
        }

        foreach (var attribute in pAttributes)
        {
            if (attribute.Index == -1)
            {
                weaver.Target.CustomAttributes.Remove(attribute.Attribute);
            }
            else
            {
                weaver.Target.Parameters[attribute.Index].CustomAttributes.Remove(attribute.Attribute);
            }
        }

        foreach (var attribute in rAttributes)
        {
            weaver.Target.MethodReturnType.CustomAttributes.Remove(attribute);
        }

        foreach (var parameter in item.Parameters)
        {
            foreach (var attribute in parameter.Attributes)
            {
                if (parameter.Index == -1)
                {
                    weaver.Target.CustomAttributes.Remove(attribute);
                }
                else
                {
                    weaver.Target.Parameters[parameter.Index].CustomAttributes.Remove(attribute);
                }
            }
        }

        var hasMethod = mInterceptors.Length > 0;
        var hasParams = pInterceptors.Length > 0;
        var hasReturn = rInterceptors.Length > 0;

        var arguments  = hasMethod ? CreateArgumentArray(weaver) : null;
        var invocation = CreateMethodInfo(weaver);
        var mEventArgs = hasMethod && needsMethodArgs?weaver.EmitLocal(Context.Finder.MethodInterceptionArgs, name : "methodEventArgs") : null;

        if (hasMethod || hasReturn)
        {
            if (hasMethod && needsMethodArgs)
            {
                il.Emit(method.IsStatic ? Codes.Null : Codes.This);
                il.Emit(Codes.Load(arguments));

                if (result == null)
                {
                    il.Emit(Codes.Null);
                }
                else
                {
                    il.Emit(Codes.Load(result));
                    il.Emit(Codes.Box(result.Type));
                }

                il.Emit(Codes.Load(invocation));
                il.Emit(Codes.Create(Context.Finder.MethodInterceptionArgsCtor));
                il.Emit(Codes.Store(mEventArgs));
            }

            il.Try();
        }

        if (hasParams && needsParams)
        {
            var pEventArgs = needsParamArgs ? weaver.EmitLocal(Context.Finder.ParameterInterceptionArgs) : null;

            for (int i = 0, count = pInterceptors.Length; i < count; i++)
            {
                var inc        = pInterceptors[i];
                var parameters = pAttributes[i].Index == -1 ? method.Parameters.ToArray() : new[] { method.Parameters[pAttributes[i].Index] };

                for (int j = 0, pCount = parameters.Length; j < pCount; j++)
                {
                    var prm           = parameters[j];
                    var pVariable     = new Variable(prm);
                    var pInfo         = CreateParameterInfo(weaver, prm);
                    var needsCopyArgs = pAttributes[i].Attribute.GetAttribute(Context.Finder.CompilationOptionsAttribute)?.GetProperty("CopyArguments", notFound: false) ?? false;

                    if (needsParamArgs)
                    {
                        il.Emit(method.IsStatic ? Codes.Null : Codes.This);
                        il.Emit(Codes.Load(pInfo));
                        il.Emit(Codes.Arg(pVariable));
                        il.Emit(Codes.Box(prm.ParameterType));
                        il.Emit(Codes.Create(Context.Finder.ParameterInterceptionArgsCtor));
                        il.Emit(Codes.Store(pEventArgs));
                    }

                    il.Emit(Codes.ThisIf(inc));
                    il.Emit(Codes.Load(inc));

                    if (needsParamArgs)
                    {
                        il.Emit(Codes.Load(pEventArgs));
                    }
                    else
                    {
                        il.Emit(Codes.Null);
                    }

                    il.Emit(Codes.Invoke(Context.Finder.ParameterInterceptorOnEnter));

                    if (needsParamArgs && !prm.IsOut && needsCopyArgs)
                    {
                        il.Emit(Codes.Load(pEventArgs));
                        il.Emit(Codes.Invoke(Context.Finder.ParameterInterceptionArgsValueGet));
                        il.Emit(Codes.Unbox(prm.ParameterType));
                        il.Emit(Codes.Store(pVariable));
                    }
                }
            }
        }

        if (hasMethod || hasReturn)
        {
            if (hasMethod && needsEnter)
            {
                for (int i = 0, count = mInterceptors.Length; i < count; i++)
                {
                    var inc = mInterceptors[i];
                    var att = mAttributes[i];

                    if (att.HasRequiredMethod("OnEnter"))
                    {
                        il.Emit(Codes.ThisIf(inc));
                        il.Emit(Codes.Load(inc));

                        if (needsMethodArgs)
                        {
                            il.Emit(Codes.Load(mEventArgs));
                        }
                        else
                        {
                            il.Emit(Codes.Null);
                        }

                        il.Emit(Codes.Invoke(Context.Finder.MethodInterceptorOnEnter));

                        if (needsMethodArgs)
                        {
                            var proceed = il.EmitLabel();

                            il.Emit(Codes.Load(mEventArgs));
                            il.Emit(Codes.Invoke(Context.Finder.MethodInterceptionArgsCancelGet));
                            il.Emit(Codes.IfFalse(proceed));

                            if (result != null && needsMethodArgs)
                            {
                                il.Emit(Codes.Load(mEventArgs));
                                il.Emit(Codes.Invoke(Context.Finder.MethodInterceptionArgsReturnGet));
                                il.Emit(Codes.Unbox(result.Type));
                                il.Emit(Codes.Store(result));
                            }

                            il.Emit(Codes.Leave(leave));
                            il.Mark(proceed);
                        }
                    }
                }

                if (needsMethodArgs && needsMethodCopyArgs && arguments != null)
                {
                    CopyArgumentArrayToParameters(weaver, arguments);
                }
            }

            il.Position = leave;

            if (hasMethod && needsCatch)
            {
                var exception = il.EmitLocal(Context.Finder.Exception);

                il.Catch(exception);

                for (int i = 0, count = mInterceptors.Length; i < count; i++)
                {
                    var inc = mInterceptors[i];
                    var att = mAttributes[i];

                    if (att.HasRequiredMethod("OnException"))
                    {
                        il.Emit(Codes.ThisIf(inc));
                        il.Emit(Codes.Load(inc));

                        if (needsMethodArgs)
                        {
                            il.Emit(Codes.Load(mEventArgs));
                        }
                        else
                        {
                            il.Emit(Codes.Null);
                        }

                        il.Emit(Codes.Load(exception));
                        il.Emit(Codes.Invoke(Context.Finder.MethodInterceptorOnException));
                    }
                }

                if (needsExit || needsReturns)
                {
                    il.Emit(Codes.Nop);
                    il.Emit(Codes.Leave(leave));
                }
            }

            if (needsExit || needsReturns)
            {
                il.Finally(leave);
            }

            if (hasMethod)
            {
                if (result != null && needsMethodArgs)
                {
                    il.Emit(Codes.Load(mEventArgs));
                    il.Emit(Codes.Load(result));
                    il.Emit(Codes.Box(weaver.Target.ReturnType));
                    il.Emit(Codes.Invoke(Context.Finder.MethodInterceptionArgsReturnSet));
                }

                if (needsExit)
                {
                    for (int i = 0, count = mInterceptors.Length; i < count; i++)
                    {
                        var inc = mInterceptors[i];
                        var att = mAttributes[i];

                        if (att.HasRequiredMethod("OnExit"))
                        {
                            il.Emit(Codes.ThisIf(inc));
                            il.Emit(Codes.Load(inc));

                            if (needsMethodArgs)
                            {
                                il.Emit(Codes.Load(mEventArgs));
                            }
                            else
                            {
                                il.Emit(Codes.Null);
                            }

                            il.Emit(Codes.Invoke(Context.Finder.MethodInterceptorOnExit));
                        }
                    }
                }

                il.Mark(cancel);
            }

            if (hasReturn && needsReturns && result != null)
            {
                var rEventArgs = needsReturnsArgs ? il.EmitLocal(Context.Finder.MethodReturnInterceptionArgs) : null;

                if (needsReturnsArgs)
                {
                    il.Emit(method.IsStatic ? Codes.Null : Codes.This);
                    il.Emit(Codes.Load(result));
                    il.Emit(Codes.Box(result.Type));
                    il.Emit(Codes.Load(invocation));
                    il.Emit(Codes.Create(Context.Finder.MethodReturnInterceptionArgsCtor));
                    il.Emit(Codes.Store(rEventArgs));
                }

                for (int i = 0, count = rInterceptors.Length; i < count; i++)
                {
                    var inc = rInterceptors[i];
                    var att = rAttributes[i];

                    if (att.HasRequiredMethod("OnReturn"))
                    {
                        il.Emit(Codes.ThisIf(inc));
                        il.Emit(Codes.Load(inc));

                        if (needsReturnsArgs)
                        {
                            il.Emit(Codes.Load(rEventArgs));
                        }
                        else
                        {
                            il.Emit(Codes.Null);
                        }

                        il.Emit(Codes.Invoke(Context.Finder.MethodReturnInterceptorOnReturn));
                    }
                }

                if (needsReturnsArgs)
                {
                    il.Emit(Codes.Load(rEventArgs));
                    il.Emit(Codes.Invoke(Context.Finder.MethodReturnInterceptionArgsValueGet));
                    il.Emit(Codes.Unbox(result.Type));
                    il.Emit(Codes.Store(result));
                }
            }

            if (!needsExit && !needsReturns)
            {
                il.Emit(Codes.Nop);
                il.Emit(Codes.Leave(leave));
            }

            il.EndTry();
            il.Insert = CodeInsertion.After;

            if (hasMethod && arguments != null)
            {
                CopyArgumentArrayToReferences(weaver, arguments);
            }

            if (hasMethod && needsMethodArgs && result != null)
            {
                il.Emit(Codes.Nop);
                il.Emit(Codes.Load(mEventArgs));
                il.Emit(Codes.Invoke(Context.Finder.MethodInterceptionArgsReturnGet));
                il.Emit(Codes.Unbox(weaver.Target.ReturnType));
            }
            else if (hasMethod && result != null)
            {
                il.Emit(Codes.Nop);
                il.Emit(Codes.Load(result));
            }
        }

        weaver.Body.InitLocals = true;
        weaver.Body.OptimizeMacros();
    }