예제 #1
0
        private Emit <DelegateType> EmitFrom(int from, int length, string name = null, ModuleBuilder module = null)
        {
            if (from < 0 || from > Operations.Count)
            {
                throw new InvalidOperationException("from must be between 0 and " + Operations.Count + ", inclusive; found " + from);
            }

            if (length < 0)
            {
                throw new InvalidOperationException("length must be non-negative; found " + length);
            }

            if (from + length > Operations.Count)
            {
                throw new InvalidOperationException("from + length must be less than " + Operations.Count + "; found " + (from + length));
            }

            var e1 =
                Emit <DelegateType> .DisassemblerDynamicMethod(
                    LinqAlternative.Select(Parameters, p => p.ParameterType).ToArray(),
                    name,
                    module
                    );

            for (var i = 0; i < length; i++)
            {
                Apply(from + i, e1);
            }

            return(e1);
        }
예제 #2
0
        /// <summary>
        /// Pops parameterTypes.Length arguments from the stack, invokes the constructor on the given type that matches parameterTypes, and pushes a reference to the new object onto the stack.
        /// </summary>
        public Emit <DelegateType> NewObject(Type type, params Type[] parameterTypes)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (parameterTypes == null)
            {
                throw new ArgumentNullException("parameterTypes");
            }

            var allCons = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance);
            var cons    =
                LinqAlternative
                .Where(
                    allCons,
                    c =>
                    c.GetParameters().Length == parameterTypes.Length &&
                    LinqAlternative.Select(c.GetParameters(), (p, i) => p.ParameterType == parameterTypes[i]).Aggregate(true, (a, b) => a && b)
                    ).SingleOrDefault();

            if (cons == null)
            {
                throw new InvalidOperationException("Type " + type + " must have a constructor that matches parameters [" + BufferedILGenerator <DelegateType> .Join(", ", ((LinqArray <Type>)parameterTypes).AsEnumerable()) + "]");
            }

            return(NewObject(cons));
        }
예제 #3
0
        /// <summary>
        /// <para>Pops a value off the stack and branches to the label at the index of that value in the given labels.</para>
        /// <para>If the value is out of range, execution falls through to the next instruction.</para>
        /// </summary>
        public Emit <DelegateType> Switch(params Label[] labels)
        {
            if (labels == null)
            {
                throw new ArgumentNullException("labels");
            }

            if (labels.Length == 0)
            {
                throw new ArgumentException("labels must have at least one element");
            }

            if (LinqAlternative.Any(labels, l => ((IOwned)l).Owner is DisassembledOperations <DelegateType>))
            {
                return
                    (Switch(LinqAlternative.Select(labels, l => l.Name).ToArray()));
            }

            foreach (var label in labels)
            {
                if (((IOwned)label).Owner != this)
                {
                    FailOwnership(label);
                }
            }

            foreach (var label in labels)
            {
                UnusedLabels.Remove(label);
            }

            var transitions =
                new[]
            {
                new StackTransition(new [] { typeof(int) }, TypeHelpers.EmptyTypes),
                new StackTransition(new [] { typeof(NativeIntType) }, TypeHelpers.EmptyTypes),
            };

            var labelsCopy = ((LinqArray <Label>)labels).Select(l => l).ToArray();

            UpdateOpCodeDelegate update;

            UpdateState(OpCodes.Switch, labelsCopy, Wrap(transitions, "Switch"), out update);

            var valid = CurrentVerifiers.ConditionalBranch(labels);

            if (!valid.Success)
            {
                throw new SigilVerificationException("Switch", valid, IL.Instructions(AllLocals));
            }

            foreach (var label in labels)
            {
                Branches.Add(SigilTuple.Create(OpCodes.Switch, label, IL.Index));
                BranchPatches[IL.Index] = SigilTuple.Create(label, update, OpCodes.Switch);
            }

            return(this);
        }
예제 #4
0
        /// <summary>
        /// Returns a string representation of this OperationResultUsage.
        /// </summary>
        public override string ToString()
        {
            var users = string.Join(", ", LinqAlternative.Select(ResultUsedBy, r => r.ToString()).OrderBy(_ => _).ToArray());

            if (users.Length == 0)
            {
                return("(" + ProducesResult + ") result is unused");
            }

            return("(" + ProducesResult + ") result is used by (" + users + ")");
        }
