Ejemplo n.º 1
0
        /// <summary>
        /// Ends the execution of the current method.
        ///
        /// If the current method does not return void, pops a value from the stack and returns it to the calling method.
        ///
        /// Return should leave the stack empty.
        /// </summary>
        public Emit <DelegateType> Return()
        {
            if (ReturnType == TypeOnStack.Get(typeof(void)))
            {
                UpdateState(Wrap(new[] { new StackTransition(0) }, "Return"));

                UpdateState(OpCodes.Ret, Wrap(StackTransition.None(), "Return"));

                Returns.Add(IL.Index);
                MustMark = true;

                return(this);
            }

            UpdateState(OpCodes.Ret, Wrap(StackTransition.Pop(ReturnType), "Return"));

            Returns.Add(IL.Index);

            UpdateState(Wrap(new[] { new StackTransition(0) }, "Return"));
            MustMark = true;

            var verify = CurrentVerifiers.Return();

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

            return(this);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Expects a reference to an array of the given element type and an index on the stack.
        ///
        /// Pops both, and pushes the address of the element at the given index.
        /// </summary>
        public Emit <DelegateType> LoadElementAddress(Type elementType)
        {
            if (!AllowsUnverifiableCIL)
            {
                FailUnverifiable("LoadElementAddress");
            }

            var arrayType = elementType.MakeArrayType();

            // needs to be markable so we can keep track of what makes use of this value
            var pushToStack = TypeOnStack.Get(elementType.MakeByRefType());

            // Shove this away, later on we'll figure out if we can insert a readonly here
            ReadonlyPatches.Add(SigilTuple.Create(IL.Index, pushToStack));

            var transitions =
                new[]
            {
                new StackTransition(new [] { TypeOnStack.Get <NativeIntType>(), TypeOnStack.Get(arrayType) }, new [] { pushToStack }),
                new StackTransition(new [] { TypeOnStack.Get <int>(), TypeOnStack.Get(arrayType) }, new [] { pushToStack })
            };

            UpdateState(OpCodes.Ldelema, elementType, Wrap(transitions, "LoadElementAddress"));

            return(this);
        }
Ejemplo n.º 3
0
        private Emit(CallingConventions callConvention, Type returnType, Type[] parameterTypes, bool allowUnverifiable, bool doVerify, bool strictBranchVerification)
        {
            CallingConventions = callConvention;

            AllowsUnverifiableCIL = allowUnverifiable;

            IsVerifying = doVerify;
            UsesStrictBranchVerification = strictBranchVerification;

            ReturnType     = TypeOnStack.Get(returnType);
            ParameterTypes = parameterTypes;

            IL = new BufferedILGenerator <DelegateType>();

            Trackers = new LinqList <VerifiableTracker>();

            AllLocals = new LinqList <Local>();

            UnusedLocals   = new LinqHashSet <Local>();
            UnusedLabels   = new LinqHashSet <Label>();
            UnmarkedLabels = new LinqHashSet <Label>();

            Branches = new LinqList <SigilTuple <OpCode, Label, int> >();
            Marks    = new LinqDictionary <Label, int>();
            Returns  = new LinqList <int>();
            Throws   = new LinqList <int>();

            BranchPatches = new LinqDictionary <int, SigilTuple <Label, UpdateOpCodeDelegate, OpCode> >();

            CurrentExceptionBlock = new Stack <ExceptionBlock>();

            TryBlocks     = new LinqDictionary <ExceptionBlock, SigilTuple <int, int> >();
            CatchBlocks   = new LinqDictionary <CatchBlock, SigilTuple <int, int> >();
            FinallyBlocks = new LinqDictionary <FinallyBlock, SigilTuple <int, int> >();

            ReadonlyPatches = new LinqList <SigilTuple <int, TypeOnStack> >();

            Shorthand = new EmitShorthand <DelegateType>(this);

            FreedLocals = new LinqList <Local>();

            CurrentLocals = new LinqDictionary <string, Local>();
            Locals        = new LocalLookup(CurrentLocals);

            CurrentLabels = new LinqDictionary <string, Label>();
            Labels        = new LabelLookup(CurrentLabels);

            ElidableCasts = new LinqList <int>();

            TypesProducedAtIndex = new LinqDictionary <int, LinqList <TypeOnStack> >();

            var start = DefineLabel("__start");

            CurrentVerifiers = IsVerifying ? new RollingVerifier(start, UsesStrictBranchVerification) : new RollingVerifierWithoutVerification(start);
            MarkLabel(start);
        }
Ejemplo n.º 4
0
        internal Local(object owner, ushort index, Type localType, DeclareLocallDelegate local, string name, LocalReusableDelegate reusable, int declaredAt)
        {
            _Owner   = owner;
            LocalDel = local;
            Name     = name;

            Index     = index;
            LocalType = localType;
            StackType = TypeOnStack.Get(localType);

            Reusable = reusable;

            DeclaredAtIndex = declaredAt;
        }
Ejemplo n.º 5
0
        Emit <DelegateType> InnerNewObject(ConstructorInfo constructor, Type[] parameterTypes)
        {
            var expectedParams = ((LinqArray <Type>)parameterTypes).Select(p => TypeOnStack.Get(p)).Reverse().ToList();

            var makesType = TypeOnStack.Get(constructor.DeclaringType);

            var transitions =
                new[]
            {
                new StackTransition(expectedParams.AsEnumerable(), new [] { makesType })
            };

            UpdateState(OpCodes.Newobj, constructor, Wrap(transitions, "NewObject"));

            return(this);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Cast a reference on the stack to the given reference type.
        ///
        /// If the cast is not legal, a CastClassException will be thrown at runtime.
        /// </summary>
        public Emit <DelegateType> CastClass(Type referenceType)
        {
            if (referenceType == null)
            {
                throw new ArgumentNullException("referenceType");
            }

            if (referenceType.IsValueType)
            {
                throw new ArgumentException("Can only cast to ReferenceTypes, found " + referenceType);
            }

            var  curIndex = IL.Index;
            bool elided   = false;

            VerificationCallback before =
                (stack, baseless) =>
            {
                // Can't reason about stack unless it's completely known
                if (baseless || elided)
                {
                    return;
                }

                var onStack = stack.First();

                if (onStack.All(a => ExtensionMethods.IsAssignableFrom(referenceType, a)))
                {
                    ElidableCasts.Add(curIndex);
                    elided = true;
                }
            };

            var newType = TypeOnStack.Get(referenceType);

            var transitions =
                new[]
            {
                new StackTransition(new [] { typeof(object) }, new [] { referenceType }, before: before)
            };

            UpdateState(OpCodes.Castclass, referenceType, Wrap(transitions, "CastClass"));

            return(this);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Calls the given constructor.  Pops its arguments in reverse order (left-most deepest in the stack).
        ///
        /// The `this` reference should appear before any parameters.
        /// </summary>
        public Emit <DelegateType> Call(ConstructorInfo cons)
        {
            if (cons == null)
            {
                throw new ArgumentNullException("cons");
            }

            if (HasFlag(cons.CallingConvention, CallingConventions.VarArgs) && !HasFlag(cons.CallingConvention, CallingConventions.Standard))
            {
                throw new NotSupportedException("Calling constructors with VarArgs is currently not supported.");
            }

            if (!IsBuildingConstructor)
            {
                throw new SigilVerificationException("Constructors may only be called directly from within a constructor, use NewObject to allocate a new object with a specific constructor.", IL.Instructions(AllLocals));
            }

            if (!IsLegalConstructoCall(cons))
            {
                throw new SigilVerificationException("Only constructors defined in the current class or it's base class may be called", IL.Instructions(AllLocals));
            }

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

            var declaring = cons.DeclaringType;

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

            expectedParams.Insert(0, TypeOnStack.Get(declaring));

            var transitions =
                new[]
            {
                new StackTransition(expectedParams.Reverse().AsEnumerable(), new TypeOnStack[0])
            };

            UpdateState(OpCodes.Call, cons, ((LinqArray <ParameterInfo>)cons.GetParameters()).Select(s => s.ParameterType).AsEnumerable(), Wrap(transitions, "Call"));

            return(this);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Pops # of parameters to the given constructor arguments from the stack, invokes the constructor, and pushes a reference to the new object onto the stack.
        /// </summary>
        public Emit <DelegateType> NewObject(ConstructorInfo constructor)
        {
            if (constructor == null)
            {
                throw new ArgumentNullException("constructor");
            }

            var expectedParams = ((LinqArray <ParameterInfo>)constructor.GetParameters()).Select(p => TypeOnStack.Get(p.ParameterType)).Reverse().ToList();

            var makesType = TypeOnStack.Get(constructor.DeclaringType);

            var transitions =
                new[]
            {
                new StackTransition(expectedParams.AsEnumerable(), new [] { makesType })
            };

            UpdateState(OpCodes.Newobj, constructor, Wrap(transitions, "NewObject"));

            return(this);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// <para>
        /// Pops a pointer to a method, and then all it's arguments (in reverse order, left-most parameter is deepest on the stack) and calls
        /// invokes the method pointer.  If the method returns a non-void result, it is pushed onto the stack.
        /// </para>
        /// <para>This override allows an arglist to be passed for calling VarArgs methods.</para>
        /// </summary>
        public Emit <DelegateType> CallIndirect(CallingConventions callConventions, Type returnType, Type[] parameterTypes, Type[] arglist = null)
        {
            if (returnType == null)
            {
                throw new ArgumentNullException("returnType");
            }

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

            var known = CallingConventions.Any | CallingConventions.ExplicitThis | CallingConventions.HasThis | CallingConventions.Standard | CallingConventions.VarArgs;

            known = ~known;

            if ((callConventions & known) != 0)
            {
                throw new ArgumentException("Unexpected value not in CallingConventions", "callConventions");
            }

            if (!AllowsUnverifiableCIL)
            {
                FailUnverifiable("CallIndirect");
            }

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

            var takeExtra = 1;

            if (HasFlag(callConventions, CallingConventions.HasThis))
            {
                takeExtra++;
            }

            IEnumerable <StackTransition> transitions;

            if (HasFlag(callConventions, CallingConventions.HasThis))
            {
                var p = new List <Type>();
                p.Add(typeof(NativeIntType));
                p.AddRange(LinqAlternative.Reverse(parameterTypes).AsEnumerable());
                p.Add(typeof(WildcardType));

                if (returnType != typeof(void))
                {
                    transitions =
                        new[]
                    {
                        new StackTransition(p, new [] { returnType })
                    };
                }
                else
                {
                    transitions =
                        new[]
                    {
                        new StackTransition(p, TypeHelpers.EmptyTypes)
                    };
                }
            }
            else
            {
                var p = new List <Type>();
                p.Add(typeof(NativeIntType));
                p.AddRange(LinqAlternative.Reverse(parameterTypes).AsEnumerable());

                if (returnType != typeof(void))
                {
                    transitions =
                        new[]
                    {
                        new StackTransition(p, new [] { returnType })
                    };
                }
                else
                {
                    transitions =
                        new[]
                    {
                        new StackTransition(p, TypeHelpers.EmptyTypes)
                    };
                }
            }

            var onStack = CurrentVerifiers.InferStack(LinqAlternative.ElementAt(transitions, 0).PoppedFromStack.Length);

            if (onStack != null && onStack.Count > 0)
            {
                var funcPtr = onStack.First();

                if (funcPtr == TypeOnStack.Get <NativeIntType>() && funcPtr.HasAttachedMethodInfo)
                {
                    if (funcPtr.CallingConvention != callConventions)
                    {
                        throw new SigilVerificationException("CallIndirect expects method calling conventions to match, found " + funcPtr.CallingConvention + " on the stack", IL.Instructions(AllLocals));
                    }

                    if (HasFlag(callConventions, CallingConventions.HasThis))
                    {
                        var thisRef = onStack.Last();

                        if (!ExtensionMethods.IsAssignableFrom(funcPtr.InstanceType, thisRef))
                        {
                            throw new SigilVerificationException("CallIndirect expects a 'this' value assignable to " + funcPtr.InstanceType + ", found " + thisRef, IL.Instructions(AllLocals));
                        }
                    }

                    if (funcPtr.ReturnType != returnType)
                    {
                        throw new SigilVerificationException("CallIndirect expects method return types to match, found " + funcPtr.ReturnType + " on the stack", IL.Instructions(AllLocals));
                    }
                }
            }

            UpdateState(OpCodes.Calli, callConventions, returnType, parameterTypes, Wrap(transitions, "CallIndirect"), arglist);

            return(this);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Calls the given method.  Pops its arguments in reverse order (left-most deepest in the stack), and pushes the return value if it is non-void.
        ///
        /// If the given method is an instance method, the `this` reference should appear before any parameters.
        ///
        /// Call does not respect overrides, the implementation defined by the given MethodInfo is what will be called at runtime.
        ///
        /// To call overrides of instance methods, use CallVirtual.
        ///
        /// When calling VarArgs methods, arglist should be set to the types of the extra parameters to be passed.
        /// </summary>
        public Emit <DelegateType> Call(MethodInfo method, Type[] arglist = null)
        {
            if (method == null)
            {
                throw new ArgumentNullException("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();

            if (arglist != null)
            {
                expectedParams.AddRange(((LinqArray <Type>)arglist).Select(t => TypeOnStack.Get(t)));
            }

            // Instance methods expect this to preceed parameters
            if (HasFlag(method.CallingConvention, CallingConventions.HasThis))
            {
                var declaring = method.DeclaringType;

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

                expectedParams.Insert(0, TypeOnStack.Get(declaring));
            }

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

            var firstParamIsThis =
                HasFlag(method.CallingConvention, CallingConventions.HasThis) ||
                HasFlag(method.CallingConvention, CallingConventions.ExplicitThis);

            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.Call, method, ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => s.ParameterType).AsEnumerable(), Wrap(transitions, "Call"), firstParamIsThis: firstParamIsThis, arglist: arglist);

            return(this);
        }
Ejemplo n.º 11
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);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Calls the method being constructed by the given emit.  Emits so used must have been constructed with BuildMethod or related methods.
        ///
        /// Pops its arguments in reverse order (left-most deepest in the stack), and pushes the return value if it is non-void.
        ///
        /// If the given method is an instance method, the `this` reference should appear before any parameters.
        ///
        /// Call does not respect overrides, the implementation defined by the given MethodInfo is what will be called at runtime.
        ///
        /// To call overrides of instance methods, use CallVirtual.
        ///
        /// When calling VarArgs methods, arglist should be set to the types of the extra parameters to be passed.
        /// </summary>
        public Emit <DelegateType> Call <MethodEmit>(Emit <MethodEmit> emit, Type[] arglist = null)
        {
            if (emit == null)
            {
                throw new ArgumentNullException("emit");
            }

            MethodInfo methodInfo = emit.MtdBuilder ?? (MethodInfo)emit.DynMethod;

            if (methodInfo == null)
            {
                throw new InvalidOperationException("emit must be building a method");
            }

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

            var expectedParams = ((LinqArray <Type>)emit.ParameterTypes).Select(s => TypeOnStack.Get(s)).ToList();

            if (arglist != null)
            {
                expectedParams.AddRange(((LinqArray <Type>)arglist).Select(t => TypeOnStack.Get(t)));
            }

            // Instance methods expect this to preceed parameters
            var declaring = methodInfo.DeclaringType;

            if (declaring != null)
            {
                if (HasFlag(emit.CallingConventions, CallingConventions.HasThis))
                {
                    if (declaring.IsValueType)
                    {
                        declaring = declaring.MakePointerType();
                    }

                    expectedParams.Insert(0, TypeOnStack.Get(declaring));
                }
            }

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

            var firstParamIsThis =
                HasFlag(emit.CallingConventions, CallingConventions.HasThis) ||
                HasFlag(emit.CallingConventions, CallingConventions.ExplicitThis);

            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.Call, methodInfo, emit.ParameterTypes, Wrap(transitions, "Call"), firstParamIsThis: firstParamIsThis, arglist: arglist);

            return(this);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// 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.
        ///
        /// The `this` reference should appear before any arguments (deepest in the stack).
        ///
        /// The method invoked at runtime is determined by the type of the `this` reference.
        ///
        /// If the method invoked shouldn't vary (or if the method is static), use Call instead.
        /// </summary>
        public Emit <DelegateType> CallVirtual(Emit <DelegateType> emit, Type constrained = null, Type[] arglist = null)
        {
            if (emit == null)
            {
                throw new ArgumentNullException("emit");
            }

            var method = emit.MtdBuilder ?? (MethodInfo)emit.DynMethod;

            if (method == null)
            {
                throw new ArgumentException("Has to be a 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 <Type>)emit.ParameterTypes).Select(s => TypeOnStack.Get(s)).ToList();

            if (arglist != null)
            {
                expectedParams.AddRange(((LinqArray <Type>)arglist).Select(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, emit.ParameterTypes, Wrap(transitions, "CallVirtual"), arglist: arglist);

            return(this);
        }