Example #1
0
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            var             newInnerLocals  = RewriteLocals(node.InnerLocals);
            BoundExpression boundExpression = (BoundExpression)this.Visit(node.BoundExpression);
            ImmutableArray <BoundSwitchSection> switchSections = (ImmutableArray <BoundSwitchSection>) this.VisitList(node.SwitchSections);

            return(node.Update(boundExpression, node.ConstantTargetOpt, newInnerLocals, switchSections, node.BreakLabel, node.StringEquality));
        }
        protected virtual void VisitSwitchStatement(BoundSwitchStatement node)
        {
            VisitExpression(node.Expression);

            foreach (var section in node.Sections)
            {
                VisitSwitchSection(section);
            }
        }
Example #3
0
                public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
                {
                    var oldScope = _currentScope;

                    _currentScope = CreateOrReuseScope(node, node.InnerLocals);
                    var result = base.VisitSwitchStatement(node);

                    _currentScope = oldScope;
                    return(result);
                }
Example #4
0
 public override object VisitSwitchStatement(BoundSwitchStatement node, object arg)
 {
     VisitExpression(node.BoundExpression);
     // TODO: switch cases missing from bound switch node
     // TODO: make sure to take into account the possibility of constant switch expression
     // TODO: take into account the possibility of no switch blocks
     // TODO: give an error when the end of a switch block is reachable (falls through)
     Unimplemented(node, "switch statement");
     return(null);
 }
Example #5
0
        internal void Parse(BoundSwitchStatement boundSwitchStatement)
        {
            if (boundSwitchStatement == null)
            {
                throw new ArgumentNullException();
            }

            var boundCall = boundSwitchStatement.Expression as BoundCall;

            if (boundCall != null && boundCall.ReceiverOpt != null)
            {
                this.isNullableType = boundCall.ReceiverOpt.Type.IsNullableType();
            }

            /*
             * if (boundSwitchStatement.OuterLocals != null)
             * {
             *  AddLocals(boundSwitchStatement.OuterLocals, this.statements);
             * }
             */

            if (boundSwitchStatement.InnerLocals != null)
            {
                AddLocals(boundSwitchStatement.InnerLocals, this.statements);
            }

            this.expression = Deserialize(boundSwitchStatement.Expression) as Expression;
            foreach (var boundSwitchSection in boundSwitchStatement.SwitchSections)
            {
                var switchSection = new SwitchSection();
                switchSection.SwitchType = this.expression.Type;
                switchSection.Parse(boundSwitchSection);
                switchSection.IsNullableType = this.isNullableType;
                this.switchCases.Add(switchSection);
            }

            this.stringEquality = boundSwitchStatement.StringEquality;

            // disable all 'auto' variables
            this.Visit(
                (e) =>
            {
                var assignmentOperator = e as AssignmentOperator;
                if (assignmentOperator != null)
                {
                    var local = assignmentOperator.Left as Local;
                    if (local != null && boundSwitchStatement.InnerLocals.Any(ol => ol.Name == local.Name))
                    {
                        assignmentOperator.TypeDeclaration = false;
                    }
                }
            });
        }
Example #6
0
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            Debug.Assert(EvalStackIsEmpty());
            DeclareLocals(node.InnerLocals, 0);

            // switch needs a byval local or a parameter as a key.
            // if this is already a fitting local, let's keep it that way
            BoundExpression boundExpression = node.BoundExpression;
            if (boundExpression.Kind == BoundKind.Local)
            {
                var localSym = ((BoundLocal)boundExpression).LocalSymbol;
                if (localSym.RefKind == RefKind.None)
                {
                    ShouldNotSchedule(localSym);
                }
            }

            boundExpression = (BoundExpression)this.Visit(boundExpression);

            // expression value is consumed by the switch
            PopEvalStack();

            // implicit control flow
            EnsureOnlyEvalStack();

            // switch sections
            ImmutableArray<BoundSwitchSection> switchSections = this.VisitList(node.SwitchSections);

            // break label
            var breakLabel = node.BreakLabel;
            if (breakLabel != null)
            {
                this.RecordLabel(breakLabel);
            }

            var result = node.Update(boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, breakLabel, node.StringEquality);

            // implicit control flow
            EnsureOnlyEvalStack();

            return result;
        }
Example #7
0
            public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
            {
                var breakLabelClone = GetLabelClone(node.BreakLabel);
                var preambleOpt = (BoundStatement)this.Visit(node.LoweredPreambleOpt);

                // expressions do not contain labels or branches
                BoundExpression boundExpression = node.Expression;
                ImmutableArray<BoundSwitchSection> switchSections = (ImmutableArray<BoundSwitchSection>)this.VisitList(node.SwitchSections);
                return node.Update(preambleOpt, boundExpression, node.ConstantTargetOpt, node.InnerLocals, node.InnerLocalFunctions, switchSections, breakLabelClone, node.StringEquality);
            }
