Exemple #1
0
        /// <summary>
        /// Used to determine if a method body is just a sequence of non-nested blocks. Ignores any PreambleBlocks at the beginning of the body
        /// </summary>
        /// <param name="method">Any method</param>
        /// <returns>method != null &amp;&amp; method.Body != null ==> IsClump(method.Body.Statements) (except for PreambleBlocks)
        /// </returns>
        internal static bool PostNormalizedFormat(Method method)
        {
            if (method == null)
            {
                return(true);
            }
            if (method.Body == null)
            {
                return(true);
            }
            // skip over any PreambleBlocks, they don't need to be in post-normalized format
            int           i  = 0;
            StatementList sl = method.Body.Statements;

            while (i < sl.Count)
            {
                PreambleBlock pb = sl[i] as PreambleBlock;
                if (pb == null)
                {
                    break;
                }
                i++;
            }
            while (i < sl.Count)
            {
                if (!HelperMethods.IsBasicBlock(sl[i] as Block))
                {
                    return(false);
                }
                i++;
            }
            return(true);
        }
        internal static Local ExtractPreamble(Method m, ContractNodes contractNodes, Block contractInitializer,
            out Block postPreamble, ref StackDepthTracker dupStackTracker, bool isVB)
        {
            postPreamble = null;

            if (m == null || m.Body == null || m.Body.Statements == null || !(m.Body.Statements.Count > 0)) return null;
            
            Block firstBlock = m.Body.Statements[0] as Block;
            if (firstBlock == null) return null;
            
            Block preambleBlock = new PreambleBlock(new StatementList(0));

            Local result;
            
            int nextInstructionInFirstBlock = ExtractClosureInitializationAndLocalThis(m, firstBlock, contractNodes,
                contractInitializer, preambleBlock, 0, out result, ref dupStackTracker);

            // Type (2): Base ctor or deferring ctor call

            if (m is InstanceInitializer)
            {
                int i, j;
                bool found;

                // Type (2a): Assignments to fields of class that had initializers

                // Just extract the statements for (2a) as part of what gets extracted for (2b)

                // Type (2b): base or deferring ctor call

                found = SearchClump(m.Body.Statements, 
                    delegate(Statement s)
                    {
                        if (s == null) return false;

                        ExpressionStatement es = s as ExpressionStatement;
                        if (es == null) return false;
                    
                        MethodCall mc = es.Expression as MethodCall;
                        if (mc == null) return false;
                    
                        MemberBinding mb = mc.Callee as MemberBinding;
                        if (mb == null) return false;
                    
                        Method callee = mb.BoundMember as Method;
                    
                        // can't depend on the TargetObject being "this": it could be "pop" if
                        // the arguments to the call had any control flow
                        // e.g., a boolean short-circuit expression or a ternary expression.
                        //if (mb.TargetObject is This && callee is InstanceInitializer) return true;
                        if (callee is InstanceInitializer
                            &&
                            ((callee.DeclaringType == m.DeclaringType || callee.DeclaringType.Template == m.DeclaringType)
                             // deferring ctor call
                             ||
                             (callee.DeclaringType == m.DeclaringType.BaseType ||
                              // base ctor call
                              callee.DeclaringType.Template == m.DeclaringType.BaseType.Template)))
                        {
                            return true;
                        }

                        return false;

                    }, 
                    out i, out j);

                if (found)
                {
                    // for VB constructors and C# constructors with closures, we need to extend the scope to include field initializers

                    Block b = (Block) m.Body.Statements[i];
                    int k = j + 1;
                    Local extraClosureLocal = null;
                    int stackDepth = 0;

                    for (; k < b.Statements.Count; k++)
                    {
                        // skip over auxiliary closure creation
                        if (extraClosureLocal == null && IsClosureCreation(m, b.Statements[k], out extraClosureLocal))
                        {
                            continue;
                        }

                        switch (b.Statements[k].NodeType)
                        {
                            case NodeType.Nop:
                                continue;

                            case NodeType.AssignmentStatement:
                            {
                                AssignmentStatement assgmt = (AssignmentStatement) b.Statements[k];
                                MemberBinding mb = assgmt.Target as MemberBinding;
                                if (mb == null)
                                {
                                    // we might be initializing locals for default values etc
                                    if (stackDepth > 0) continue;
                                    
                                    goto doneWithFieldInits;
                                }

                                if (!(mb.BoundMember is Field))
                                {
                                    // we might be initializing locals for default values etc
                                    if (stackDepth > 0) continue;
                                    goto doneWithFieldInits;
                                }

                                if (mb.TargetObject == null)
                                {
                                    // we might be initializing locals for default values etc
                                    if (stackDepth > 0) continue;
                                    goto doneWithFieldInits;
                                }

                                // there are 2 cases here. Either we are assigning to this.f = ..., which is a field initialization,
                                // or it is initializing the closure field for "this" with this.
                                if (mb.TargetObject.NodeType == NodeType.This)
                                {
                                    // okay field initialization
                                    continue;
                                }

                                if (mb.TargetObject.NodeType == NodeType.Pop)
                                {
                                    // okay field initialization (popping this)
                                    stackDepth--;
                                    continue;
                                }

                                // we might also be initializing the extra closure fields, if the target is the extraClosureLocal.
                                if (mb.TargetObject == extraClosureLocal)
                                {
                                    continue;
                                }

                                if (mb.TargetObject.NodeType == NodeType.Local && assgmt.Source != null &&
                                    assgmt.Source.NodeType == NodeType.This && mb.BoundMember.Name != null &&
                                    (mb.BoundMember.Name.Name.EndsWith("_this") || mb.BoundMember.Name.Name == "$VB$Me"))
                                {
                                    // closure initialization (storing this)
                                    // add it to postPreamble, since it needs to be inserted for duplicate closure object
                                    postPreamble = new Block(new StatementList(1));
                                    postPreamble.Statements.Add((Statement) b.Statements[k].Clone());
                                    continue;
                                }

                                goto doneWithFieldInits;
                            }

                            case NodeType.ExpressionStatement:
                            {
                                ExpressionStatement estmt = (ExpressionStatement) b.Statements[k];
                                if (estmt.Expression != null && estmt.Expression is This)
                                {
                                    // handle special push/pop pattern occurring occasionally
                                    stackDepth++;
                                    continue;
                                }

                                // handle ctor calls on addresses of value types
                                // NOTE: this could be mistakenly the first user statement.
                                MethodCall mc = estmt.Expression as MethodCall;
                                if (mc == null) goto doneWithFieldInits;

                                MemberBinding mb = mc.Callee as MemberBinding;
                                if (mb == null) goto doneWithFieldInits;
                                
                                if (!(mb.BoundMember is InstanceInitializer)) goto doneWithFieldInits;
                                
                                if (!mb.BoundMember.DeclaringType.IsValueType) goto doneWithFieldInits;
                                
                                if (mb.TargetObject.NodeType != NodeType.AddressOf) goto doneWithFieldInits;
                                
                                continue;
                            }

                            default:
                                goto doneWithFieldInits;
                        }
                    }

                    doneWithFieldInits:

                    StatementList sl2 = ExtractClump(m.Body.Statements, 0, 0, i, k - 1);
                    preambleBlock.Statements.Add(new Block(sl2));

                    ExtractVB_ENCCallToPreamble(m.Body.Statements[i] as Block, k, preambleBlock.Statements);
                }
                else
                {
                    // for struct ctors, we may not have a "this" call

                    // for C# constructors with closures, we need to extend the scope

                    Block b = firstBlock;
                    int k = nextInstructionInFirstBlock;
                    Local extraClosureLocal = null;

                    for (; k < b.Statements.Count; k++)
                    {
                        // skip over auxiliary closure creation and initialization
                        if (extraClosureLocal == null && IsClosureCreation(m, b.Statements[k], out extraClosureLocal))
                        {
                            continue;
                        }

                        switch (b.Statements[k].NodeType)
                        {
                            case NodeType.Nop:
                                continue;

                            case NodeType.AssignmentStatement:
                            {
                                AssignmentStatement assgmt = (AssignmentStatement) b.Statements[k];
                                MemberBinding mb = assgmt.Target as MemberBinding;
                                
                                if (mb == null) goto doneWithFieldInits;

                                if (!(mb.BoundMember is Field)) goto doneWithFieldInits;
                                
                                if (mb.TargetObject == null) goto doneWithFieldInits;
                                
                                // we might be initializing the extra closure fields, if the target is the extraClosureLocal.
                                if (mb.TargetObject == extraClosureLocal)
                                {
                                    continue;
                                }

                                goto doneWithFieldInits;
                            }

                            default:
                                goto doneWithFieldInits;
                        }
                    }

                    doneWithFieldInits:
                    
                    for (int toCopy = nextInstructionInFirstBlock; toCopy < k; toCopy++)
                    {
                        preambleBlock.Statements.Add(firstBlock.Statements[toCopy]);
                        firstBlock.Statements[toCopy] = null;
                    }
                }
            }

            // Create a new body, add the preamble block, then all of the other blocks

            StatementList sl = new StatementList(m.Body.Statements.Count);
            sl.Add(preambleBlock);

            if (m.Body != null)
            {
                foreach (Block b in m.Body.Statements)
                {
                    if (b != null) sl.Add(b);
                }
            }

            m.Body.Statements = sl;

            return result;
        }