Example #1
0
        public static bool IsAssignableFrom(this TypeOnStack type1, TypeOnStack type2)
        {
            // Native int can be convereted to any pointer type
            if (type1.IsPointer && type2 == TypeOnStack.Get<NativeIntType>()) return true;
            if (type2.IsPointer && type1 == TypeOnStack.Get<NativeIntType>()) return true;

            if ((type1.IsPointer || type1.IsReference) && !(type2.IsPointer || type2.IsReference)) return false;
            if ((type2.IsPointer || type2.IsReference) && !(type1.IsPointer || type1.IsReference)) return false;

            if (type1.IsPointer || type1.IsReference)
            {
                return type1.Type.GetElementType() == type2.Type.GetElementType();
            }

            var t1 = type1.Type;
            var t2 = type2.Type;

            t1 = Alias(t1);
            t2 = Alias(t2);

            // The null type can be assigned to any reference type
            if (t2 == typeof(NullType) && !t1.IsValueType) return true;

            return ReallyIsAssignableFrom(t1, t2);
        }
        /// <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);
        }
Example #3
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);
        }
        /// <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);
        }
Example #5
0
        /// <summary>
        /// Pushes a pointer to the given function onto the stack, as a native int.
        ///
        /// To resolve a method at runtime using an object, use LoadVirtualFunctionPointer instead.
        /// </summary>
        public Emit <DelegateType> LoadFunctionPointer(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            var parameters = method.GetParameters();

            var paramList = ((LinqArray <ParameterInfo>)parameters).Select(p => p.ParameterType).ToList();

            var type =
                TypeOnStack.GetKnownFunctionPointer(
                    method.CallingConvention,
                    HasFlag(method.CallingConvention, CallingConventions.HasThis) ? method.DeclaringType : null,
                    method.ReturnType,
                    paramList.ToArray()
                    );

            UpdateState(OpCodes.Ldftn, method, paramList.AsEnumerable(), Wrap(new[] { new StackTransition(new TypeOnStack[0], new[] { type }) }, "LoadFunctionPointer"));

            return(this);
        }
        Emit <DelegateType> InnerLoadVirtualFunctionPointer(MethodInfo method, Type[] parameterTypes)
        {
            var thisType =
                HasFlag(method.CallingConvention, CallingConventions.HasThis) ?
                method.DeclaringType :
                null;

            var paramList = new List <Type>(parameterTypes);

            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, parameterTypes, Wrap(transitions, "LoadVirtualFunctionPointer"));

            return(this);
        }
Example #7
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);
        }
Example #8
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);
        }
Example #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);
        }
Example #10
0
        public static bool IsAssignableFrom(TypeOnStack type1, TypeOnStack type2)
        {
            // wildcards match *everything*
            if (type1 == TypeOnStack.Get<WildcardType>() || type2 == TypeOnStack.Get<WildcardType>()) return true;

            if (type1.IsArray && type2.IsArray)
            {
                if (type1.Type.GetArrayRank() == type2.Type.GetArrayRank())
                {
                    var t1Elem = type1.Type.GetElementType();
                    var t2Elem = type2.Type.GetElementType();

                    while (t1Elem.HasElementType) t1Elem = t1Elem.GetElementType();
                    while (t2Elem.HasElementType) t2Elem = t2Elem.GetElementType();

                    if (t1Elem == typeof(WildcardType) || t2Elem == typeof(WildcardType)) return true;
                }
            }

            if (type1.IsPointer && type2.IsPointer)
            {
                if (type1.Type.GetElementType() == typeof(WildcardType) || type2.Type.GetElementType() == typeof(WildcardType)) return true;
            }

            if (type1.IsReference && type2.IsReference)
            {
                if (type1.Type.GetElementType() == typeof(WildcardType) || type2.Type.GetElementType() == typeof(WildcardType)) return true;
            }

            // any pointer type matches, well, any pointer
            if (type1.Type == typeof(AnyPointerType) && type2.IsPointer) return true;
            if (type2.Type == typeof(AnyPointerType) && type1.IsPointer) return true;

            // likewise for any by ref
            if (type1.Type == typeof(AnyByRefType) && type2.IsReference) return true;
            if (type2.Type == typeof(AnyByRefType) && type1.IsReference) return true;

            // Native int can be convereted to any pointer type
            if (type1.IsPointer && type2 == TypeOnStack.Get<NativeIntType>()) return true;
            if (type2.IsPointer && type1 == TypeOnStack.Get<NativeIntType>()) return true;

            if ((type1.IsPointer || type1.IsReference) && !(type2.IsPointer || type2.IsReference)) return false;
            if ((type2.IsPointer || type2.IsReference) && !(type1.IsPointer || type1.IsReference)) return false;

            if (type1.IsPointer || type1.IsReference)
            {
                return type1.Type.GetElementType() == type2.Type.GetElementType();
            }

            var t1 = type1.Type;
            var t2 = type2.Type;

            // The null type can be assigned to any reference type
            if (t1 == typeof(NullType) && !t2.IsValueType) return true;
            if (t2 == typeof(NullType) && !t1.IsValueType) return true;

            t1 = Alias(t1);
            t2 = Alias(t2);

            return ReallyIsAssignableFrom(t1, t2);
        }
Example #11
0
 public static bool IsAssignableFrom(Type type1, TypeOnStack type2)
 {
     return TypeOnStack.Get(type1).IsAssignableFrom(type2);
 }
Example #12
0
 private StackState(StackState prev, TypeOnStack val)
 {
     Previous = prev;
     Value = val;
 }
Example #13
0
        public TypeOnStack[] Top(int n = 1)
        {
            var ret = new TypeOnStack[n];

            int i = 0;
            var cur = this;

            while (i < n)
            {
                if (cur.IsRoot) return null;

                ret[i] = cur.Value;
                cur = cur.Previous;
                i++;
            }

            return ret;
        }
Example #14
0
 public StackState Push(TypeOnStack val)
 {
     return new StackState(this, val);
 }
Example #15
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);
        }
Example #16
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);
        }