/// <summary> /// Handles both object and collection initializers. /// </summary> bool TransformObjectInitializers(List<ILNode> body, ILExpression expr, int pos) { if (!context.Settings.ObjectOrCollectionInitializers) return false; Debug.Assert(body[pos] == expr); // should be called for top-level expressions only ILVariable v; ILExpression newObjExpr; MethodReference ctor; List<ILExpression> ctorArgs; // v = newObj(ctor, ctorArgs) if (!(expr.Match(ILCode.Stloc, out v, out newObjExpr) && newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))) return false; int originalPos = pos; // don't use object initializer syntax for closures if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, ctor.DeclaringType.ResolveWithinSameModule())) return false; ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(ctor.DeclaringType)); if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements return false; int totalElementCount = pos - originalPos - 1; // totalElementCount: includes elements from nested collections Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1); // Verify that we can inline 'v' into the next instruction: if (pos >= body.Count) return false; // reached end of block, but there should be another instruction which consumes the initialized object ILInlining inlining = new ILInlining(method); // one ldloc for each initializer argument, and another ldloc for the use of the initialized object if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1) return false; if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0)) return false; ILExpression nextExpr = body[pos] as ILExpression; if (!inlining.CanInlineInto(nextExpr, v, initializer)) return false; expr.Arguments[0] = initializer; // remove all the instructions that were pulled into the initializer body.RemoveRange(originalPos + 1, pos - originalPos - 1); // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject' ChangeFirstArgumentToInitializedObject(initializer); inlining = new ILInlining(method); inlining.InlineIfPossible(body, ref originalPos); return true; }
/// <summary> /// Handles both object and collection initializers. /// </summary> bool TransformObjectInitializers(List <ILNode> body, ILExpression expr, int pos) { if (!context.Settings.ObjectOrCollectionInitializers) { return(false); } Debug.Assert(body[pos] == expr); // should be called for top-level expressions only ILVariable v; ILExpression newObjExpr; MethodReference ctor; List <ILExpression> ctorArgs; // v = newObj(ctor, ctorArgs) if (!(expr.Match(ILCode.Stloc, out v, out newObjExpr) && newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))) { return(false); } int originalPos = pos; // don't use object initializer syntax for closures if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, ctor.DeclaringType.ResolveWithinSameModule())) { return(false); } ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(ctor.DeclaringType)); if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements { return(false); } int totalElementCount = pos - originalPos - 1; // totalElementCount: includes elements from nested collections Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1); // Verify that we can inline 'v' into the next instruction: if (pos >= body.Count) { return(false); // reached end of block, but there should be another instruction which consumes the initialized object } ILInlining inlining = new ILInlining(method); // one ldloc for each initializer argument, and another ldloc for the use of the initialized object if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1) { return(false); } if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0)) { return(false); } ILExpression nextExpr = body[pos] as ILExpression; if (!inlining.CanInlineInto(nextExpr, v, initializer)) { return(false); } expr.Arguments[0] = initializer; // remove all the instructions that were pulled into the initializer body.RemoveRange(originalPos + 1, pos - originalPos - 1); // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject' ChangeFirstArgumentToInitializedObject(initializer); inlining = new ILInlining(method); inlining.InlineIfPossible(body, ref originalPos); return(true); }
/// <summary> /// Handles both object and collection initializers. /// </summary> bool TransformObjectInitializers(List <ILNode> body, ILExpression expr, int pos) { if (!context.Settings.ObjectOrCollectionInitializers) { return(false); } Debug.Assert(body[pos] == expr); // should be called for top-level expressions only ILVariable v; ILExpression newObjExpr; TypeReference newObjType; bool isValueType; MethodReference ctor; List <ILExpression> ctorArgs; if (expr.Match(ILCode.Stloc, out v, out newObjExpr)) { if (newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs)) { // v = newObj(ctor, ctorArgs) newObjType = ctor.DeclaringType; isValueType = false; } else if (newObjExpr.Match(ILCode.DefaultValue, out newObjType)) { // v = defaultvalue(type) isValueType = true; } else { return(false); } } else if (expr.Match(ILCode.Call, out ctor, out ctorArgs)) { // call(SomeStruct::.ctor, ldloca(v), remainingArgs) if (ctorArgs.Count > 0 && ctorArgs[0].Match(ILCode.Ldloca, out v)) { isValueType = true; newObjType = ctor.DeclaringType; ctorArgs = new List <ILExpression>(ctorArgs); ctorArgs.RemoveAt(0); newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs); } else { return(false); } } else { return(false); } if (newObjType.IsValueType != isValueType) { return(false); } int originalPos = pos; // don't use object initializer syntax for closures if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, newObjType.ResolveWithinSameModule())) { return(false); } ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(newObjType), isValueType); if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements { return(false); } int totalElementCount = pos - originalPos - 1; // totalElementCount: includes elements from nested collections Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1); // Verify that we can inline 'v' into the next instruction: if (pos >= body.Count) { return(false); // reached end of block, but there should be another instruction which consumes the initialized object } ILInlining inlining = new ILInlining(method); if (isValueType) { // one ldloc for the use of the initialized object if (inlining.numLdloc.GetOrDefault(v) != 1) { return(false); } // one ldloca for each initializer argument, and also for the ctor call (if it exists) if (inlining.numLdloca.GetOrDefault(v) != totalElementCount + (expr.Code == ILCode.Call ? 1 : 0)) { return(false); } // one stloc for the initial store (if no ctor call was used) if (inlining.numStloc.GetOrDefault(v) != (expr.Code == ILCode.Call ? 0 : 1)) { return(false); } } else { // one ldloc for each initializer argument, and another ldloc for the use of the initialized object if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1) { return(false); } if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0)) { return(false); } } ILExpression nextExpr = body[pos] as ILExpression; if (!inlining.CanInlineInto(nextExpr, v, initializer)) { return(false); } if (expr.Code == ILCode.Stloc) { expr.Arguments[0] = initializer; } else { Debug.Assert(expr.Code == ILCode.Call); expr.Code = ILCode.Stloc; expr.Operand = v; expr.Arguments.Clear(); expr.Arguments.Add(initializer); } // remove all the instructions that were pulled into the initializer body.RemoveRange(originalPos + 1, pos - originalPos - 1); // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject' ChangeFirstArgumentToInitializedObject(initializer); inlining = new ILInlining(method); inlining.InlineIfPossible(body, ref originalPos); return(true); }
/// <summary> /// Handles both object and collection initializers. /// </summary> bool TransformObjectInitializers(List<ILNode> body, ILExpression expr, int pos) { if (!context.Settings.ObjectOrCollectionInitializers) return false; Debug.Assert(body[pos] == expr); // should be called for top-level expressions only ILVariable v; ILExpression newObjExpr; TypeReference newObjType; bool isValueType; MethodReference ctor; List<ILExpression> ctorArgs; if (expr.Match(ILCode.Stloc, out v, out newObjExpr)) { if (newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs)) { // v = newObj(ctor, ctorArgs) newObjType = ctor.DeclaringType; isValueType = false; } else if (newObjExpr.Match(ILCode.DefaultValue, out newObjType)) { // v = defaultvalue(type) isValueType = true; } else { return false; } } else if (expr.Match(ILCode.Call, out ctor, out ctorArgs)) { // call(SomeStruct::.ctor, ldloca(v), remainingArgs) if (ctorArgs.Count > 0 && ctorArgs[0].Match(ILCode.Ldloca, out v)) { isValueType = true; newObjType = ctor.DeclaringType; ctorArgs = new List<ILExpression>(ctorArgs); ctorArgs.RemoveAt(0); newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs); } else { return false; } } else { return false; } if (newObjType.IsValueType != isValueType) return false; int originalPos = pos; // don't use object initializer syntax for closures if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, newObjType.ResolveWithinSameModule())) return false; ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(newObjType), isValueType); if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements return false; int totalElementCount = pos - originalPos - 1; // totalElementCount: includes elements from nested collections Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1); // Verify that we can inline 'v' into the next instruction: if (pos >= body.Count) return false; // reached end of block, but there should be another instruction which consumes the initialized object ILInlining inlining = new ILInlining(method); if (isValueType) { // one ldloc for the use of the initialized object if (inlining.numLdloc.GetOrDefault(v) != 1) return false; // one ldloca for each initializer argument, and also for the ctor call (if it exists) if (inlining.numLdloca.GetOrDefault(v) != totalElementCount + (expr.Code == ILCode.Call ? 1 : 0)) return false; // one stloc for the initial store (if no ctor call was used) if (inlining.numStloc.GetOrDefault(v) != (expr.Code == ILCode.Call ? 0 : 1)) return false; } else { // one ldloc for each initializer argument, and another ldloc for the use of the initialized object if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1) return false; if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0)) return false; } ILExpression nextExpr = body[pos] as ILExpression; if (!inlining.CanInlineInto(nextExpr, v, initializer)) return false; if (expr.Code == ILCode.Stloc) { expr.Arguments[0] = initializer; } else { Debug.Assert(expr.Code == ILCode.Call); expr.Code = ILCode.Stloc; expr.Operand = v; expr.Arguments.Clear(); expr.Arguments.Add(initializer); } // remove all the instructions that were pulled into the initializer body.RemoveRange(originalPos + 1, pos - originalPos - 1); // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject' ChangeFirstArgumentToInitializedObject(initializer); inlining = new ILInlining(method); inlining.InlineIfPossible(body, ref originalPos); return true; }