コード例 #1
0
 internal void Define(LabelScopeInfo block)
 {
     for (LabelScopeInfo info = block; info != null; info = info.Parent)
     {
         if (info.ContainsTarget(this._node))
         {
             throw System.Linq.Expressions.Error.LabelTargetAlreadyDefined(this._node.Name);
         }
     }
     this._definitions.Add(block);
     block.AddLabelInfo(this._node, this);
     if (this._definitions.Count == 1)
     {
         foreach (LabelScopeInfo info2 in this._references)
         {
             this.ValidateJump(info2);
         }
     }
     else
     {
         if (this._acrossBlockJump)
         {
             throw System.Linq.Expressions.Error.AmbiguousJump(this._node.Name);
         }
         this._labelDefined = false;
     }
 }
コード例 #2
0
ファイル: LabelInfo.cs プロジェクト: dotnet/corefx
 internal void Reference(LabelScopeInfo block)
 {
     _references.Add(block);
     if (_definitions.Count > 0)
     {
         ValidateJump(block);
     }
 }
コード例 #3
0
 internal void Reference(LabelScopeInfo block)
 {
     _references.Add(block);
     if (_definitions.Count > 0)
     {
         ValidateJump(block);
     }
 }
コード例 #4
0
        private void ValidateJump(LabelScopeInfo reference)
        {
            this._opCode = this._canReturn ? OpCodes.Ret : OpCodes.Br;
            for (LabelScopeInfo info = reference; info != null; info = info.Parent)
            {
                if (this._definitions.Contains(info))
                {
                    return;
                }
                if ((info.Kind == LabelScopeKind.Finally) || (info.Kind == LabelScopeKind.Filter))
                {
                    break;
                }
                if ((info.Kind == LabelScopeKind.Try) || (info.Kind == LabelScopeKind.Catch))
                {
                    this._opCode = OpCodes.Leave;
                }
            }
            this._acrossBlockJump = true;
            if ((this._node != null) && (this._node.Type != typeof(void)))
            {
                throw System.Linq.Expressions.Error.NonLocalJumpWithValue(this._node.Name);
            }
            if (this._definitions.Count > 1)
            {
                throw System.Linq.Expressions.Error.AmbiguousJump(this._node.Name);
            }
            LabelScopeInfo first = this._definitions.First <LabelScopeInfo>();
            LabelScopeInfo info3 = Helpers.CommonNode <LabelScopeInfo>(first, reference, b => b.Parent);

            this._opCode = this._canReturn ? OpCodes.Ret : OpCodes.Br;
            for (LabelScopeInfo info4 = reference; info4 != info3; info4 = info4.Parent)
            {
                if (info4.Kind == LabelScopeKind.Finally)
                {
                    throw System.Linq.Expressions.Error.ControlCannotLeaveFinally();
                }
                if (info4.Kind == LabelScopeKind.Filter)
                {
                    throw System.Linq.Expressions.Error.ControlCannotLeaveFilterTest();
                }
                if ((info4.Kind == LabelScopeKind.Try) || (info4.Kind == LabelScopeKind.Catch))
                {
                    this._opCode = OpCodes.Leave;
                }
            }
            for (LabelScopeInfo info5 = first; info5 != info3; info5 = info5.Parent)
            {
                if (!info5.CanJumpInto)
                {
                    if (info5.Kind == LabelScopeKind.Expression)
                    {
                        throw System.Linq.Expressions.Error.ControlCannotEnterExpression();
                    }
                    throw System.Linq.Expressions.Error.ControlCannotEnterTry();
                }
            }
        }
コード例 #5
0
 private void CheckTry()
 {
     // Try inside a filter is not verifiable
     for (LabelScopeInfo j = _labelBlock; j != null; j = j.Parent)
     {
         if (j.Kind == LabelScopeKind.Filter)
         {
             throw Error.TryNotAllowedInFilter();
         }
     }
 }
コード例 #6
0
 private static void CheckTry(LabelScopeInfo labelBlock)
 {
     // Try inside a filter is not verifiable
     foreach (var j in SequenceHelper.ExploreSequenceUntilNull(labelBlock, found => found.Parent))
     {
         if (j.Kind == LabelScopeKind.Filter)
         {
             throw new InvalidOperationException("Try expression is not allowed inside a filter body.");
         }
     }
 }
