Example #1
0
        /// <summary>
        /// Pops a size from the stack, allocates size bytes on the local dynamic memory pool, and pushes a pointer to the allocated block.
        ///
        /// LocalAllocate can only be called if the stack is empty aside from the size value.
        ///
        /// Memory allocated with LocalAllocate is released when the current method ends execution.
        /// </summary>
        public Emit <DelegateType> LocalAllocate()
        {
            if (CatchBlocks.Any(c => c.Value.Item2 == -1))
            {
                throw new InvalidOperationException("LocalAllocate cannot be used in a catch block");
            }

            if (FinallyBlocks.Any(f => f.Value.Item2 == -1))
            {
                throw new InvalidOperationException("LocalAllocate cannot be used in a finally block");
            }

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

            UpdateState(Wrap(new[] { new StackTransition(1) }, "LocalAllocate"));

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

            UpdateState(OpCodes.Localloc, Wrap(transitions, "LocalAllocate"));

            return(this);
        }
Example #2
0
        private void ValidateTryCatchFinallyBlocks()
        {
            foreach (var kv in TryBlocks.AsEnumerable())
            {
                if (kv.Value.Item2 == -1)
                {
                    throw
                        new SigilVerificationException(
                            "Unended ExceptionBlock " + kv.Key,
                            IL.Instructions(AllLocals)
                            );
                }
            }

            foreach (var kv in CatchBlocks.AsEnumerable())
            {
                if (kv.Value.Item2 == -1)
                {
                    throw new Exception("Invalid State, all ExceptionBlocks are ended but CatchBlock " + kv.Key + " isn't ended");
                }
            }

            foreach (var kv in FinallyBlocks.AsEnumerable())
            {
                if (kv.Value.Item2 == -1)
                {
                    throw new Exception("Invalid State, all ExceptionBlocks are ended but FinallyBlock " + kv.Key + " isn't ended");
                }
            }
        }
Example #3
0
        /// <summary>
        /// Begins a catch block for the given exception type in the given exception block.
        ///
        /// The given exception block must still be open.
        /// </summary>
        public CatchBlock BeginCatchBlock(ExceptionBlock forTry, Type exceptionType)
        {
            if (exceptionType == null)
            {
                throw new ArgumentNullException("exceptionType");
            }

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

            if (((IOwned)forTry).Owner != this)
            {
                FailOwnership(forTry);
            }

            if (CurrentExceptionBlock.Count > 0 && forTry != CurrentExceptionBlock.Peek())
            {
                throw new InvalidOperationException("Cannot start CatchBlock on " + forTry + " while inner ExceptionBlock is still open");
            }

            if (!typeof(Exception).IsAssignableFrom(exceptionType))
            {
                throw new ArgumentException("BeginCatchBlock expects a type descending from Exception, found " + exceptionType, "exceptionType");
            }

            var currentlyOpen = CatchBlocks.Where(c => c.Key.ExceptionBlock == forTry && c.Value.Item2 == -1).Select(s => s.Key).SingleOrDefault();

            if (currentlyOpen != null)
            {
                throw new InvalidOperationException("Cannot start a new catch block, " + currentlyOpen + " has not been ended");
            }

            if (MustMark)
            {
                MarkLabel(DefineLabel(AutoNamer.Next(this, "__autolabel")));
            }

            UpdateState(Wrap(new[] { new StackTransition(0) }, "BeginCatchBlock"));

            var tryBlock = TryBlocks[forTry];

            if (tryBlock.Item2 != -1)
            {
                throw new SigilVerificationException("BeginCatchBlock expects an unclosed exception block, but " + forTry + " is already closed", IL.Instructions(AllLocals));
            }

            IL.BeginCatchBlock(exceptionType);

            UpdateState(Wrap(StackTransition.Push(exceptionType), "BeginCatchBlock"));

            var ret = new CatchBlock(exceptionType, forTry);

            CatchBlocks[ret] = SigilTuple.Create(IL.Index, -1);

            return(ret);
        }
