/// <summary> /// Create the Ctor /// </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> /// 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> /// 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> /// 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 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); }
/// <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> /// 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> /// Convert all synchronized methods. /// </summary> private static void Convert(MethodBody body) { var typeSystem = body.Method.Module.TypeSystem; var monitorType = typeSystem.LookupType("System.Threading", "Monitor"); var enterMethod = new MethodReference("Enter", typeSystem.Void, monitorType); enterMethod.Parameters.Add(new ParameterDefinition(typeSystem.Object)); var exitMethod = new MethodReference("Exit", typeSystem.Void, monitorType); exitMethod.Parameters.Add(new ParameterDefinition(typeSystem.Object)); var firstInstr = body.Instructions[0]; // Expand macro's body.SimplifyMacros(); // Prepare new return var retSeq = new ILSequence(); retSeq.Emit(OpCodes.Nop); retSeq.Emit(OpCodes.Ret); // Monitor.Enter(this) var initSeq = new ILSequence(); initSeq.Emit(OpCodes.Ldarg_0); // ld this initSeq.Emit(OpCodes.Call, enterMethod); initSeq.InsertTo(0, body); // Leave sequence var leaveSeq = new ILSequence(); leaveSeq.Emit(OpCodes.Nop); leaveSeq.Emit(OpCodes.Leave, retSeq.First); leaveSeq.AppendTo(body); // Finally: Monitor.Exit(this) var finallySeq = new ILSequence(); finallySeq.Emit(OpCodes.Ldarg_0); // ld this finallySeq.Emit(OpCodes.Call, exitMethod); finallySeq.Emit(OpCodes.Endfinally); finallySeq.AppendTo(body); // Replace Ret instructions foreach (var instr in body.Instructions.Where(x => x.OpCode.Code == Mono.Cecil.Cil.Code.Ret)) { if (instr.Next == leaveSeq.First) { instr.ChangeToNop(); } else { instr.OpCode = OpCodes.Br; instr.Operand = leaveSeq.First; } } // Append ret sequence retSeq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add try/finally block var handler = new ExceptionHandler(ExceptionHandlerType.Finally); handler.TryStart = firstInstr; handler.TryEnd = finallySeq.First; // leaveSeq.Last; handler.HandlerStart = finallySeq.First; handler.HandlerEnd = retSeq.First; // finallySeq.Last; body.ExceptionHandlers.Insert(0, handler); }
/// <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)) { // Not need to bother with cloning struct-type fields here, // as this will be done automatically by one of the Converters. // Prepare for stfld seq.Emit(OpCodes.Ldarg, body.ThisParameter); // Load from source seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Ldfld, field); // 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); }