/// <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 && 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; }