/// <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
        public void Disassemble(MethodBody body)
        {
            // start writing IL code
            var method       = body.Method;
            var codesize     = body.ComputeCodeSize();
            var maxstacksize = body.ComputeMaxStackSize();

            body.ComputeOffsets();

            _o.WriteLine("// Code size {0} (0x{0:x})", codesize);
            _o.WriteLine(".maxstack {0}", maxstacksize);
            if (method.DeclaringType.Module.Assembly != null && method.DeclaringType.Module.Assembly.EntryPoint == method)
            {
                _o.WriteLine(".entrypoint");
            }

            if (method.Body.HasVariables)
            {
                _o.Write(".locals ");
                if (body.InitLocals)
                {
                    _o.Write("init ");
                }
                _o.WriteLine("(");
                _o.Indent();
                foreach (var v in body.Variables)
                {
                    _o.Write("[" + v.Index + "] ");
                    v.VariableType.WriteTo(_o);
                    if (!string.IsNullOrEmpty(v.Name))
                    {
                        _o.Write(' ');
                        _o.Write(DisassemblerHelpers.Escape(v.Name));
                    }
                    if (v.Index + 1 < body.Variables.Count)
                    {
                        _o.Write(',');
                    }
                    _o.WriteLine();
                }
                _o.Unindent();
                _o.WriteLine(")");
            }
            _o.WriteLine();

            if (body.Instructions.Count > 0)
            {
                var inst          = body.Instructions[0];
                var branchTargets = GetBranchTargets(body.Instructions);
                WriteStructureBody(new IlStructure(body, codesize), branchTargets, ref inst);
            }
            else
            {
                // we ignore method without instructions (but it can have exception handlers)
                _o.WriteLine();
            }
        }
예제 #3
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);
            }
예제 #4
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);
            }
예제 #5
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);
            }
예제 #6
0
            /// <summary>
            /// Inline the call to the given method
            /// </summary>
            private static void InlineCall(Instruction instruction, MethodBody body, MethodDefinition targetMethod)
            {
                // Prepare
                var prefixSeq = new ILSequence();

                // Create "this" variable
                VariableDefinition thisVariable = null;

                if (targetMethod.HasThis)
                {
                    thisVariable = new VariableDefinition(targetMethod.DeclaringType);
                    body.Variables.Add(thisVariable);
                    body.InitLocals = true;
                }

                // Store argument in variables
                var paramVariables = new List <VariableDefinition>();

                foreach (var parameter in targetMethod.Parameters.Reverse())
                {
                    // Create variable
                    var paramVariable = new VariableDefinition(parameter.ParameterType);
                    body.Variables.Add(paramVariable);
                    paramVariables.Insert(0, paramVariable);

                    // Pop
                    prefixSeq.Emit(OpCodes.Stloc, paramVariable);
                }

                // Store this argument (if any)
                if (thisVariable != null)
                {
                    // Pop
                    prefixSeq.Emit(OpCodes.Stloc, thisVariable);
                }

                // Clone variables first
                var source    = targetMethod.Body;
                var variables = new List <VariableDefinition>();

                foreach (var sv in source.Variables)
                {
                    var clone = new VariableDefinition(sv.VariableType);
                    variables.Add(clone);
                    body.Variables.Add(clone);
                }

                // Now clone instructions
                var seq = new ILSequence();

                foreach (var instr in source.Instructions)
                {
                    var ni = new Instruction(instr.OpCode, instr.Operand);
                    seq.Append(ni);
                    ni.Offset = instr.Offset;

                    // Convert variable opcodes
                    switch (instr.OpCode.OperandType)
                    {
                    case OperandType.InlineVar:
                    case OperandType.ShortInlineVar:
                    {
                        var index = source.Variables.IndexOf((VariableDefinition)instr.Operand);
                        ni.Operand = variables[index];
                    }
                    break;
                    }

                    // Convert parameter opcodes
                    switch (instr.OpCode.Code)
                    {
                    case Code.Ldarg:
                    {
                        var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Ldloc;
                    }
                    break;

                    case Code.Ldarga:
                    {
                        var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Ldloca;
                    }
                    break;

                    case Code.Starg:
                    {
                        var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Stloc;
                    }
                    break;
                    }
                }

                // Update branch targets
                for (var i = 0; i < seq.Length; i++)
                {
                    var instr = seq[i];
                    var oldi  = source.Instructions[i];

                    if (instr.OpCode.OperandType == OperandType.InlineSwitch)
                    {
                        var olds    = (Instruction[])oldi.Operand;
                        var targets = new Instruction[olds.Length];

                        for (int j = 0; j < targets.Length; j++)
                        {
                            targets[j] = GetClone(seq, source.Instructions, olds[j]);
                        }

                        instr.Operand = targets;
                    }
                    else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget ||
                             instr.OpCode.OperandType == OperandType.InlineBrTarget)
                    {
                        instr.Operand = GetClone(seq, source.Instructions, (Instruction)oldi.Operand);
                    }
                }

                // Clone exception handlers
                if (source.HasExceptionHandlers)
                {
                    body.ComputeOffsets();
                    CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers);
                }

                // Replace ret instructions
                var end             = seq.Emit(OpCodes.Nop);
                var retInstructions = seq.Where(x => x.OpCode.Code == Code.Ret).ToList();

                foreach (var ins in retInstructions)
                {
                    ins.OpCode  = OpCodes.Br;
                    ins.Operand = end;
                }

                // cast return type of a generic method. TODO: better might be to
                // correctly resolve calls to generic instances as well (above)
                if (targetMethod.ReturnType.IsGenericParameter)
                {
                    var           methodRef  = (MethodReference)instruction.Operand;
                    TypeReference returnType = null;

                    var gp = (GenericParameter)methodRef.ReturnType;
                    if (gp.Type == GenericParameterType.Type)
                    {
                        var gi = methodRef.DeclaringType as IGenericInstance;
                        if (gi != null && gi.HasGenericArguments)
                        {
                            returnType = gi.GenericArguments[gp.Position];
                        }
                    }
                    else if (gp.Type == GenericParameterType.Method)
                    {
                        var gi = methodRef as IGenericInstance;
                        if (gi != null && gi.HasGenericArguments)
                        {
                            returnType = gi.GenericArguments[gp.Position];
                        }
                    }

                    if (returnType != null)
                    {
                        if (!returnType.IsPrimitive)
                        {
                            seq.Emit(OpCodes.Castclass, returnType);
                        }
                        // todo: handle primitive types. unbox them? are structs correctly handled? enums?
                    }
                }

                // Insert cloned instructions
                prefixSeq.InsertTo(0, seq);
                seq.InsertToAfter(instruction, body);

                // Change replaced instruction to nop
                instruction.ChangeToNop();

                // Update offsets
                body.ComputeOffsets();
            }
