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>
        /// <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);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Pops a value off the stack and throws it as an exception.
        ///
        /// Throw expects the value to be or extend from a System.Exception.
        /// </summary>
        public Emit <DelegateType> Throw()
        {
            UpdateState(OpCodes.Throw, Wrap(StackTransition.Pop <Exception>(), "Throw"));
            UpdateState(Wrap(new[] { new StackTransition(new[] { typeof(PopAllType) }, TypeHelpers.EmptyTypes) }, "Throw"));

            Throws.Add(IL.Index);

            MustMark = true;

            var verify = CurrentVerifiers.Throw();

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

            return(this);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Marks a label in the instruction stream.
        ///
        /// When branching, leaving, or switching with a label control will be transfered to where it was *marked* not defined.
        ///
        /// Labels can only be marked once, and *must* be marked before creating a delegate.
        /// </summary>
        public Emit <DelegateType> MarkLabel(Label label)
        {
            if (label == null)
            {
                throw new ArgumentNullException("label");
            }

            if (((IOwned)label).Owner != this)
            {
                if (((IOwned)label).Owner is DisassembledOperations <DelegateType> )
                {
                    return(MarkLabel(label.Name));
                }

                FailOwnership(label);
            }

            if (!UnmarkedLabels.Contains(label))
            {
                throw new InvalidOperationException("label [" + label.Name + "] has already been marked, and cannot be marked a second time");
            }

            if (MustMark)
            {
                MustMark = false;
            }

            var valid = CurrentVerifiers.Mark(label);

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

            UnmarkedLabels.Remove(label);

            IL.MarkLabel(label);

            Marks[label] = IL.Index;

            return(this);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// <para>Pops one argument from the stack, branches to the given label if the value is true.</para>
        /// <para>A value is true if it is non-zero or non-null.</para>
        /// </summary>
        public Emit <DelegateType> BranchIfTrue(Label label)
        {
            if (label == null)
            {
                throw new ArgumentNullException("label");
            }

            if (((IOwned)label).Owner != this)
            {
                if (((IOwned)label).Owner is DisassembledOperations <DelegateType> )
                {
                    return(BranchIfTrue(label.Name));
                }

                FailOwnership(label);
            }

            UnusedLabels.Remove(label);

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

            UpdateOpCodeDelegate update;

            UpdateState(OpCodes.Brtrue, label, Wrap(transitions, "BranchIfTrue"), out update);

            var valid = CurrentVerifiers.ConditionalBranch(label);

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

            Branches.Add(SigilTuple.Create(OpCodes.Brtrue, label, IL.Index));

            BranchPatches[IL.Index] = SigilTuple.Create(label, update, OpCodes.Brtrue);

            return(this);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// <para>Leave an exception or catch block, branching to the given label.</para>
        /// <para>This instruction empties the stack.</para>
        /// </summary>
        public Emit <DelegateType> Leave(Label label)
        {
            if (label == null)
            {
                throw new ArgumentNullException("label");
            }

            if (((IOwned)label).Owner != this)
            {
                if (((IOwned)label).Owner is DisassembledOperations <DelegateType> )
                {
                    return(Leave(label.Name));
                }

                FailOwnership(label);
            }

            if (!TryBlocks.Any(t => t.Value.Item2 == -1) && !CatchBlocks.Any(c => c.Value.Item2 == -1))
            {
                throw new InvalidOperationException("Leave can only be used within an exception or catch block");
            }

            // Note that Leave *always* nuked the stack; nothing survies exiting an exception block
            UpdateOpCodeDelegate update;

            UpdateState(OpCodes.Leave, label, Wrap(new[] { new StackTransition(new [] { typeof(PopAllType) }, TypeHelpers.EmptyTypes) }, "Leave"), out update);

            Branches.Add(SigilTuple.Create(OpCodes.Leave, label, IL.Index));

            BranchPatches[IL.Index] = SigilTuple.Create(label, update, OpCodes.Leave);
            MustMark = true;

            var valid = CurrentVerifiers.UnconditionalBranch(label);

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

            return(this);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Unconditionally branches to the given label.
        /// </summary>
        public Emit <DelegateType> Branch(Label label)
        {
            if (label == null)
            {
                throw new ArgumentNullException("label");
            }

            if (((IOwned)label).Owner != this)
            {
                if (((IOwned)label).Owner is DisassembledOperations <DelegateType> )
                {
                    return(Branch(label.Name));
                }

                FailOwnership(label);
            }

            UnusedLabels.Remove(label);

            UpdateOpCodeDelegate update;

            UpdateState(OpCodes.Br, label, Wrap(StackTransition.None(), "Branch"), out update);

            var valid = CurrentVerifiers.UnconditionalBranch(label);

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

            Branches.Add(SigilTuple.Create(OpCodes.Br, label, IL.Index));

            BranchPatches[IL.Index] = SigilTuple.Create(label, update, OpCodes.Br);

            MustMark = true;

            return(this);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// From within a catch block, rethrows the exception that caused the catch block to be entered.
        /// </summary>
        public Emit <DelegateType> ReThrow()
        {
            if (!CatchBlocks.Any(c => c.Value.Item2 == -1))
            {
                throw new InvalidOperationException("ReThrow is only legal in a catch block");
            }

            UpdateState(OpCodes.Rethrow, Wrap(StackTransition.None(), "ReThrow"));
            UpdateState(Wrap(new[] { new StackTransition(new[] { typeof(PopAllType) }, Type.EmptyTypes) }, "ReThrow"));

            Throws.Add(IL.Index);

            MustMark = true;

            var verify = CurrentVerifiers.ReThrow();

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

            return(this);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Pops two arguments from the stack, branches to the given label if the second value is less than the first value (when treated as unsigned values).
        /// </summary>
        public Emit <DelegateType> UnsignedBranchIfLess(Label label)
        {
            if (label == null)
            {
                throw new ArgumentNullException("label");
            }

            if (((IOwned)label).Owner != this)
            {
                if (((IOwned)label).Owner is DisassembledOperations <DelegateType> )
                {
                    return(UnsignedBranchIfLess(label.Name));
                }

                FailOwnership(label);
            }

            UnusedLabels.Remove(label);

            UpdateOpCodeDelegate update;

            UpdateState(OpCodes.Blt_Un, label, BranchComparableTransitions("UnsignedBranchIfLess"), out update);

            var valid = CurrentVerifiers.ConditionalBranch(label);

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

            Branches.Add(SigilTuple.Create(OpCodes.Blt_Un, label, IL.Index));

            BranchPatches[IL.Index] = SigilTuple.Create(label, update, OpCodes.Blt_Un);

            return(this);
        }
Ejemplo n.º 10
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);
        }