Example #8
0
        private void EmitStringSwitchJumpTable(
            BoundSwitchStatement switchStatement,
            KeyValuePair<ConstantValue, object>[] switchCaseLabels,
            LabelSymbol fallThroughLabel,
            LocalOrParameter key,
            SyntaxNode syntaxNode)
        {
            LocalDefinition keyHash = null;

            // Condition is necessary, but not sufficient (e.g. might be missing a special or well-known member).
            if (SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch(_module, switchCaseLabels.Length))
            {
                Debug.Assert(_module.SupportsPrivateImplClass);

                var privateImplClass = _module.GetPrivateImplClass(syntaxNode, _diagnostics);
                Cci.IReference stringHashMethodRef = privateImplClass.GetMethod(PrivateImplementationDetails.SynthesizedStringHashFunctionName);

                // Heuristics and well-known member availability determine the existence
                // of this helper.  Rather than reproduce that (language-specific) logic here,
                // we simply check for the information we really want - whether the helper is
                // available.
                if (stringHashMethodRef != null)
                {
                    // static uint ComputeStringHash(string s)
                    // pop 1 (s)
                    // push 1 (uint return value)
                    // stackAdjustment = (pushCount - popCount) = 0

                    _builder.EmitLoad(key);
                    _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0);
                    _builder.EmitToken(stringHashMethodRef, syntaxNode, _diagnostics);

                    var UInt32Type = _module.Compilation.GetSpecialType(SpecialType.System_UInt32);
                    keyHash = AllocateTemp(UInt32Type, syntaxNode);

                    _builder.EmitLocalStore(keyHash);
                }
            }

            Cci.IReference stringEqualityMethodRef = _module.Translate(switchStatement.StringEquality, syntaxNode, _diagnostics);

            Cci.IMethodReference stringLengthRef = null;
            var stringLengthMethod = _module.Compilation.GetSpecialTypeMember(SpecialMember.System_String__Length) as MethodSymbol;
            if (stringLengthMethod != null && !stringLengthMethod.HasUseSiteError)
            {
                stringLengthRef = _module.Translate(stringLengthMethod, syntaxNode, _diagnostics);
            }

            SwitchStringJumpTableEmitter.EmitStringCompareAndBranch emitStringCondBranchDelegate =
                (keyArg, stringConstant, targetLabel) =>
                {
                    if (stringConstant == ConstantValue.Null)
                    {
                        // if (key == null)
                        //      goto targetLabel
                        _builder.EmitLoad(keyArg);
                        _builder.EmitBranch(ILOpCode.Brfalse, targetLabel, ILOpCode.Brtrue);
                    }
                    else if (stringConstant.StringValue.Length == 0 && stringLengthRef != null)
                    {
                        // if (key != null && key.Length == 0)
                        //      goto targetLabel

                        object skipToNext = new object();
                        _builder.EmitLoad(keyArg);
                        _builder.EmitBranch(ILOpCode.Brfalse, skipToNext, ILOpCode.Brtrue);

                        _builder.EmitLoad(keyArg);
                        // Stack: key --> length
                        _builder.EmitOpCode(ILOpCode.Call, 0);
                        var diag = DiagnosticBag.GetInstance();
                        _builder.EmitToken(stringLengthRef, null, diag);
                        Debug.Assert(diag.IsEmptyWithoutResolution);
                        diag.Free();

                        _builder.EmitBranch(ILOpCode.Brfalse, targetLabel, ILOpCode.Brtrue);
                        _builder.MarkLabel(skipToNext);
                    }
                    else
                    {
                        this.EmitStringCompareAndBranch(key, syntaxNode, stringConstant, targetLabel, stringEqualityMethodRef);
                    }
                };

            _builder.EmitStringSwitchJumpTable(
                caseLabels: switchCaseLabels,
                fallThroughLabel: fallThroughLabel,
                key: key,
                keyHash: keyHash,
                emitStringCondBranchDelegate: emitStringCondBranchDelegate,
                computeStringHashcodeDelegate: SynthesizedStringSwitchHashMethod.ComputeStringHash);

            if (keyHash != null)
            {
                FreeTemp(keyHash);
            }
        }