Example #4
0
        /// <summary>
        /// Transfers control to another method.
        ///
        /// The parameters and calling convention of method must match the current one's.
        ///
        /// The stack must be empty to jump.
        ///
        /// Like the branching instructions, Jump cannot leave exception blocks.
        /// </summary>
        public Emit <DelegateType> Jump(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (method.CallingConvention != CallingConventions)
            {
                throw new ArgumentException("Jump expected a calling convention of " + CallingConventions + ", found " + method.CallingConvention);
            }

            var paras = method.GetParameters();

            if (paras.Length != ParameterTypes.Length)
            {
                throw new ArgumentException("Jump expected a method with " + ParameterTypes.Length + " parameters, found " + paras.Length);
            }

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

            if (CatchBlocks.Any(t => t.Value.Item2 == -1))
            {
                throw new InvalidOperationException("Jump cannot transfer control from a catch block");
            }

            if (FinallyBlocks.Any(t => t.Value.Item2 == -1))
            {
                throw new InvalidOperationException("Jump cannot transfer control from a finally block");
            }

            if (TryBlocks.Any(t => t.Value.Item2 == -1))
            {
                throw new InvalidOperationException("Jump cannot transfer control from an exception block");
            }

            UpdateState(Wrap(new[] { new StackTransition(0) }, "Jump"));

            for (var i = 0; i < paras.Length; i++)
            {
                var shouldBe   = paras[i].ParameterType;
                var actuallyIs = ParameterTypes[i];

                if (!shouldBe.IsAssignableFrom(actuallyIs))
                {
                    throw new SigilVerificationException("Jump expected the #" + i + " parameter to be assignable from " + actuallyIs + ", but found " + shouldBe, IL.Instructions(AllLocals));
                }
            }

            UpdateState(OpCodes.Jmp, method, TypeHelpers.EmptyTypes, Wrap(StackTransition.None(), "Jump"));

            return(this);
        }
Example #5
0
 public override int GetHashCode()
 {
     unchecked
     {
         var hashCode = 37 + Body.GetHashCode();
         hashCode = (hashCode * 397) ^ CatchBlocks.GetHashCode();
         hashCode = (hashCode * 397) ^ Finally.GetHashCode();
         return(hashCode);
     }
 }
Example #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);
        }
        /// <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);
        }
Example #8
0
 private bool Equals(TryBlock other)
 {
     return(Body.Equals(other.Body) && CatchBlocks.Equals(other.CatchBlocks) && Finally.Equals(other.Finally));
 }
Example #9
0
        private void ValidateTryCatchFinallyBranches()
        {
            foreach (var branch in Branches.AsEnumerable())
            {
                var instr = BranchPatches[branch.Item3];

                var toLabel   = branch.Item2;
                var fromIndex = branch.Item3;

                var toIndex = Marks[toLabel];

                var fromTryBlocks     = TryBlocks.Where(t => fromIndex >= t.Value.Item1 && fromIndex <= t.Value.Item2).ToList();
                var fromCatchBlocks   = CatchBlocks.Where(c => fromIndex >= c.Value.Item1 && fromIndex <= c.Value.Item2).ToList();
                var fromFinallyBlocks = FinallyBlocks.Where(f => fromIndex >= f.Value.Item1 && fromIndex <= f.Value.Item2).ToList();

                var toTryBlocks     = TryBlocks.Where(t => toIndex >= t.Value.Item1 && toIndex <= t.Value.Item2).ToList();
                var toCatchBlocks   = CatchBlocks.Where(c => toIndex >= c.Value.Item1 && toIndex <= c.Value.Item2).ToList();
                var toFinallyBlocks = FinallyBlocks.Where(f => toIndex >= f.Value.Item1 && toIndex <= f.Value.Item2).ToList();

                var fromTryBlock     = fromTryBlocks.OrderByDescending(t => t.Value.Item1).Select(t => t.Key).FirstOrDefault();
                var fromCatchBlock   = fromCatchBlocks.OrderByDescending(c => c.Value.Item1).Select(c => c.Key).FirstOrDefault();
                var fromFinallyBlock = fromFinallyBlocks.OrderByDescending(f => f.Value.Item1).Select(f => f.Key).FirstOrDefault();

                var toTryBlock     = toTryBlocks.OrderByDescending(t => t.Value.Item1).Select(t => t.Key).FirstOrDefault();
                var toCatchBlock   = toCatchBlocks.OrderByDescending(c => c.Value.Item1).Select(c => c.Key).FirstOrDefault();
                var toFinallyBlock = toFinallyBlocks.OrderByDescending(f => f.Value.Item1).Select(f => f.Key).FirstOrDefault();

                // Nothing funky going on, carry on
                if (fromTryBlock == null && fromCatchBlock == null && fromFinallyBlock == null && toTryBlock == null && toCatchBlock == null && toFinallyBlock == null)
                {
                    continue;
                }

                if (fromCatchBlock != null && toCatchBlock != fromCatchBlock)
                {
                    if (instr.Item3 != OpCodes.Leave)
                    {
                        throw
                            new SigilVerificationException(
                                "Cannot branch from inside " + fromCatchBlock + " to outside, exit the ExceptionBlock first",
                                IL.Instructions(AllLocals)
                                );
                    }
                }

                if (fromFinallyBlock != null && toFinallyBlock != fromFinallyBlock)
                {
                    throw
                        new SigilVerificationException(
                            "Cannot branch from inside " + fromFinallyBlock + " to outside, exit the ExceptionBlock first",
                            IL.Instructions(AllLocals)
                            );
                }

                if (toFinallyBlock != null && fromFinallyBlock != toFinallyBlock)
                {
                    throw
                        new SigilVerificationException(
                            "Cannot branch into a FinallyBlock",
                            IL.Instructions(AllLocals)
                            );
                }

                if (fromTryBlock != null && toTryBlock != fromTryBlock)
                {
                    if (instr.Item3 != OpCodes.Leave)
                    {
                        throw
                            new SigilVerificationException(
                                "Cannot branch from inside " + fromTryBlock + " to outside, exit the ExceptionBlock first",
                                IL.Instructions(AllLocals)
                                );
                    }
                }
            }
        }