예제 #7
0
        public override void Process(ConfusionParameter parameter)
        {
            method = parameter.Target as MethodDefinition;
            if (!method.HasBody)
            {
                return;
            }

            int slv = 5;

            if (Array.IndexOf(parameter.Parameters.AllKeys, "level") != -1)
            {
                if (!int.TryParse(parameter.Parameters["level"], out slv) && (slv <= 0 || slv > 10))
                {
                    Log("Invaild level, 5 will be used.");
                    slv = 5;
                }
            }
            genJunk = false;
            if (method.Module.Architecture != TargetArchitecture.I386)
            {
                genJunk = false;
            }
            else if (Array.IndexOf(parameter.Parameters.AllKeys, "genjunk") != -1)
            {
                if (!bool.TryParse(parameter.Parameters["genjunk"], out genJunk))
                {
                    Log("Invaild junk code parameter, junk code would not generated.");
                    genJunk = false;
                }
            }
            double trueLv = slv / 10.0;

            MethodBody body = method.Body;

            body.ComputeHeader();
            body.MaxStackSize += 5;
            Dictionary <Instruction, Level> Ids = GetIds(body);

            Level[] lvs = GetLvs(Ids);
            List <Instruction[]> scopes = new List <Instruction[]>();

            foreach (Level lv in lvs)
            {
                scopes.Add(GetInstructionsByLv(lv, Ids));
            }

            body.Instructions.Clear();
            Dictionary <Instruction, Instruction> HdrTbl = new Dictionary <Instruction, Instruction>();

            for (int i = 0; i < scopes.Count; i++)
            {
                Instruction[]   scope = scopes[i];
                Instruction[][] blocks;
                blocks = BranchesSplit(scope, trueLv);
                AddBranches(body, ref blocks);
                Reorder(ref blocks);

                HdrTbl.Add(scope[0], blocks[0][0]);

                foreach (Instruction[] iblk in blocks)
                {
                    body.Instructions.Add(iblk[0]);
                    for (int ii = 1; ii < iblk.Length; ii++)
                    {
                        Instruction tmp;
                        if (iblk[ii].Operand is Instruction)
                        {
                            if (HdrTbl.TryGetValue(iblk[ii].Operand as Instruction, out tmp) && tmp != blocks[0][0])
                            {
                                iblk[ii].Operand = tmp;
                            }
                        }
                        else if (iblk[ii].Operand is Instruction[])
                        {
                            Instruction[] op = iblk[ii].Operand as Instruction[];
                            for (int iii = 0; iii < op.Length; iii++)
                            {
                                if (HdrTbl.TryGetValue(op[iii], out tmp) && tmp != blocks[0][0])
                                {
                                    op[iii] = tmp;
                                }
                            }
                            iblk[ii].Operand = op;
                        }
                        body.Instructions.Add(iblk[ii]);
                    }
                }
                SetLvHandler(lvs[i], body, blocks);
            }

            foreach (ExceptionHandler eh in body.ExceptionHandlers)
            {
                eh.TryEnd     = eh.TryEnd.Next;
                eh.HandlerEnd = eh.HandlerEnd.Next;
                //if ((eh.HandlerType & ExceptionHandlerType.Filter) == ExceptionHandlerType.Filter)
                //{
                //    eh.FilterEnd = eh.FilterEnd.Next;
                //}
            }

            body.ComputeOffsets();
            body.PreserveMaxStackSize = true;
        }
            /// <summary>
            /// Inline the call to the given ctor
            /// </summary>
            private static void InlineNewObjCall(Instruction instruction, MethodBody body, MethodDefinition ctor)
            {
                // Prepare
                var prefixSeq = new ILSequence();

                ctor.Body.SimplifyMacros();

                // Create "this" variable
                var thisVariable = new VariableDefinition(ctor.DeclaringType);

                body.Variables.Add(thisVariable);
                body.InitLocals = true;

                // Store argument in variables
                var paramVariables = new List <VariableDefinition>();

                foreach (var parameter in ctor.Parameters.Reverse())
                {
                    // Create variable
                    var paramVariable = new VariableDefinition(parameter.ParameterType);
                    body.Variables.Add(paramVariable);
                    paramVariables.Insert(0, paramVariable);

                    // Pop
                    prefixSeq.Emit(OpCodes.Stloc, paramVariable);
                }

                // Clone variables first
                var source    = ctor.Body;
                var variables = new List <VariableDefinition>();

                foreach (var sv in source.Variables)
                {
                    var clone = new VariableDefinition(sv.VariableType);
                    variables.Add(clone);
                    body.Variables.Add(clone);
                }

                // Now clone instructions
                var seq = new ILSequence();

                foreach (var instr in source.Instructions)
                {
                    var ni = new Instruction(instr.OpCode, instr.Operand);
                    seq.Append(ni);
                    ni.Offset = instr.Offset;

                    // Convert variable opcodes
                    switch (instr.OpCode.OperandType)
                    {
                    case OperandType.InlineVar:
                    case OperandType.ShortInlineVar:
                    {
                        var index = source.Variables.IndexOf((VariableDefinition)instr.Operand);
                        ni.Operand = variables[index];
                    }
                    break;
                    }

                    // Convert parameter opcodes
                    switch (instr.OpCode.Code)
                    {
                    case Mono.Cecil.Cil.Code.Ldarg:
                    {
                        var index = ctor.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Ldloc;
                    }
                    break;

                    case Mono.Cecil.Cil.Code.Ldarga:
                    {
                        var index = ctor.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Ldloca;
                    }
                    break;

                    case Mono.Cecil.Cil.Code.Starg:
                    {
                        var index = ctor.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Stloc;
                    }
                    break;
                    }
                }

                // Update branch targets
                for (var i = 0; i < seq.Length; i++)
                {
                    var instr = seq[i];
                    var oldi  = source.Instructions[i];

                    if (instr.OpCode.OperandType == OperandType.InlineSwitch)
                    {
                        var olds    = (Instruction[])oldi.Operand;
                        var targets = new Instruction[olds.Length];

                        for (int j = 0; j < targets.Length; j++)
                        {
                            targets[j] = GetClone(seq, source.Instructions, olds[j]);
                        }

                        instr.Operand = targets;
                    }
                    else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget ||
                             instr.OpCode.OperandType == OperandType.InlineBrTarget)
                    {
                        instr.Operand = GetClone(seq, source.Instructions, (Instruction)oldi.Operand);
                    }
                }

                // Clone exception handlers
                if (source.HasExceptionHandlers)
                {
                    CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers);
                }

                // Find call to "this" ctor
                var callToCtors = seq.Where(x => IsCallToThisCtor(x, ctor)).ToList();

                if (callToCtors.Count == 0)
                {
                    throw new CompilerException(string.Format("No call to another this ctor found in {0}", ctor));
                }
                if (callToCtors.Count > 1)
                {
                    throw new CompilerException(string.Format("Multiple calls to another this ctor found in {0}", ctor));
                }
                var callToCtor = callToCtors[0];

                // Change "ld this" to nop
                var args = callToCtor.GetCallArguments(seq, true);

                args[0].ChangeToNop(); // Replace ldarg.0

                // Replace call to this ctor with newobj
                var callSeq = new ILSequence();

                callSeq.Emit(OpCodes.Newobj, (MethodReference)callToCtor.Operand);
                callSeq.Emit(OpCodes.Stloc, thisVariable); // Save new object
                callToCtor.ChangeToNop();
                callSeq.InsertToBefore(callToCtor, seq);

                // Replace ret instructions
                var end             = seq.Emit(OpCodes.Ldloc, thisVariable);
                var retInstructions = seq.Where(x => x.OpCode.Code == Mono.Cecil.Cil.Code.Ret).ToList();

                foreach (var ins in retInstructions)
                {
                    ins.OpCode  = OpCodes.Br;
                    ins.Operand = end;
                }

                // Insert cloned instructions
                prefixSeq.InsertTo(0, seq);
                seq.InsertToAfter(instruction, body);

                // Change replaced instruction to nop
                instruction.ChangeToNop();

                // Update offsets
                body.ComputeOffsets();
            }