コード例 #7
0
        private void EmitExpressionAsVoid(Expression node, CompilationFlags flags = CompilationFlags.EmitAsNoTail)
        {
            var labelScopeChangeInfo = GetLabelScopeChangeInfo(true, _labelBlock, node);

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = new LabelScopeInfo(labelScopeChangeInfo.Value.parent, labelScopeChangeInfo.Value.kind);
                DefineBlockLabels(labelScopeChangeInfo.Value.nodes);
            }

            switch (node.NodeType)
            {
            case ExpressionType.Assign:
                EmitAssign((AssignBinaryExpression)node, CompilationFlags.EmitAsVoidType);
                break;

            case ExpressionType.Block:
                Emit((BlockExpression)node, UpdateEmitAsTypeFlag(flags, CompilationFlags.EmitAsVoidType));
                break;

            case ExpressionType.Throw:
                EmitThrow((UnaryExpression)node, CompilationFlags.EmitAsVoidType);
                break;

            case ExpressionType.Goto:
                EmitGotoExpression(node, UpdateEmitAsTypeFlag(flags, CompilationFlags.EmitAsVoidType));
                break;

            case ExpressionType.Constant:
            case ExpressionType.Default:
            case ExpressionType.Parameter:
                // no-op
                break;

            default:
                if (node.Type == typeof(void))
                {
                    EmitExpression(node, UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitNoExpressionStart));
                }
                else
                {
                    EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
                    IL.Emit(OpCodes.Pop);
                }

                break;
            }

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = labelScopeChangeInfo.Value.parent;
            }
        }
コード例 #8
0
        // We don't want "ref" parameters to modify values of expressions
        // except where it would in IL: locals, args, fields, and array elements
        // (Unbox is an exception, it's intended to emit a ref to the original
        // boxed value)
        private void EmitAddress(Expression node, Type type, CompilationFlags flags = CompilationFlags.EmitExpressionStart)
        {
            var emitStart            = (flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart;
            var labelScopeChangeInfo = GetLabelScopeChangeInfo(emitStart, _labelBlock, node);

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = new LabelScopeInfo(labelScopeChangeInfo.Value.parent, labelScopeChangeInfo.Value.kind);
                DefineBlockLabels(labelScopeChangeInfo.Value.nodes);
            }

            switch (node.NodeType)
            {
            default:
                EmitExpressionAddress(node, type);
                break;

            case ExpressionType.ArrayIndex:
                AddressOf((BinaryExpression)node, type);
                break;

            case ExpressionType.Parameter:
                AddressOf((ParameterExpression)node, type);
                break;

            case ExpressionType.MemberAccess:
                AddressOf((MemberExpression)node, type);
                break;

            case ExpressionType.Unbox:
                AddressOf((UnaryExpression)node, type);
                break;

            case ExpressionType.Call:
                AddressOf((MethodCallExpression)node, type);
                break;

            case ExpressionType.Index:
                AddressOf((IndexExpression)node, type);
                break;
            }

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = labelScopeChangeInfo.Value.parent;
            }
        }
コード例 #9
0
 private void CheckRethrow()
 {
     // Rethrow is only valid inside a catch.
     for (LabelScopeInfo j = _labelBlock; j != null; j = j.Parent)
     {
         if (j.Kind == LabelScopeKind.Catch)
         {
             return;
         }
         else if (j.Kind == LabelScopeKind.Finally)
         {
             // Rethrow from inside finally is not verifiable
             break;
         }
     }
     throw Error.RethrowRequiresCatch();
 }
コード例 #10
0
        private void EmitLoopExpression(Expression expr)
        {
            var node = (LoopExpression)expr;

            var parent = _labelBlock;

            _labelBlock = new LabelScopeInfo(parent, LabelScopeKind.Statement);

            var breakTarget    = DefineLabel(node.BreakLabel);
            var continueTarget = DefineLabel(node.ContinueLabel);

            continueTarget.MarkWithEmptyStack();
            EmitExpressionAsVoid(node.Body);

            _labelBlock = parent;

            breakTarget.MarkWithEmptyStack();
        }
