/// <summary> /// Inject initialization code to the given ctor /// </summary> private static void InjectInitializationCode(MethodDefinition ctor, IEnumerable <FieldDefinition> structFields) { // Create sequence var initSeq = StructFields.CreateInitializationCode(structFields, true); // Find location where to insert var body = ctor.Body; // Insert at start of method initSeq.InsertTo(0, body); }
/// <summary> /// Inject initialization code to the given ctor /// </summary> private static void InjectInitializationCode(MethodDefinition ctor, IEnumerable <FieldDefinition> structFields) { // Create sequence var initSeq = StructFields.CreateInitializationCode(structFields, false); // Find location where to insert var body = ctor.Body; var baseCtorCall = body.Instructions.FirstOrDefault(x => IsBaseOrThisCtorCall(ctor, x)); if (baseCtorCall != null) { // Insert after call to base/this ctor initSeq.InsertToAfter(baseCtorCall, body); } else { // Insert at start of method initSeq.InsertTo(0, body); } }
/// <summary> /// Create default ctors for reachable structs. /// </summary> public void Convert(ReachableContext reachableContext) { // Collect all type var todoTypes = reachableContext.ReachableTypes.Where(x => x.IsValueType && !x.IsPrimitive && !x.IsEnum).ToList(); if (todoTypes.Count == 0) { return; } foreach (var type in todoTypes) { if (!HasDefaultCtor(type)) { CreateDefaultCtor(reachableContext, type); } if (StructFields.IsImmutableStruct(type) && !type.HasGenericParameters) { CreateDefaultField(reachableContext, type); } } }
/// <summary> /// Does the given type have any instance field that is a struct? /// </summary> private static bool HasInstanceStructFields(TypeDefinition type, out List <FieldDefinition> structFields) { structFields = null; if (type.IsEnum) // Class ctor is already created automatically for enums { return(false); } if (type.Name.StartsWith("<PrivateImplementationDetails>")) { return(false); } foreach (var field in type.Fields.Where(x => !x.IsStatic && x.IsReachable && StructFields.IsStructField(x))) { if (structFields == null) { structFields = new List <FieldDefinition>(); } structFields.Add(field); } return(structFields != null); }
/// <summary> /// Create a CopyFrom method. /// </summary> private static MethodDefinition CreateCopyFromMethod(ReachableContext reachableContext, TypeDefinition type) { var typeSystem = type.Module.TypeSystem; var method = new MethodDefinition(NameConstants.Struct.CopyFromMethodName, MethodAttributes.Public, type); var sourceParam = new ParameterDefinition(type); method.Parameters.Add(sourceParam); method.DeclaringType = type; var body = new MethodBody(method); body.InitLocals = true; method.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); // Call base CopyFrom var baseType = (type.BaseType != null) ? type.BaseType.GetElementType().Resolve() : null; if ((baseType != null) && baseType.IsValueType && (baseType.FullName != "System.ValueType")) { var baseMethod = new MethodReference(NameConstants.Struct.CopyFromMethodName, baseType, baseType) { HasThis = true }; baseMethod.Parameters.Add(new ParameterDefinition(baseType)); seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Call, baseMethod); } // Copy all fields foreach (var field in type.Fields.Where(x => !x.IsStatic)) { TypeDefinition fieldTypeDef; var isStructField = StructFields.IsStructField(field, out fieldTypeDef); // Prepare for stfld seq.Emit(OpCodes.Ldarg, body.ThisParameter); // Load from source seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Ldfld, field); // If struct, create clone if (isStructField) { var cloneMethod = new MethodReference(NameConstants.Struct.CloneMethodName, fieldTypeDef, fieldTypeDef) { HasThis = true }; seq.Emit(OpCodes.Call, cloneMethod); } // Save in this seq.Emit(OpCodes.Stfld, field); } // Return this seq.Emit(OpCodes.Ldarg, body.ThisParameter); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add method type.Methods.Add(method); method.SetReachable(reachableContext); return(method); }