Example #10
0
        /// <summary>
        /// Ends the given exception block.
        ///
        /// All catch and finally blocks associated with the given exception block must be ended before this method is called.
        /// </summary>
        public Emit <DelegateType> EndExceptionBlock(ExceptionBlock forTry)
        {
            if (forTry == null)
            {
                throw new ArgumentNullException("forTry");
            }

            if (((IOwned)forTry).Owner != this)
            {
                FailOwnership(forTry);
            }

            var location = TryBlocks[forTry];

            // Can't close the same exception block twice
            if (location.Item2 != -1)
            {
                throw new InvalidOperationException("ExceptionBlock has already been ended");
            }

            if (CurrentExceptionBlock.Count > 0 && forTry != CurrentExceptionBlock.Peek())
            {
                throw new InvalidOperationException("Cannot end outer ExceptionBlock " + forTry + " while inner EmitExceptionBlock " + CurrentExceptionBlock.Peek() + " is open");
            }

            // Can't close an exception block while there are outstanding catch blocks
            foreach (var kv in CatchBlocks.AsEnumerable())
            {
                if (kv.Key.ExceptionBlock != forTry)
                {
                    continue;
                }

                if (kv.Value.Item2 == -1)
                {
                    throw new InvalidOperationException("Cannot end ExceptionBlock, CatchBlock " + kv.Key + " has not been ended");
                }
            }

            foreach (var kv in FinallyBlocks.AsEnumerable())
            {
                if (kv.Key.ExceptionBlock != forTry)
                {
                    continue;
                }

                if (kv.Value.Item2 == -1)
                {
                    throw new InvalidOperationException("Cannot end ExceptionBlock, FinallyBlock " + kv.Key + " has not been ended");
                }
            }

            if (!CatchBlocks.Any(k => k.Key.ExceptionBlock == forTry) && !FinallyBlocks.Any(k => k.Key.ExceptionBlock == forTry))
            {
                throw new InvalidOperationException("Cannot end ExceptionBlock without defining at least one of a catch or finally block");
            }

            IL.EndExceptionBlock();

            TryBlocks[forTry] = SigilTuple.Create(location.Item1, IL.Index);

            Marks[forTry.Label] = IL.Index;

            CurrentExceptionBlock.Pop();

            if (MustMark)
            {
                MarkLabel(DefineLabel(AutoNamer.Next(this, "__autolabel")));
            }

            return(this);
        }