コード例 #11
0
        private static void CheckRethrow(LabelScopeInfo labelBlock)
        {
            // Rethrow is only valid inside a catch.
            foreach (var j in SequenceHelper.ExploreSequenceUntilNull(labelBlock, found => found.Parent))
            {
                if (j.Kind == LabelScopeKind.Catch)
                {
                    return;
                }

                if (j.Kind == LabelScopeKind.Finally)
                {
                    // Rethrow from inside finally is not verifiable
                    break;
                }
            }

            throw new InvalidOperationException("Rethrow statement is valid only inside a Catch block.");
        }
コード例 #12
0
        private void EmitExpressionAndBranch(bool branchValue, Expression node, Label label)
        {
            Debug.Assert(node.Type == typeof(bool));
            var labelScopeChangeInfo = GetLabelScopeChangeInfo(true, _labelBlock, node);

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = new LabelScopeInfo(labelScopeChangeInfo.Value.parent, labelScopeChangeInfo.Value.kind);
                DefineBlockLabels(labelScopeChangeInfo.Value.nodes);
            }

            switch (node.NodeType)
            {
            case ExpressionType.Not:
                EmitBranchNot(branchValue, (UnaryExpression)node, label);
                break;

            case ExpressionType.AndAlso:
            case ExpressionType.OrElse:
                EmitBranchLogical(branchValue, (BinaryExpression)node, label);
                break;

            case ExpressionType.Block:
                EmitBranchBlock(branchValue, (BlockExpression)node, label);
                break;

            case ExpressionType.Equal:
            case ExpressionType.NotEqual:
                EmitBranchComparison(branchValue, (BinaryExpression)node, label);
                break;

            default:
                EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
                EmitBranchOp(branchValue, label);
                break;
            }

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = labelScopeChangeInfo.Value.parent;
            }
        }
コード例 #13
0
        // Emits the address of the expression, returning the write back if necessary
        //
        // For properties, we want to write back into the property if it's
        // passed byref.
        private WriteBack?EmitAddressWriteBack(Expression node, Type type)
        {
            var labelScopeChangeInfo = GetLabelScopeChangeInfo(true, _labelBlock, node);

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = new LabelScopeInfo(labelScopeChangeInfo.Value.parent, labelScopeChangeInfo.Value.kind);
                DefineBlockLabels(labelScopeChangeInfo.Value.nodes);
            }

            WriteBack?result = null;

            if (TypeUtils.AreEquivalent(type, node.Type))
            {
                switch (node.NodeType)
                {
                case ExpressionType.MemberAccess:
                    result = AddressOfWriteBack((MemberExpression)node);
                    break;

                case ExpressionType.Index:
                    result = AddressOfWriteBack((IndexExpression)node);
                    break;

                default:
                    break;
                }
            }

            if (result == null)
            {
                EmitAddress(node, type, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
            }

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = labelScopeChangeInfo.Value.parent;
            }

            return(result);
        }
コード例 #14
0
        private void EmitCatchStart(CatchBlock cb)
        {
            if (cb.Filter == null)
            {
                EmitSaveExceptionOrPop(cb);
                return;
            }

            // emit filter block. Filter blocks are untyped so we need to do
            // the type check ourselves.
            var endFilter = IL.DefineLabel();
            var rightType = IL.DefineLabel();

            // skip if it's not our exception type, but save
            // the exception if it is so it's available to the
            // filter
            IL.Emit(OpCodes.Isinst, cb.Test);
            IL.Emit(OpCodes.Dup);
            IL.Emit(OpCodes.Brtrue, rightType);
            IL.Emit(OpCodes.Pop);
            IL.Emit(OpCodes.Ldc_I4_0);
            IL.Emit(OpCodes.Br, endFilter);

            // it's our type, save it and emit the filter.
            IL.MarkLabel(rightType);
            EmitSaveExceptionOrPop(cb);

            var parent = _labelBlock;

            _labelBlock = new LabelScopeInfo(parent, LabelScopeKind.Filter);

            EmitExpression(cb.Filter);

            _labelBlock = parent;

            // begin the catch, clear the exception, we've
            // already saved it
            IL.MarkLabel(endFilter);
            IL.BeginCatchBlock(null);
            IL.Emit(OpCodes.Pop);
        }