Example #9
0
        private void EmitSwitchHeader(
            BoundSwitchStatement switchStatement,
            BoundExpression expression,
            KeyValuePair<ConstantValue, object>[] switchCaseLabels,
            LabelSymbol fallThroughLabel)
        {
            Debug.Assert(expression.ConstantValue == null);
            Debug.Assert((object)expression.Type != null &&
                expression.Type.IsValidV6SwitchGoverningType());
            Debug.Assert(switchCaseLabels.Length > 0);

            Debug.Assert(switchCaseLabels != null);

            LocalDefinition temp = null;
            LocalOrParameter key;
            BoundSequence sequence = null;

            if (expression.Kind == BoundKind.Sequence)
            {
                sequence = (BoundSequence)expression;
                DefineLocals(sequence);
                EmitSideEffects(sequence);
                expression = sequence.Value;
            }

            if (expression.Kind == BoundKind.SequencePointExpression)
            {
                var sequencePointExpression = (BoundSequencePointExpression)expression;
                EmitSequencePoint(sequencePointExpression);
                expression = sequencePointExpression.Expression;
            }

            switch (expression.Kind)
            {
                case BoundKind.Local:
                    var local = ((BoundLocal)expression).LocalSymbol;
                    if (local.RefKind == RefKind.None && !IsStackLocal(local))
                    {
                        key = this.GetLocal(local);
                        break;
                    }
                    goto default;

                case BoundKind.Parameter:
                    var parameter = (BoundParameter)expression;
                    if (parameter.ParameterSymbol.RefKind == RefKind.None)
                    {
                        key = ParameterSlot(parameter);
                        break;
                    }
                    goto default;

                default:
                    EmitExpression(expression, true);
                    temp = AllocateTemp(expression.Type, expression.Syntax);
                    _builder.EmitLocalStore(temp);
                    key = temp;
                    break;
            }

            // Emit switch jump table            
            if (expression.Type.SpecialType != SpecialType.System_String)
            {
                _builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, key, expression.Type.EnumUnderlyingType().PrimitiveTypeCode);
            }
            else
            {
                this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, key, expression.Syntax);
            }

            if (temp != null)
            {
                FreeTemp(temp);
            }

            if (sequence != null)
            {
                FreeLocals(sequence, doNotRelease: null);
            }
        }
Example #10
0
        private void EmitSwitchStatement(BoundSwitchStatement switchStatement)
        {
            var preambleOpt = switchStatement.LoweredPreambleOpt;
            if (preambleOpt != null)
            {
                EmitStatement(preambleOpt);
            }

            // Switch expression must have a valid switch governing type
            Debug.Assert((object)switchStatement.Expression.Type != null);
            Debug.Assert(switchStatement.Expression.Type.IsValidV6SwitchGoverningType());

            // We must have rewritten nullable switch expression into non-nullable constructs.
            Debug.Assert(!switchStatement.Expression.Type.IsNullableType());

            BoundExpression expression = switchStatement.Expression;
            ImmutableArray<BoundSwitchSection> switchSections = switchStatement.SwitchSections;
            GeneratedLabelSymbol breakLabel = switchStatement.BreakLabel;
            LabelSymbol constantTargetOpt = switchStatement.ConstantTargetOpt;

            if ((object)constantTargetOpt != null)
            {
                EmitConstantSwitchHeader(expression, constantTargetOpt);
            }
            else
            {
                // ConstantTargetOpt should be set to breakLabel for empty switch statement
                Debug.Assert(switchStatement.SwitchSections.Any());

                // Get switch case labels (indexed by their constant value) for emitting switch header and jump table
                LabelSymbol fallThroughLabel = breakLabel;
                KeyValuePair<ConstantValue, object>[] switchCaseLabels = GetSwitchCaseLabels(switchSections, ref fallThroughLabel);

                // CONSIDER: EmitSwitchHeader may modify the switchCaseLabels array by sorting it.
                // CONSIDER: Currently, only purpose of creating this switchCaseLabels array is for Emitting the switch header.
                // CONSIDER: If this requirement changes, we may want to pass in ArrayBuilder<KeyValuePair<ConstantValue, object>> instead.

                if (switchCaseLabels.Length == 0)
                {
                    // no case labels
                    EmitExpression(expression, used: false);
                    _builder.EmitBranch(ILOpCode.Br, fallThroughLabel);
                }
                else
                {
                    EmitSwitchHeader(switchStatement, expression, switchCaseLabels, fallThroughLabel);
                }
            }

            EmitSwitchBody(switchStatement.InnerLocals, switchSections, breakLabel, switchStatement.Syntax);
        }
Example #11
0
            public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
            {
                var breakLabelClone = GetLabelClone(node.BreakLabel);

                // expressions do not contain labels or branches
                BoundExpression boundExpression = node.BoundExpression;
                ImmutableArray<BoundSwitchSection> switchSections = (ImmutableArray<BoundSwitchSection>)this.VisitList(node.SwitchSections);
                Debug.Assert(node.OuterLocals.IsEmpty);
                return node.Update(node.OuterLocals, boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, breakLabelClone, node.StringEquality);
            }