예제 #9
0
            /// <summary>
            /// Inline the call to the given method
            /// </summary>
            private static void InlineCall(Instruction instruction, MethodBody body, MethodDefinition targetMethod)
            {
                // Prepare
                var prefixSeq = new ILSequence();

                // Create "this" variable
                VariableDefinition thisVariable = null;

                if (targetMethod.HasThis)
                {
                    thisVariable = new VariableDefinition(targetMethod.DeclaringType);
                    body.Variables.Add(thisVariable);
                    body.InitLocals = true;
                }

                // Store argument in variables
                var paramVariables = new List <VariableDefinition>();

                foreach (var parameter in targetMethod.Parameters.Reverse())
                {
                    // Create variable
                    var paramVariable = new VariableDefinition(parameter.ParameterType);
                    body.Variables.Add(paramVariable);
                    paramVariables.Insert(0, paramVariable);

                    // Pop
                    prefixSeq.Emit(OpCodes.Stloc, paramVariable);
                }

                // Store this argument (if any)
                if (thisVariable != null)
                {
                    // Pop
                    prefixSeq.Emit(OpCodes.Stloc, thisVariable);
                }

                // Clone variables first
                var source    = targetMethod.Body;
                var variables = new List <VariableDefinition>();

                foreach (var sv in source.Variables)
                {
                    var clone = new VariableDefinition(sv.VariableType);
                    variables.Add(clone);
                    body.Variables.Add(clone);
                }

                // Now clone instructions
                var seq = new ILSequence();

                foreach (var instr in source.Instructions)
                {
                    var ni = new Instruction(instr.OpCode, instr.Operand);
                    seq.Append(ni);
                    ni.Offset = instr.Offset;

                    // Convert variable opcodes
                    switch (instr.OpCode.OperandType)
                    {
                    case OperandType.InlineVar:
                    case OperandType.ShortInlineVar:
                    {
                        var index = source.Variables.IndexOf((VariableDefinition)instr.Operand);
                        ni.Operand = variables[index];
                    }
                    break;
                    }

                    // Convert parameter opcodes
                    switch (instr.OpCode.Code)
                    {
                    case Code.Ldarg:
                    {
                        var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Ldloc;
                    }
                    break;

                    case Code.Ldarga:
                    {
                        var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Ldloca;
                    }
                    break;

                    case Code.Starg:
                    {
                        var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable;
                        ni.OpCode  = OpCodes.Stloc;
                    }
                    break;
                    }
                }

                // Update branch targets
                for (var i = 0; i < seq.Length; i++)
                {
                    var instr = seq[i];
                    var oldi  = source.Instructions[i];

                    if (instr.OpCode.OperandType == OperandType.InlineSwitch)
                    {
                        var olds    = (Instruction[])oldi.Operand;
                        var targets = new Instruction[olds.Length];

                        for (int j = 0; j < targets.Length; j++)
                        {
                            targets[j] = GetClone(seq, source.Instructions, olds[j]);
                        }

                        instr.Operand = targets;
                    }
                    else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget ||
                             instr.OpCode.OperandType == OperandType.InlineBrTarget)
                    {
                        instr.Operand = GetClone(seq, source.Instructions, (Instruction)oldi.Operand);
                    }
                }

                // Clone exception handlers
                if (source.HasExceptionHandlers)
                {
                    body.ComputeOffsets();
                    CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers);
                }

                // Replace ret instructions
                var end             = seq.Emit(OpCodes.Nop);
                var retInstructions = seq.Where(x => x.OpCode.Code == Code.Ret).ToList();

                foreach (var ins in retInstructions)
                {
                    ins.OpCode  = OpCodes.Br;
                    ins.Operand = end;
                }

                // Insert cloned instructions
                prefixSeq.InsertTo(0, seq);
                seq.InsertToAfter(instruction, body);

                // Change replaced instruction to nop
                instruction.ChangeToNop();

                // Update offsets
                body.ComputeOffsets();
            }
예제 #10
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);
            }
예제 #11
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);
            }