コード例 #15
0
        // Returns true if the label was successfully defined
        // or false if the label is now ambiguous
        internal void Define(LabelScopeInfo block)
        {
            // Prevent the label from being shadowed, which enforces cleaner
            // trees. Also we depend on this for simplicity (keeping only one
            // active IL Label per LabelInfo)
            foreach (var j in SequenceHelper.ExploreSequenceUntilNull(block, found => found.Parent))
            {
                if (j.ContainsTarget(_node !))
                {
                    throw new InvalidOperationException($"Cannot redefine label '{_node!.Name}' in an inner block.");
                }
            }

            _definitions.Add(block);
            block.AddLabelInfo(_node !, this);

            // Once defined, validate all jumps
            if (_definitions.Count == 1)
            {
                foreach (var r in _references)
                {
                    ValidateJump(r);
                }
            }
            else
            {
                // Was just redefined, if we had any across block jumps, they're
                // now invalid
                if (_acrossBlockJump)
                {
                    throw new InvalidOperationException($"Cannot jump to ambiguous label '{_node?.Name}'.");
                }

                // For local jumps, we need a new IL label
                // This is okay because:
                //   1. no across block jumps have been made or will be made
                //   2. we don't allow the label to be shadowed
                _labelDefined = false;
            }
        }
コード例 #16
0
        // Returns true if the label was successfully defined
        // or false if the label is now ambiguous
        internal void Define(LabelScopeInfo block)
        {
            // Prevent the label from being shadowed, which enforces cleaner
            // trees. Also we depend on this for simplicity (keeping only one
            // active IL Label per LabelInfo)
            for (LabelScopeInfo j = block; j != null; j = j.Parent)
            {
                if (j.ContainsTarget(_node))
                {
                    throw Error.LabelTargetAlreadyDefined(_node.Name);
                }
            }

            _definitions.Add(block);
            block.AddLabelInfo(_node, this);

            // Once defined, validate all jumps
            if (_definitions.Count == 1)
            {
                foreach (LabelScopeInfo r in _references)
                {
                    ValidateJump(r);
                }
            }
            else
            {
                // Was just redefined, if we had any across block jumps, they're
                // now invalid
                if (_acrossBlockJump)
                {
                    throw Error.AmbiguousJump(_node.Name);
                }
                // For local jumps, we need a new IL label
                // This is okay because:
                //   1. no across block jumps have been made or will be made
                //   2. we don't allow the label to be shadowed
                _labelDefined = false;
            }
        }
コード例 #17
0
        private static (LabelScopeInfo parent, LabelScopeKind kind, IList <Expression>?nodes)? GetLabelScopeChangeInfo(bool emitStart, LabelScopeInfo labelBlock, Expression node)
        {
            if (!emitStart)
            {
                return(null);
            }

            // Anything that is "statement-like" -- e.g. has no associated
            // stack state can be jumped into, with the exception of try-blocks
            // We indicate this by a "Block"
            //
            // Otherwise, we push an "Expression" to indicate that it can't be
            // jumped into
            switch (node.NodeType)
            {
            default:
                if (labelBlock.Kind == LabelScopeKind.Expression)
                {
                    return(null);
                }

                return(labelBlock, LabelScopeKind.Expression, null);

            case ExpressionType.Label:
                // LabelExpression is a bit special, if it's directly in a
                // block it becomes associate with the block's scope. Same
                // thing if it's in a switch case body.
                if (labelBlock.Kind != LabelScopeKind.Block)
                {
                    return(labelBlock, LabelScopeKind.Statement, null);
                }

                var label = ((LabelExpression)node).Target;
                if (labelBlock.ContainsTarget(label))
                {
                    return(null);
                }

                if (labelBlock.Parent?.Kind == LabelScopeKind.Switch && labelBlock.Parent.ContainsTarget(label))
                {
                    return(null);
                }

                return(labelBlock, LabelScopeKind.Statement, null);

            case ExpressionType.Block:
                if (node is SpilledExpressionBlock)
                {
                    // treat it as an expression
                    goto default;
                }

                return(labelBlock.Parent?.Kind != LabelScopeKind.Switch
                        ? (labelBlock, LabelScopeKind.Block, new[] { node })
                        : (labelBlock, LabelScopeKind.Block, null));

            case ExpressionType.Switch:
                var nodes   = new List <Expression>();
                var @switch = (SwitchExpression)node;
                foreach (var c in @switch.Cases)
                {
                    nodes.Add(c.Body);
                }

                if (@switch.DefaultBody != null)
                {
                    nodes.Add(@switch.DefaultBody);
                }

                return(labelBlock, LabelScopeKind.Switch, nodes);

            // Remove this when Convert(Void) goes away.
            case ExpressionType.Convert:
                if (node.Type != typeof(void))
                {
                    // treat it as an expression
                    goto default;
                }

                return(labelBlock, LabelScopeKind.Statement, null);

            case ExpressionType.Conditional:
            case ExpressionType.Loop:
            case ExpressionType.Goto:
                return(labelBlock, LabelScopeKind.Statement, null);
            }
        }
