/// <summary> /// Implement IAsyncSetThis. /// </summary> private static void ImplementISetThis(TypeDefinition type, ReachableContext reachableContext) { var thisField = type.Fields.FirstOrDefault(x => x.Name.StartsWith("<>") && x.Name.EndsWith("__this")); if (thisField == null) return; // Add interface var intfType = type.Module.Import(new TypeReference(InternalConstants.Dot42InternalNamespace, "IAsyncSetThis", type.Module, type.Module.Assembly.Name)); type.Interfaces.Add(new InterfaceImpl(intfType)); // Add "SetThis(object)" method var method = new MethodDefinition("SetThis", MethodAttributes.Public, type.Module.TypeSystem.Void); method.SetReachable(reachableContext); type.Methods.Add(method); var valueParam = new ParameterDefinition(type.Module.TypeSystem.Object); method.Parameters.Add(valueParam); method.Body = new MethodBody(method) { InitLocals = true }; var seq = new ILSequence(); seq.Emit(OpCodes.Ldarg_0); // this seq.Emit(OpCodes.Ldarg, valueParam); seq.Emit(OpCodes.Castclass, thisField.FieldType); seq.Emit(OpCodes.Stfld, thisField); seq.Emit(OpCodes.Ret); seq.AppendTo(method.Body); }
/// <summary> /// Convert all synchronized methods. /// </summary> private static void CreateDefaultCtor(ReachableContext reachableContext, TypeDefinition type) { var typeSystem = type.Module.TypeSystem; var ctor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, typeSystem.Void); ctor.DeclaringType = type; var body = new MethodBody(ctor); body.InitLocals = true; ctor.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add ctor type.Methods.Add(ctor); ctor.SetReachable(reachableContext); }
/// <summary> /// Create a new method in the declaring type of the given implicit implementation with the given name. /// This method will call the implicit implementation. /// </summary> internal static MethodDefinition CreateExplicitStub(MethodDefinition implicitImpl, string name, MethodDefinition iMethod, bool avoidGenericParam) { // Create method var newMethod = new MethodDefinition(name, implicitImpl.Attributes, implicitImpl.ReturnType); newMethod.IsVirtual = false; newMethod.IsAbstract = false; newMethod.IsFinal = true; // Clone generic parameters foreach (var gp in implicitImpl.GenericParameters) { newMethod.GenericParameters.Add(new GenericParameter(gp.Name, newMethod)); } // Update according to new context var cloner = new TypeCloner(avoidGenericParam, implicitImpl.Module.TypeSystem); newMethod.ReturnType = cloner.Get(implicitImpl.ReturnType, newMethod); // Clone parameters foreach (var p in iMethod.Parameters) { newMethod.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, cloner.Get(p.ParameterType, newMethod))); } // Add the method var targetType = implicitImpl.DeclaringType; targetType.Methods.Add(newMethod); // Add override newMethod.Overrides.Add(iMethod); // Create method body var body = new MethodBody(newMethod); newMethod.Body = body; var worker = body.GetILProcessor(); // Push this worker.Emit(OpCodes.Ldarg, body.ThisParameter); for (var i = 0; i < implicitImpl.Parameters.Count; i++) { var p = iMethod.Parameters[i]; var newMethodParam = newMethod.Parameters[i]; worker.Emit(OpCodes.Ldarg, newMethodParam); if (/*avoidGenericParam &&*/ p.ParameterType.ContainsGenericParameter) { worker.Emit(OpCodes.Box, implicitImpl.Parameters[i].ParameterType); } } worker.Emit(implicitImpl.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, implicitImpl); worker.Emit(OpCodes.Ret); // Mark method reachable if (implicitImpl.IsReachable) { newMethod.SetReachable(null); } return newMethod; }
/// <summary> /// Ensure there is a class ctor. /// </summary> private static MethodDefinition EnsureClassCtor(ReachableContext reachableContext, TypeDefinition type) { var ctor = type.GetClassCtor(); if (ctor != null) return ctor; // Already exists // Create class ctor var typeSystem = type.Module.TypeSystem; ctor = new MethodDefinition(".cctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Static | MethodAttributes.SpecialName, typeSystem.Void); ctor.DeclaringType = type; var body = new MethodBody(ctor); body.InitLocals = true; ctor.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add ctor type.Methods.Add(ctor); ctor.SetReachable(reachableContext); return ctor; }
/// <summary> /// Add a method that has the same signature as basemethod and calls method. /// </summary> private MethodDefinition AddBridge(MethodDefinition method, MethodDefinition baseMethod) { var bridge = new MethodDefinition(baseMethod.Name, baseMethod.Attributes, baseMethod.ReturnType) { HasThis = true }; var cloner = new TypeCloner(true, method.Module.TypeSystem); bridge.ReturnType = cloner.Get(baseMethod.ReturnType, bridge); bridge.IsAbstract = false; // Clone parameters foreach (var p in baseMethod.Parameters) { bridge.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, cloner.Get(p.ParameterType, bridge))); } // Create body var body = new MethodBody(bridge); bridge.Body = body; // Create code var seq = new ILSequence(); // this seq.Emit(OpCodes.Ldarg_0); // parameters for (var i = 0; i < bridge.Parameters.Count; i++) { var p = bridge.Parameters[i]; seq.Emit(OpCodes.Ldarg, p); if (baseMethod.Parameters[i].ParameterType.ContainsGenericParameter) { seq.Emit(OpCodes.Unbox, method.Parameters[i].ParameterType); } } // Call actual method seq.Emit(OpCodes.Call, method); // Return seq.Emit(OpCodes.Ret); // Add code to body seq.AppendTo(body); body.ComputeOffsets(); // add overrides, so that we can find the method later bridge.Overrides.Add(baseMethod); // Add to class method.DeclaringType.Methods.Add(bridge); bridge.SetReachable(reachableContext); return bridge; }
/// <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; }
/// <summary> /// Create a Clone method. /// </summary> private static void CreateCloneMethod(ReachableContext reachableContext, TypeDefinition type, MethodDefinition copyFromMethod) { var method = new MethodDefinition(NameConstants.Struct.CloneMethodName, MethodAttributes.Public, type); method.DeclaringType = type; var body = new MethodBody(method); body.InitLocals = true; method.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); // Create new instance var defaultCtor = CreateDefaultCtorRef(type); seq.Emit(OpCodes.Newobj, defaultCtor); // Call clone.CopyFrom seq.Emit(OpCodes.Dup); seq.Emit(OpCodes.Ldarg, body.ThisParameter); seq.Emit(OpCodes.Call, copyFromMethod); // Return clone seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add method type.Methods.Add(method); method.SetReachable(reachableContext); }