Example #12
0
        private void EmitSwitchHeader(
            BoundSwitchStatement switchStatement,
            BoundExpression expression,
            KeyValuePair<ConstantValue, object>[] switchCaseLabels,
            LabelSymbol fallThroughLabel)
        {
            Debug.Assert(expression.ConstantValue == null);
            Debug.Assert((object)expression.Type != null &&
                expression.Type.IsValidSwitchGoverningType());
            Debug.Assert(switchCaseLabels.Length > 0);

            Debug.Assert(switchCaseLabels != null);

            var exprType = expression.Type;
            LocalDefinition temp = null;

            // Emit switch jump table            
            if (expression.Type.SpecialType != SpecialType.System_String)
            {
                if (expression.Kind == BoundKind.Local && ((BoundLocal)expression).LocalSymbol.RefKind == RefKind.None)
                {
                    builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, this.GetLocal((BoundLocal)expression), exprType.EnumUnderlyingType().PrimitiveTypeCode);
                }
                else if (expression.Kind == BoundKind.Parameter && ((BoundParameter)expression).ParameterSymbol.RefKind == RefKind.None)
                {
                    builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, ParameterSlot((BoundParameter)expression), exprType.EnumUnderlyingType().PrimitiveTypeCode);
                }
                else
                {
                    EmitExpression(expression, true);
                    temp = AllocateTemp(exprType, expression.Syntax);
                    builder.EmitLocalStore(temp);

                    builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, temp, exprType.EnumUnderlyingType().PrimitiveTypeCode);
                }
            }
            else
            {
                if (expression.Kind == BoundKind.Local && ((BoundLocal)expression).LocalSymbol.RefKind == RefKind.None)
                {
                    this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, this.GetLocal((BoundLocal)expression), expression.Syntax);
                }
                else
                {
                    EmitExpression(expression, true);
                    temp = AllocateTemp(exprType, expression.Syntax);
                    builder.EmitLocalStore(temp);

                    this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, temp, expression.Syntax);
                }
            }

            if (temp != null)
            {
                FreeTemp(temp);
            }
        }
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     var preambleOpt = (BoundStatement)this.Visit(node.LoweredPreambleOpt);
     var newInnerLocals = RewriteLocals(node.InnerLocals);
     BoundExpression boundExpression = (BoundExpression)this.Visit(node.Expression);
     ImmutableArray<BoundSwitchSection> switchSections = (ImmutableArray<BoundSwitchSection>)this.VisitList(node.SwitchSections);
     return node.Update(preambleOpt, boundExpression, node.ConstantTargetOpt, newInnerLocals, node.InnerLocalFunctions, switchSections, node.BreakLabel, node.StringEquality);
 }
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            Debug.Assert(node.OuterLocals.IsEmpty);
            Debug.Assert(this.evalStack == 0);
            DeclareLocals(node.InnerLocals, 0);

            var origStack = this.evalStack;

            // switch expects that key local stays local
            EnsureOnlyEvalStack();

            BoundExpression boundExpression = (BoundExpression)this.Visit(node.BoundExpression);

            // expression value is consumed by the switch
            this.evalStack = origStack;

            // implicit control flow
            EnsureOnlyEvalStack();

            // switch sections
            ImmutableArray<BoundSwitchSection> switchSections = this.VisitList(node.SwitchSections);

            // break label
            var breakLabel = node.BreakLabel;
            if (breakLabel != null)
            {
                this.RecordLabel(breakLabel);
            }

            var result = node.Update(node.OuterLocals, boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, breakLabel, node.StringEquality);

            // implicit control flow
            EnsureOnlyEvalStack();

            return result;
        }
Example #15
0
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            Debug.Assert(this.evalStack == 0);
            DeclareLocals(node.LocalsOpt, 0);

            var origStack = this.evalStack;

            // switch expects that key local stays local
            EnsureOnlyEvalStack();

            BoundExpression boundExpression = (BoundExpression)this.Visit(node.BoundExpression);

            // expression value is consumed by the switch
            this.evalStack = origStack;

            // implicit control flow
            EnsureOnlyEvalStack();

            ImmutableArray<BoundSwitchSection> switchSections = this.VisitList(node.SwitchSections);
            var result = node.Update(boundExpression, node.ConstantTargetOpt, node.LocalsOpt, switchSections, node.BreakLabel, node.StringEquality);

            // implicit control flow
            EnsureOnlyEvalStack();

            return result;
        }