コード例 #18
0
 private void PushLabelBlock(LabelScopeKind type)
 {
     _labelBlock = new LabelScopeInfo(_labelBlock, type);
 }
コード例 #19
0
ファイル: LabelInfo.cs プロジェクト: octavioh/ironruby
        // Returns true if the label was successfully defined
        // or false if the label is now ambiguous
        internal void Define(LabelScopeInfo block) {
            // Prevent the label from being shadowed, which enforces cleaner
            // trees. Also we depend on this for simplicity (keeping only one
            // active IL Label per LabelInfo)
            for (LabelScopeInfo j = block; j != null; j = j.Parent) {
                if (j.ContainsTarget(_node)) {
                    throw Error.LabelTargetAlreadyDefined(_node.Name);
                }
            }

            _definitions.Add(block);
            block.AddLabelInfo(_node, this);

            // Once defined, validate all jumps
            if (_definitions.Count == 1) {
                foreach (var r in _references) {
                    ValidateJump(r);
                }
            } else {
                // Was just redefined, if we had any across block jumps, they're
                // now invalid
                if (_acrossBlockJump) {
                    throw Error.AmbiguousJump(_node.Name);
                }
                // For local jumps, we need a new IL label
                // This is okay because:
                //   1. no across block jumps have been made or will be made
                //   2. we don't allow the label to be shadowed
                _labelDefined = false;
            }
        }
コード例 #20
0
ファイル: LabelInfo.cs プロジェクト: octavioh/ironruby
 internal LabelScopeInfo(LabelScopeInfo parent, LabelScopeKind kind) {
     Parent = parent;
     Kind = kind;
 }
コード例 #21
0
ファイル: LabelInfo.cs プロジェクト: octavioh/ironruby
        private void ValidateJump(LabelScopeInfo reference) {
            // Assume we can do a ret/branch
            _opCode = _canReturn ? OpCodes.Ret : OpCodes.Br;

            // look for a simple jump out
            for (LabelScopeInfo j = reference; j != null; j = j.Parent) {
                if (_definitions.Contains(j)) {
                    // found it, jump is valid!
                    return;
                }
                if (j.Kind == LabelScopeKind.Finally ||
                    j.Kind == LabelScopeKind.Filter) {
                    break;
                }
                if (j.Kind == LabelScopeKind.Try ||
                    j.Kind == LabelScopeKind.Catch) {
                    _opCode = OpCodes.Leave;
                }
            }

            _acrossBlockJump = true;
            if (_definitions.Count > 1) {
                throw Error.AmbiguousJump(_node.Name);
            }

            // We didn't find an outward jump. Look for a jump across blocks
            LabelScopeInfo def = _definitions.First();
            LabelScopeInfo common = Helpers.CommonNode(def, reference, b => b.Parent);

            // Assume we can do a ret/branch
            _opCode = _canReturn ? OpCodes.Ret : OpCodes.Br;

            // Validate that we aren't jumping across a finally
            for (LabelScopeInfo j = reference; j != common; j = j.Parent) {
                if (j.Kind == LabelScopeKind.Finally) {
                    throw Error.ControlCannotLeaveFinally();
                }
                if (j.Kind == LabelScopeKind.Filter) {
                    throw Error.ControlCannotLeaveFilterTest();
                }
                if (j.Kind == LabelScopeKind.Try ||
                    j.Kind == LabelScopeKind.Catch) {
                    _opCode = OpCodes.Leave;
                }
            }

            // Valdiate that we aren't jumping into a catch or an expression
            for (LabelScopeInfo j = def; j != common; j = j.Parent) {
                if (!j.CanJumpInto) {
                    if (j.Kind == LabelScopeKind.Expression) {
                        throw Error.ControlCannotEnterExpression();
                    } else {
                        throw Error.ControlCannotEnterTry();
                    }
                }
            }
        }
