/// <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);
            }
예제 #2
0
            /// <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>
            /// 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);
            }
예제 #5
0
            /// <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);
            }
예제 #6
0
            /// <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);
            }
예제 #7
0
            /// <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;
            }
예제 #10
0
            /// <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;
            }        
예제 #11
0
            /// <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>
            /// 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);
            }
예제 #13
0
            /// <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);
            }
예제 #14
0
            /// <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);
            }