예제 #5
0
        /// <summary>
        /// Pops an object reference off the stack, and pushes a pointer to the given method's implementation on that object.
        ///
        /// For static or non-virtual functions, use LoadFunctionPointer
        /// </summary>
        public Emit <DelegateType> LoadVirtualFunctionPointer(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (method.IsStatic)
            {
                throw new ArgumentException("Only non-static methods can be passed to LoadVirtualFunctionPointer, found " + method);
            }

            var thisType =
                HasFlag(method.CallingConvention, CallingConventions.HasThis) ?
                method.DeclaringType :
                null;

            var parameters = method.GetParameters();
            var paramList  = LinqAlternative.Select(parameters, p => p.ParameterType).ToList();

            var declaring = method.DeclaringType;

            if (TypeHelpers.IsValueType(declaring))
            {
                declaring = declaring.MakePointerType();
            }

            paramList.Insert(0, declaring);

            var type =
                TypeOnStack.GetKnownFunctionPointer(
                    method.CallingConvention,
                    thisType,
                    method.ReturnType,
                    paramList.ToArray()
                    );

            var transitions =
                new[]
            {
                new StackTransition(new [] { declaring }, new [] { typeof(NativeIntType) })
            };

            UpdateState(OpCodes.Ldvirtftn, method, LinqAlternative.Select(parameters, p => p.ParameterType).AsEnumerable(), Wrap(transitions, "LoadVirtualFunctionPointer"));

            return(this);
        }
        /// <summary>
        /// Pops an object reference off the stack, and pushes a pointer to the given method's implementation on that object.
        ///
        /// For static or non-virtual functions, use LoadFunctionPointer
        /// </summary>
        public Emit <DelegateType> LoadVirtualFunctionPointer(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (method.IsStatic)
            {
                throw new ArgumentException("Only non-static methods can be passed to LoadVirtualFunctionPointer, found " + method);
            }


            var parameters = method.GetParameters();
            var paramList  = LinqAlternative.Select(parameters, p => p.ParameterType).ToArray();

            return(InnerLoadVirtualFunctionPointer(method, paramList));
        }
예제 #7
0
        /// <summary>
        /// Creates a new Emit, suitable for building a constructor on the given TypeBuilder.
        ///
        /// The DelegateType and TypeBuilder must agree on parameter types and parameter counts.
        ///
        /// If you intend to use unveriable code, you must set allowUnverifiableCode to true.
        ///
        /// If doVerify is false (default is true) Sigil will *not* throw an exception on invalid IL.  This is faster, but the benefits
        /// of Sigil are reduced to "a nicer ILGenerator interface".
        ///
        /// If strictBranchValidation is true (default is false) Sigil will enforce "Backward branch constraints" which are *technically* required
        /// for valid CIL, but in practice often ignored.  The most common case to set this option is if you are generating types to write to disk.
        /// </summary>
        public static Emit <DelegateType> BuildConstructor(TypeBuilder type, MethodAttributes attributes, CallingConventions callingConvention = CallingConventions.HasThis, bool allowUnverifiableCode = false, bool doVerify = true, bool strictBranchVerification = false)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            CheckAttributesAndConventions(attributes, callingConvention);

            if (!HasFlag(callingConvention, CallingConventions.HasThis))
            {
                throw new ArgumentException("Constructors always have a this reference");
            }

            ValidateNewParameters <DelegateType>();

            var delType = typeof(DelegateType);

            var invoke         = delType.GetMethod("Invoke");
            var returnType     = invoke.ReturnType;
            var parameterTypes = LinqAlternative.Select(invoke.GetParameters(), s => s.ParameterType).ToArray();

            if (returnType != typeof(void))
            {
                throw new ArgumentException("DelegateType used must return void");
            }

            var constructorBuilder = type.DefineConstructor(attributes, callingConvention, parameterTypes);

            // Constructors always have a `this`
            var pList = new List <Type>(parameterTypes);

            pList.Insert(0, TypeHelpers.AsType(type));

            parameterTypes = pList.ToArray();

            var ret = new Emit <DelegateType>(callingConvention, typeof(void), parameterTypes, allowUnverifiableCode, doVerify, strictBranchVerification)
            {
                ConstrBuilder         = constructorBuilder,
                IsBuildingConstructor = true
            };

            return(ret);
        }