コード例 #22
0
 private void PushLabelBlock(LabelScopeKind type)
 {
     _labelBlock = new LabelScopeInfo(_labelBlock, type);
 }
コード例 #23
0
 internal LabelScopeInfo(LabelScopeInfo parent, LabelScopeKind kind)
 {
     this.Parent = parent;
     this.Kind = kind;
 }
コード例 #24
0
 internal LabelScopeInfo(LabelScopeInfo parent, LabelScopeKind kind)
 {
     Parent = parent;
     Kind   = kind;
 }
コード例 #25
0
 internal LabelScopeInfo(LabelScopeInfo parent, LabelScopeKind kind)
 {
     this.Parent = parent;
     this.Kind   = kind;
 }
コード例 #26
0
        private void ValidateJump(LabelScopeInfo reference)
        {
            // Assume we can do a ret/branch
            _opCode = CanReturn ? OpCodes.Ret : OpCodes.Br;

            // look for a simple jump out
            foreach (var j in SequenceHelper.ExploreSequenceUntilNull(reference, found => found.Parent))
            {
                if (_definitions.Contains(j))
                {
                    // found it, jump is valid!
                    return;
                }

                if (j.Kind == LabelScopeKind.Finally || j.Kind == LabelScopeKind.Filter)
                {
                    break;
                }

                if (j.Kind == LabelScopeKind.Try || j.Kind == LabelScopeKind.Catch)
                {
                    _opCode = OpCodes.Leave;
                }
            }

            _acrossBlockJump = true;

            if (_node != null && _node.Type != typeof(void))
            {
                throw new InvalidOperationException($"Cannot jump to non-local label '{_node.Name}' with a value. Only jumps to labels defined in outer blocks can pass values.");
            }

            if (_definitions.Count > 1)
            {
                throw new InvalidOperationException($"Cannot jump to ambiguous label '{_node?.Name}'.");
            }

            // We didn't find an outward jump. Look for a jump across blocks
            var def    = _definitions.First();
            var common = SequenceHelper.CommonNode(def, reference, b => b.Parent);

            // Assume we can do a ret/branch
            _opCode = CanReturn ? OpCodes.Ret : OpCodes.Br;

            // Validate that we aren't jumping across a finally
            foreach (var j in SequenceHelper.ExploreSequenceUntilNull(reference, common, found => found.Parent !))
            {
                switch (j.Kind)
                {
                case LabelScopeKind.Finally:
                    throw new InvalidOperationException("Control cannot leave a finally block.");

                case LabelScopeKind.Filter:
                    throw new InvalidOperationException("Control cannot leave a filter test.");

                case LabelScopeKind.Try:
                case LabelScopeKind.Catch:
                    _opCode = OpCodes.Leave;
                    break;

                default:
                    break;
                }
            }

            // Validate that we aren't jumping into a catch or an expression
            foreach (var j in SequenceHelper.ExploreSequenceUntilNull(def, found => found.Parent))
            {
                if (j.CanJumpInto)
                {
                    continue;
                }

                if (j.Kind == LabelScopeKind.Expression)
                {
                    throw new InvalidOperationException("Control cannot enter an expression--only statements can be jumped into.");
                }

                throw new InvalidOperationException("Control cannot enter a try block.");
            }
        }
