Exemplo n.º 1
0
            public override void CloseScope(ILBuilder builder)
            {
                Debug.Assert(_handlers.Count > 1);

                // Fix up the NextExceptionHandler reference of each leader block.
                var tryScope      = _handlers[0];
                var previousBlock = tryScope.LeaderBlock;

                for (int i = 1; i < _handlers.Count; i++)
                {
                    var handlerScope = _handlers[i];
                    var nextBlock    = handlerScope.LeaderBlock;

                    previousBlock.NextExceptionHandler = nextBlock;
                    previousBlock = nextBlock;
                }

                // Generate label for try/catch "leave" target.
                builder.MarkLabel(_endLabel);

                // hide the following code, since it could be reached through the label above.
                builder.DefineHiddenSequencePoint();

                Debug.Assert(builder._currentBlock == builder._labelInfos[_endLabel].bb);

                if (_handlers[1].Type == ScopeType.Finally)
                {
                    // Generate "nop" branch to itself. If this block is unreachable
                    // (because the finally block does not complete), the "nop" will be
                    // replaced by Br_s. On the other hand, if this block is reachable,
                    // the "nop" will be skipped so any "leave" instructions jumping
                    // to this block will jump to the next instead.
                    builder.EmitBranch(ILOpCode.Nop, _endLabel);

                    _handlers[1].SetBlockedByFinallyDestination(_endLabel);
                }
            }
Exemplo n.º 2
0
        internal void EmitJumpTable()
        {
            //  For emitting the switch statement (integral governing type) jump table with a non-constant
            //  switch expression, we can use a naive approach and generate a single big MSIL switch instruction
            //  with all the case labels and fall through label. However, this approach can be optimized
            //  to improve both the code size and speed using the following optimization steps:

            //  a)	Sort the switch case labels based on their constant values.

            //  b)	Divide the sorted switch labels into buckets with good enough density (>50%). For example:
            //      switch(..)
            //      {
            //          case 1:
            //          case 100:
            //              break;
            //          case 2:
            //          case 4:
            //              break;
            //          case 200:
            //          case 201:
            //          case 202:
            //              break;
            //      }

            //      can be divided into 3 buckets: (1, 2, 4) (100) (200, 201, 202).
            //      We do this bucketing so that we have reasonable size jump tables for generated switch instructions.

            //  c)	After bucketing, generate code to perform a binary search on these buckets array,
            //      emitting conditional jumps if current bucket sub-array has more than one bucket and
            //      emitting the switch instruction when we are down to a single bucket in the sub-array.


            // (a) Sort switch labels: This was done in the constructor

            Debug.Assert(!_sortedCaseLabels.IsEmpty);
            var sortedCaseLabels = _sortedCaseLabels;

            int endLabelIndex = sortedCaseLabels.Length - 1;
            int startLabelIndex;

            // Check for a label with ConstantValue.Null.
            // Sorting ensures that if we do have one, it will be
            // the first label in the sorted list.
            if (sortedCaseLabels[0].Key != ConstantValue.Null)
            {
                startLabelIndex = 0;
            }
            else
            {
                // Skip null label for emitting switch table header.
                // We should have inserted a conditional branch to 'null' label during rewriting.
                // See LocalRewriter.MakeSwitchStatementWithNullableExpression
                startLabelIndex = 1;
            }

            if (startLabelIndex <= endLabelIndex)
            {
                // We have at least one non-null case label, emit jump table

                // (b) Generate switch buckets
                ImmutableArray <SwitchBucket> switchBuckets = this.GenerateSwitchBuckets(startLabelIndex, endLabelIndex);

                // (c) Emit switch buckets
                this.EmitSwitchBuckets(switchBuckets, 0, switchBuckets.Length - 1);
            }
            else
            {
                _builder.EmitBranch(ILOpCode.Br, _fallThroughLabel);
            }
        }