예제 #8
0
파일: Emit.cs 프로젝트: csainty/Sigil
        internal static Emit <DelegateType> DisassemblerDynamicMethod(Type[] parameters = null, string name = null, ModuleBuilder module = null, bool doVerify = true, bool strictBranchVerification = false)
        {
            module = module ?? Module;

            name = name ?? AutoNamer.Next("_DynamicMethod");

            ValidateNewParameters <DelegateType>();

            var delType = typeof(DelegateType);

            var invoke         = delType.GetMethod("Invoke");
            var returnType     = invoke.ReturnType;
            var parameterTypes = parameters ?? LinqAlternative.Select(invoke.GetParameters(), s => s.ParameterType).ToArray();

            var dynMethod = new DynamicMethod(name, returnType, parameterTypes, module, skipVisibility: true);

            var ret = new Emit <DelegateType>(dynMethod.CallingConvention, returnType, parameterTypes, AllowsUnverifiableCode(module), doVerify, strictBranchVerification);

            ret.DynMethod = dynMethod;

            return(ret);
        }
예제 #9
0
        /// <summary>
        /// <para>Calls the given method virtually.  Pops its arguments in reverse order (left-most deepest in the stack), and pushes the return value if it is non-void.</para>
        /// <para>The `this` reference should appear before any arguments (deepest in the stack).</para>
        /// <para>The method invoked at runtime is determined by the type of the `this` reference.</para>
        /// <para>If the method invoked shouldn't vary (or if the method is static), use Call instead.</para>
        /// </summary>
        public Emit <DelegateType> CallVirtual(MethodInfo method, Type constrained = null, Type[] arglist = null)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (method.IsStatic)
            {
                throw new ArgumentException("Only non-static methods can be called using CallVirtual, found " + method);
            }

            if (HasFlag(method.CallingConvention, CallingConventions.VarArgs) && !HasFlag(method.CallingConvention, CallingConventions.Standard))
            {
                if (arglist == null)
                {
                    throw new InvalidOperationException("When calling a VarArgs method, arglist must be set");
                }
            }

            var expectedParams = ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => TypeOnStack.Get(s.ParameterType)).ToList();

            var declaring = method.DeclaringType;

            if (TypeHelpers.IsValueType(declaring))
            {
                declaring = declaring.MakePointerType();
            }

            // "this" parameter
            expectedParams.Insert(0, TypeOnStack.Get(declaring));

            if (arglist != null)
            {
                expectedParams.AddRange(LinqAlternative.Select(arglist, t => TypeOnStack.Get(t)));
            }

            var resultType = method.ReturnType == typeof(void) ? null : TypeOnStack.Get(method.ReturnType);

            // Shove the constrained prefix in if it's supplied
            if (constrained != null)
            {
                UpdateState(OpCodes.Constrained, constrained, Wrap(StackTransition.None(), "CallVirtual"));
            }

            IEnumerable <StackTransition> transitions;

            if (resultType != null)
            {
                transitions =
                    new[]
                {
                    new StackTransition(expectedParams.Reverse().AsEnumerable(), new [] { resultType })
                };
            }
            else
            {
                transitions =
                    new[]
                {
                    new StackTransition(expectedParams.Reverse().AsEnumerable(), new TypeOnStack[0])
                };
            }

            UpdateState(OpCodes.Callvirt, method, ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => s.ParameterType).AsEnumerable(), Wrap(transitions, "CallVirtual"), arglist: arglist);

            return(this);
        }
예제 #10
0
        /// <summary>
        /// A string representation of this Operation.
        /// </summary>
        public override string ToString()
        {
            if (IsExceptionBlockStart)
            {
                return("--Start Exception Block--");
            }

            if (IsExceptionBlockEnd)
            {
                return("--End Exception Block--");
            }

            if (IsCatchBlockStart)
            {
                return("--Start Catch Block--");
            }

            if (IsCatchBlockEnd)
            {
                return("--End Catch Block--");
            }

            if (IsFinallyBlockStart)
            {
                return("--Start Finally Block--");
            }

            if (IsFinallyBlockEnd)
            {
                return("--End Finally Block--");
            }

            if (IsMarkLabel)
            {
                return("--Mark Label " + LabelName + "--");
            }

            var ps =
                string.Join(
                    ", ",
                    LinqAlternative.Select(
                        Parameters,
                        o =>
            {
                if (o == null)
                {
                    return("(null)");
                }

                return(o.ToString());
            }
                        ).ToArray()
                    );

            if (ps.Length == 0)
            {
                return(OpCode.ToString());
            }

            return(OpCode + " " + ps);
        }