コード例 #27
0
        private void ValidateJump(LabelScopeInfo reference)
        {
            // Assume we can do a ret/branch
            _opCode = _canReturn ? OpCodes.Ret : OpCodes.Br;

            // look for a simple jump out
            for (LabelScopeInfo j = reference; j != null; j = j.Parent)
            {
                if (_definitions.Contains(j))
                {
                    // found it, jump is valid!
                    return;
                }
                if (j.Kind == LabelScopeKind.Finally ||
                    j.Kind == LabelScopeKind.Filter)
                {
                    break;
                }
                if (j.Kind == LabelScopeKind.Try ||
                    j.Kind == LabelScopeKind.Catch)
                {
                    _opCode = OpCodes.Leave;
                }
            }

            _acrossBlockJump = true;
            if (_node != null && _node.Type != typeof(void))
            {
                throw Error.NonLocalJumpWithValue(_node.Name);
            }

            if (_definitions.Count > 1)
            {
                throw Error.AmbiguousJump(_node.Name);
            }

            // We didn't find an outward jump. Look for a jump across blocks
            LabelScopeInfo def    = _definitions.First();
            LabelScopeInfo common = Helpers.CommonNode(def, reference, b => b.Parent);

            // Assume we can do a ret/branch
            _opCode = _canReturn ? OpCodes.Ret : OpCodes.Br;

            // Validate that we aren't jumping across a finally
            for (LabelScopeInfo j = reference; j != common; j = j.Parent)
            {
                if (j.Kind == LabelScopeKind.Finally)
                {
                    throw Error.ControlCannotLeaveFinally();
                }
                if (j.Kind == LabelScopeKind.Filter)
                {
                    throw Error.ControlCannotLeaveFilterTest();
                }
                if (j.Kind == LabelScopeKind.Try ||
                    j.Kind == LabelScopeKind.Catch)
                {
                    _opCode = OpCodes.Leave;
                }
            }

            // Validate that we aren't jumping into a catch or an expression
            for (LabelScopeInfo j = def; j != common; j = j.Parent)
            {
                if (!j.CanJumpInto)
                {
                    if (j.Kind == LabelScopeKind.Expression)
                    {
                        throw Error.ControlCannotEnterExpression();
                    }
                    else
                    {
                        throw Error.ControlCannotEnterTry();
                    }
                }
            }
        }
コード例 #28
0
        private void EmitTryExpression(Expression expr)
        {
            var node = (TryExpression)expr;

            CheckTry(_labelBlock);

            //******************************************************************
            // 1. ENTERING TRY
            //******************************************************************

            var parent = _labelBlock;

            _labelBlock = new LabelScopeInfo(parent, LabelScopeKind.Try);

            IL.BeginExceptionBlock();
            //******************************************************************
            // 2. Emit the try statement body
            //******************************************************************
            EmitExpression(node.Body);
            var          tryType = node.Type;
            LocalBuilder?value   = null;

            if (tryType != typeof(void))
            {
                //store the value of the try body
                value = GetLocal(tryType);
                IL.Emit(OpCodes.Stloc, value);
            }
            //******************************************************************
            // 3. Emit the catch blocks
            //******************************************************************
            foreach (var cb in node.Handlers)
            {
                var tmpParent = _labelBlock;
                _labelBlock = new LabelScopeInfo(tmpParent, LabelScopeKind.Catch);

                // Begin the strongly typed exception block
                if (cb.Filter == null)
                {
                    IL.BeginCatchBlock(cb.Test);
                }
                else
                {
                    IL.BeginExceptFilterBlock();
                }

                var innerScopeInfo = GetInnerScope(node, _scope);
                if (innerScopeInfo.HasValue)
                {
                    _scope = innerScopeInfo.Value.child.Enter(this, innerScopeInfo.Value.parent);
                }

                EmitCatchStart(cb);
                //
                // Emit the catch block body
                //
                EmitExpression(cb.Body);
                if (tryType != typeof(void))
                {
                    //store the value of the catch block body
                    // ReSharper disable once AssignNullToNotNullAttribute
                    IL.Emit(OpCodes.Stloc, value);
                }

                if (innerScopeInfo.HasValue)
                {
                    innerScopeInfo.Value.child.Exit();
                    _scope = innerScopeInfo.Value.parent;
                }

                _labelBlock = tmpParent;
            }
            //******************************************************************
            // 4. Emit the finally block
            //******************************************************************
            if (node.Finally != null || node.Fault != null)
            {
                var tmpParent = _labelBlock;
                _labelBlock = new LabelScopeInfo(tmpParent, LabelScopeKind.Finally);

                if (node.Finally != null)
                {
                    IL.BeginFinallyBlock();
                }
                else
                {
                    IL.BeginFaultBlock();
                }
                // Emit the body
                EmitExpressionAsVoid(node.Finally ?? node.Fault !);
                IL.EndExceptionBlock();

                _labelBlock = tmpParent;
            }
            else
            {
                IL.EndExceptionBlock();
            }
            if (value != null)
            {
                // ReSharper disable once AssignNullToNotNullAttribute
                IL.Emit(OpCodes.Ldloc, value);
                FreeLocal(value);
            }

            _labelBlock = parent;
        }