Ejemplo n.º 1
0
        private static void GetAllExceptions(MethodBase method, HashSet <Type> exceptionTypes,
                                             HashSet <MethodBase> visitedMethods, int depth)
        {
            var        ilReader     = new ILReader(method);
            MethodBase stackTopItem = null;

            foreach (var instruction in ilReader)
            {
                if (instruction is InlineMethodInstruction)
                {
                    var methodInstruction = (InlineMethodInstruction)instruction;

                    if (methodInstruction.OpCode.StackBehaviourPush == StackBehaviour.Pushref &&
                        (methodInstruction.Method.MemberType & MemberTypes.Constructor) != 0)
                    {
                        stackTopItem = methodInstruction.Method;
                    }

                    if (!visitedMethods.Contains(methodInstruction.Method))
                    {
                        visitedMethods.Add(methodInstruction.Method);
                        GetAllExceptions(methodInstruction.Method, exceptionTypes, visitedMethods,
                                         depth + 1);
                    }
                }
                else
                {
                    switch (instruction.OpCode.Value)
                    {
                    case 0x7A:         // throw
                        if (stackTopItem == null)
                        {
                            throw new InvalidProgramException();
                        }

                        exceptionTypes.Add(stackTopItem.DeclaringType);
                        break;
                    }
                }
            }
        }
Ejemplo n.º 2
0
            public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
            {
                base.DecompileMethod(method, output, options);
                if (!method.HasBody)
                {
                    return;
                }
                var typeSystem             = new DecompilerTypeSystem(method.Module);
                var specializingTypeSystem = typeSystem.GetSpecializingTypeSystem(new SimpleTypeResolveContext(typeSystem.Resolve(method)));
                var reader = new ILReader(specializingTypeSystem);

                reader.UseDebugSymbols = options.DecompilerSettings.UseDebugSymbols;
                ILFunction         il      = reader.ReadIL(method.Body, options.CancellationToken);
                ILTransformContext context = new ILTransformContext(il, typeSystem, options.DecompilerSettings)
                {
                    CancellationToken = options.CancellationToken
                };

                context.Stepper.StepLimit = options.StepLimit;
                context.Stepper.IsDebug   = options.IsDebug;
                try {
                    il.RunTransforms(transforms, context);
                } catch (StepLimitReachedException) {
                } catch (Exception ex) {
                    output.WriteLine(ex.ToString());
                    output.WriteLine();
                    output.WriteLine("ILAst after the crash:");
                } finally {
                    // update stepper even if a transform crashed unexpectedly
                    if (options.StepLimit == int.MaxValue)
                    {
                        Stepper = context.Stepper;
                        OnStepperUpdated(new EventArgs());
                    }
                }
                (output as ISmartTextOutput)?.AddButton(Images.ViewCode, "Show Steps", delegate {
                    DebugSteps.Show();
                });
                output.WriteLine();
                il.WriteTo(output, DebugSteps.Options);
            }
Ejemplo n.º 3
0
        ILFunction TransformDelegateConstruction(NewObj value, out ILInstruction target)
        {
            target = null;
            if (!IsDelegateConstruction(value))
            {
                return(null);
            }
            var targetMethod = ((IInstructionWithMethodOperand)value.Arguments[1]).Method;

            if (IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod))
            {
                target = value.Arguments[0];
                var methodDefinition = (Mono.Cecil.MethodDefinition)context.TypeSystem.GetCecil(targetMethod);
                var localTypeSystem  = context.TypeSystem.GetSpecializingTypeSystem(new SimpleTypeResolveContext(targetMethod));
                var ilReader         = new ILReader(localTypeSystem);
                ilReader.UseDebugSymbols = context.Settings.UseDebugSymbols;
                var function = ilReader.ReadIL(methodDefinition.Body, context.CancellationToken);
                function.DelegateType = value.Method.DeclaringType;
                function.CheckInvariant(ILPhase.Normal);

                var contextPrefix = targetMethod.Name;
                foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter))
                {
                    v.Name = contextPrefix + v.Name;
                }

                var nestedContext = new ILTransformContext(function, localTypeSystem, context.Settings)
                {
                    CancellationToken = context.CancellationToken
                };
                function.RunTransforms(CSharpDecompiler.GetILTransforms().TakeWhile(t => !(t is DelegateConstruction)), nestedContext);
                function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter)));
                // handle nested lambdas
                ((IILTransform) new DelegateConstruction()).Run(function, nestedContext);
                function.AddILRange(target.ILRange);
                function.AddILRange(value.Arguments[1].ILRange);
                return(function);
            }
            return(null);
        }
Ejemplo n.º 4
0
        bool LookaheadExpressionFieldConstant(bool isDup, ref ILReader reader, out MetadataToken?fieldToken)
        {
            fieldToken = null;
            var fork = reader.Clone();

            if (//Expression.Constant(typeof(<>__DisplayClass>), c)
                (isDup || fork.TryGet(OpCodes.Ldloc, 0) != null) &&
                fork.TryGet(OpCodes.Ldtoken) != null &&
                fork.TryGetCall(nameof(Type.GetTypeFromHandle)) != null &&
                fork.TryGetCall(nameof(Expression.Constant)) != null &&
                //Expression.Field( , fieldof(c.a));
                fork.TryGet(OpCodes.Ldtoken) is Instruction ldtoken &&
                fork.TryGetCall(nameof(System.Reflection.FieldInfo.GetFieldFromHandle)) != null &&
                fork.TryGetCall(nameof(Expression.Field)) != null)
            {
                fieldToken      = ((FieldReference)ldtoken.Operand).MetadataToken;
                reader.Position = fork.Position;
                return(true);
            }

            return(false);
        }
Ejemplo n.º 5
0
        public void Write(ArraySegment <Byte> segment, String outputPath, UInt16 expectedVersion)
        {
            using (MemoryStream sourceFile = new MemoryStream(segment.Array, 0, segment.Count))
                using (StreamWriter outputFile = File.CreateText(outputPath))
                {
                    ILReader   reader = new ILReader(sourceFile, expectedVersion);
                    String[][] lines  = reader.ReadLines();

                    for (var i = 0; i < lines.Length; i++)
                    {
                        outputFile.WriteLine($"{i:D4}:");

                        String[] entries = lines[i];
                        foreach (String line in entries)
                        {
                            outputFile.WriteLine(line);
                        }

                        outputFile.WriteLine();
                    }
                }
        }
Ejemplo n.º 6
0
        public static MethodDefinition Wrap(ReflectionNET.MethodInfo methodInfo)
        {
            var methodName = new MethodName(methodInfo.Name);
            var builder    = new MethodBuilder(methodName);

            var generator = builder.GetGenerator();

            foreach (var local in methodInfo.GetMethodBody().LocalVariables)
            {
                generator.DeclareLocal(local.LocalType);
            }

            var instructions = new ILReader(methodInfo).Instructions;
            var modifyWriter = new StringModifyWriter(generator);

            foreach (var instr in instructions)
            {
                modifyWriter.Write(instr);
            }
            //ILInstructionWriter.WriteIL(instructions, generator);
            return(builder.CreateMethodDefinition());
        }
Ejemplo n.º 7
0
    private static MemberInfo MemberOf(Delegate action, params OpCode[] ops)
    {
        MemberInfo info = null;

        if (cache.TryGetValue(action.Method.MethodHandle, out info))
        {
            return(info);
        }

        ILReader reader = new ILReader(action.Method);

        foreach (ILInstruction instruction in reader.Instructions)
        {
            if (ops.Any(x => x == instruction.Op))
            {
                info = instruction.Data as MemberInfo;
                cache[action.Method.MethodHandle] = info;
                return(info);
            }
        }

        throw new InvalidOperationException("Did not find a member.");
    }
Ejemplo n.º 8
0
        public void TestStackAnalysis(Type aType, string aMethodName, Type[] aArgs)
        {
            if (aArgs is null)
            {
                aArgs = Array.Empty <Type>();
            }
            var method     = aType.GetMethod(aMethodName, 0, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, aArgs, null);
            var methodBase = new _MethodInfo(method, 1, _MethodInfo.TypeEnum.Normal, null);

            var appAssembler = new AppAssembler(null, new VoidTextWriter(), "")
            {
                DebugMode = Cosmos.Build.Common.DebugMode.None
            };

            var ilReader = new ILReader();
            var opCodes  = ilReader.ProcessMethod(method);

            var mSequence = appAssembler.GenerateDebugSequencePoints(methodBase, Cosmos.Build.Common.DebugMode.None);

            var iMethod = new ILMethod(opCodes, mSequence);

            Assert.DoesNotThrow(() => iMethod.Analyse());
        }
Ejemplo n.º 9
0
    public unsafe void DeconstructOpcodes3()
    {
        var gen = CreateGenerator();

        var l1 = gen.DefineLabel();
        var l2 = gen.DefineLabel();

        gen.Emit(OpCodes.ADD);
        gen.Emit(OpCodes.LDC_I4_S, 228);
        gen.Emit(OpCodes.ADD);
        gen.Emit(OpCodes.JMP_HQ, l2);
        gen.Emit(OpCodes.LDC_I4_S, 228);
        gen.Emit(OpCodes.ADD);
        gen.Emit(OpCodes.LDC_I4_S, 228);
        gen.Emit(OpCodes.LDC_I4_S, 228);
        gen.Emit(OpCodes.ADD);
        gen.Emit(OpCodes.JMP_HQ, l1);
        gen.UseLabel(l1);
        gen.Emit(OpCodes.SUB);
        gen.Emit(OpCodes.SUB);
        gen.UseLabel(l2);
        gen.Emit(OpCodes.SUB);
        gen.Emit(OpCodes.SUB);
        var offset = 0;
        var body   = gen.BakeByteArray();

        var(result, map) = ILReader.Deconstruct(body, &offset, null);
        var labels = ILReader.DeconstructLabels(body, &offset);

        var first_label = result[map[labels[0]].pos];

        Assert.AreEqual(first_label, OpCodes.SUB.Value);
        //Assert.AreEqual(second_label, OpCodes.SUB.Value);
        Assert.AreEqual(OpCodes.ADD.Value, result[0]);
        Assert.AreEqual(OpCodes.LDC_I4_S.Value, result[1]);
        Assert.AreEqual((uint)228, result[2]);
    }
Ejemplo n.º 10
0
        public static HashSet <int> ComputeBranchTargets(this MethodIL methodBody)
        {
            HashSet <int> branchTargets = new HashSet <int>();
            var           reader        = new ILReader(methodBody.GetILBytes());

            while (reader.HasNext)
            {
                ILOpcode opcode = reader.ReadILOpcode();
                if (opcode >= ILOpcode.br_s && opcode <= ILOpcode.blt_un)
                {
                    branchTargets.Add(reader.ReadBranchDestination(opcode));
                }
                else if (opcode == ILOpcode.switch_)
                {
                    uint count   = reader.ReadILUInt32();
                    int  jmpBase = reader.Offset + (int)(4 * count);
                    for (uint i = 0; i < count; i++)
                    {
                        branchTargets.Add((int)reader.ReadILUInt32() + jmpBase);
                    }
                }
                else
                {
                    reader.Skip(opcode);
                }
            }
            foreach (ILExceptionRegion einfo in methodBody.GetExceptionRegions())
            {
                if (einfo.Kind == ILExceptionRegionKind.Filter)
                {
                    branchTargets.Add(einfo.FilterOffset);
                }
                branchTargets.Add(einfo.HandlerOffset);
            }
            return(branchTargets);
        }
Ejemplo n.º 11
0
        public void TestGenerateGroups(Type aType, string aMethodName, int aExpectedGroups, Type[] aArgs)
        {
            if (aArgs is null)
            {
                aArgs = Array.Empty <Type>();
            }
            var method     = aType.GetMethod(aMethodName, 0, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, aArgs, null);
            var methodBase = new _MethodInfo(method, 1, _MethodInfo.TypeEnum.Normal, null);

            var appAssembler = new AppAssembler(null, new VoidTextWriter(), "")
            {
                DebugMode = Cosmos.Build.Common.DebugMode.None
            };

            var ilReader = new ILReader();
            var opCodes  = ilReader.ProcessMethod(method);

            var mSequence = appAssembler.GenerateDebugSequencePoints(methodBase, Cosmos.Build.Common.DebugMode.None);

            var iMethod = new ILMethod(opCodes, mSequence);
            var groups  = ILGroup.GenerateGroups(iMethod, mSequence);

            Assert.AreEqual(aExpectedGroups, groups.Count);
        }
Ejemplo n.º 12
0
        public static FlowGraph Create(MethodIL il)
        {
            HashSet <int> bbStarts = GetBasicBlockStarts(il);

            List <BasicBlock> bbs = new List <BasicBlock>();

            void AddBB(int start, int count)
            {
                if (count > 0)
                {
                    bbs.Add(new BasicBlock(start, count));
                }
            }

            int prevStart = 0;

            foreach (int ofs in bbStarts.OrderBy(o => o))
            {
                AddBB(prevStart, ofs - prevStart);
                prevStart = ofs;
            }

            AddBB(prevStart, il.GetILBytes().Length - prevStart);

            FlowGraph fg = new FlowGraph(bbs);

            // We know where each basic block starts now. Proceed by linking them together.
            ILReader reader = new ILReader(il.GetILBytes());

            foreach (BasicBlock bb in bbs)
            {
                reader.Seek(bb.Start);
                while (reader.HasNext)
                {
                    Debug.Assert(fg.Lookup(reader.Offset) == bb);
                    ILOpcode opc = reader.ReadILOpcode();
                    if (opc.IsBranch())
                    {
                        int tar = reader.ReadBranchDestination(opc);
                        bb.Targets.Add(fg.Lookup(tar));
                        if (!opc.IsUnconditionalBranch())
                        {
                            bb.Targets.Add(fg.Lookup(reader.Offset));
                        }

                        break;
                    }

                    if (opc == ILOpcode.switch_)
                    {
                        uint numCases = reader.ReadILUInt32();
                        int  jmpBase  = reader.Offset + checked ((int)(numCases * 4));
                        bb.Targets.Add(fg.Lookup(jmpBase));

                        for (uint i = 0; i < numCases; i++)
                        {
                            int caseOfs = jmpBase + (int)reader.ReadILUInt32();
                            bb.Targets.Add(fg.Lookup(caseOfs));
                        }

                        break;
                    }

                    if (opc == ILOpcode.ret || opc == ILOpcode.endfinally || opc == ILOpcode.endfilter || opc == ILOpcode.throw_ || opc == ILOpcode.rethrow)
                    {
                        break;
                    }

                    reader.Skip(opc);
                    // Check fall through
                    if (reader.HasNext)
                    {
                        BasicBlock nextBB = fg.Lookup(reader.Offset);
                        if (nextBB != bb)
                        {
                            // Falling through
                            bb.Targets.Add(nextBB);
                            break;
                        }
                    }
                }
            }

            foreach (BasicBlock bb in bbs)
            {
                foreach (BasicBlock tar in bb.Targets)
                {
                    tar.Sources.Add(bb);
                }
            }

            return(fg);
        }
Ejemplo n.º 13
0
    public static void GetAllExceptions(MethodBase method, HashSet <Type> exceptionTypes,
                                        HashSet <MethodBase> visitedMethods, Type[] localVars, Stack <Type> stack, int depth)
    {
        var ilReader        = new ILReader(method);
        var allInstructions = ilReader.ToArray();

        ILInstruction instruction;

        for (int i = 0; i < allInstructions.Length; i++)
        {
            instruction = allInstructions[i];
            if (instruction is InlineMethodInstruction)
            {
                var methodInstruction = (InlineMethodInstruction)instruction;

                if (!visitedMethods.Contains(methodInstruction.Method))
                {
                    visitedMethods.Add(methodInstruction.Method);
                    GetAllExceptions(methodInstruction.Method, exceptionTypes, visitedMethods,
                                     localVars, stack, depth + 1);
                }

                var curMethod = methodInstruction.Method;
                if (curMethod is ConstructorInfo)
                {
                    stack.Push(((ConstructorInfo)curMethod).DeclaringType);
                }
                else if (method is MethodInfo)
                {
                    stack.Push(((MethodInfo)curMethod).ReturnParameter.ParameterType);
                }
            }
            else if (instruction is InlineFieldInstruction)
            {
                var fieldInstruction = (InlineFieldInstruction)instruction;
                stack.Push(fieldInstruction.Field.FieldType);
            }
            else if (instruction is ShortInlineBrTargetInstruction)
            {
            }
            else if (instruction is InlineBrTargetInstruction)
            {
            }
            else
            {
                switch (instruction.OpCode.Value)
                {
                // ld*
                case 0x06:
                    stack.Push(localVars[0]);
                    break;

                case 0x07:
                    stack.Push(localVars[1]);
                    break;

                case 0x08:
                    stack.Push(localVars[2]);
                    break;

                case 0x09:
                    stack.Push(localVars[3]);
                    break;

                case 0x11:
                {
                    var index = (ushort)allInstructions[i + 1].OpCode.Value;
                    stack.Push(localVars[index]);
                    break;
                }

                // st*
                case 0x0A:
                    localVars[0] = stack.Pop();
                    break;

                case 0x0B:
                    localVars[1] = stack.Pop();
                    break;

                case 0x0C:
                    localVars[2] = stack.Pop();
                    break;

                case 0x0D:
                    localVars[3] = stack.Pop();
                    break;

                case 0x13:
                {
                    var index = (ushort)allInstructions[i + 1].OpCode.Value;
                    localVars[index] = stack.Pop();
                    break;
                }

                // throw
                case 0x7A:
                    if (stack.Peek() == null)
                    {
                        break;
                    }
                    if (!typeof(Exception).IsAssignableFrom(stack.Peek()))
                    {
                        //var ops = allInstructions.Select(f => f.OpCode).ToArray();
                        //break;
                    }
                    exceptionTypes.Add(stack.Pop());
                    break;

                default:
                    switch (instruction.OpCode.StackBehaviourPop)
                    {
                    case StackBehaviour.Pop0:
                        break;

                    case StackBehaviour.Pop1:
                    case StackBehaviour.Popi:
                    case StackBehaviour.Popref:
                    case StackBehaviour.Varpop:
                        stack.Pop();
                        break;

                    case StackBehaviour.Pop1_pop1:
                    case StackBehaviour.Popi_pop1:
                    case StackBehaviour.Popi_popi:
                    case StackBehaviour.Popi_popi8:
                    case StackBehaviour.Popi_popr4:
                    case StackBehaviour.Popi_popr8:
                    case StackBehaviour.Popref_pop1:
                    case StackBehaviour.Popref_popi:
                        stack.Pop();
                        stack.Pop();
                        break;

                    case StackBehaviour.Popref_popi_pop1:
                    case StackBehaviour.Popref_popi_popi:
                    case StackBehaviour.Popref_popi_popi8:
                    case StackBehaviour.Popref_popi_popr4:
                    case StackBehaviour.Popref_popi_popr8:
                    case StackBehaviour.Popref_popi_popref:
                        stack.Pop();
                        stack.Pop();
                        stack.Pop();
                        break;
                    }

                    switch (instruction.OpCode.StackBehaviourPush)
                    {
                    case StackBehaviour.Push0:
                        break;

                    case StackBehaviour.Push1:
                    case StackBehaviour.Pushi:
                    case StackBehaviour.Pushi8:
                    case StackBehaviour.Pushr4:
                    case StackBehaviour.Pushr8:
                    case StackBehaviour.Pushref:
                    case StackBehaviour.Varpush:
                        stack.Push(null);
                        break;

                    case StackBehaviour.Push1_push1:
                        stack.Push(null);
                        stack.Push(null);
                        break;
                    }

                    break;
                }
            }
        }
    }
Ejemplo n.º 14
0
        public static void Scan(ref DependencyList list, NodeFactory factory, MethodIL methodIL, ScanModes modes)
        {
            ILReader reader = new ILReader(methodIL.GetILBytes());

            Tracker tracker = new Tracker(methodIL);

            // The algorithm here is really primitive: we scan the IL forward in a single pass, remembering
            // the last type/string/token we saw.
            //
            // We then intrinsically recognize a couple methods that consume this information.
            //
            // This has obvious problems since we don't have exact knowledge of the parameters passed
            // (something being in front of a call doesn't mean it's a parameter to the call). But since
            // this is a heuristic, it's okay. We want this to be as fast as possible.
            //
            // The main purposes of this scanner is to make following patterns work:
            //
            // * Enum.GetValues(typeof(Foo)) - this is very common and we need to make sure Foo[] is compiled.
            // * Type.GetType("Foo, Bar").GetMethod("Blah") - framework uses this to work around layering problems.
            // * typeof(Foo<>).MakeGenericType(arg).GetMethod("Blah") - used in e.g. LINQ expressions implementation
            // * typeof(Foo<>).GetProperty("Blah") - used in e.g. LINQ expressions implementation
            // * Marshal.SizeOf(typeof(Foo)) - very common and we need to make sure interop data is generated

            while (reader.HasNext)
            {
                ILOpcode opcode = reader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldstr:
                    tracker.TrackStringToken(reader.ReadILToken());
                    break;

                case ILOpcode.ldtoken:
                    int token = reader.ReadILToken();
                    if (IsTypeEqualityTest(methodIL, reader, out ILReader newReader))
                    {
                        reader = newReader;
                    }
                    else
                    {
                        tracker.TrackLdTokenToken(token);
                        TypeDesc type = methodIL.GetObject(token) as TypeDesc;
                        if (type != null && !type.IsCanonicalSubtype(CanonicalFormKind.Any))
                        {
                            list = list ?? new DependencyList();
                            list.Add(factory.MaximallyConstructableType(type), "Unknown LDTOKEN use");
                        }
                    }

                    break;

                case ILOpcode.call:
                case ILOpcode.callvirt:
                    var method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
                    if (method != null)
                    {
                        HandleCall(ref list, factory, methodIL, method, ref tracker, modes);
                    }
                    break;

                default:
                    reader.Skip(opcode);
                    break;
                }
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Parse MIbcGroup method and return enumerable of MethodProfileData
        ///
        /// Like the AssemblyDictionary method, data is encoded via IL instructions. The format is
        ///
        /// ldtoken methodInProfileData
        /// Any series of instructions that does not include pop. Expansion data is encoded via ldstr "id"
        /// followed by a expansion specific sequence of il opcodes.
        /// pop
        /// {Repeat N times for N methods described}
        ///
        /// Extensions supported with current parser:
        ///
        /// ldstr "ExclusiveWeight"
        /// Any ldc.i4 or ldc.r4 or ldc.r8 instruction to indicate the exclusive weight
        ///
        /// ldstr "WeightedCallData"
        /// ldc.i4 <Count of methods called>
        /// Repeat <Count of methods called times>
        ///  ldtoken <Method called from this method>
        ///  ldc.i4 <Weight associated with calling the <Method called from this method>>
        ///
        /// This format is designed to be extensible to hold more data as we add new per method profile data without breaking existing parsers.
        /// </summary>
        static IEnumerable <MethodProfileData> ReadMIbcGroup(TypeSystemContext tsc, EcmaMethod method)
        {
            EcmaMethodIL             ilBody           = EcmaMethodIL.Create(method);
            MetadataLoaderForPgoData metadataLoader   = new MetadataLoaderForPgoData(ilBody);
            ILReader            ilReader              = new ILReader(ilBody.GetILBytes());
            object              methodInProgress      = null;
            object              metadataNotResolvable = new object();
            object              metadataObject        = null;
            MibcGroupParseState state            = MibcGroupParseState.LookingForNextMethod;
            int    intValue                      = 0;
            int    weightedCallGraphSize         = 0;
            int    profileEntryFound             = 0;
            double exclusiveWeight               = 0;
            Dictionary <MethodDesc, int> weights = null;
            bool        processIntValue          = false;
            List <long> instrumentationDataLongs = null;

            PgoSchemaElem[] pgoSchemaData = null;

            while (ilReader.HasNext)
            {
                ILOpcode opcode = ilReader.ReadILOpcode();
                processIntValue = false;
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                {
                    int token = ilReader.ReadILToken();
                    if (state == MibcGroupParseState.ProcessingInstrumentationData)
                    {
                        instrumentationDataLongs.Add(token);
                    }
                    else
                    {
                        metadataObject = null;
                        try
                        {
                            metadataObject = ilBody.GetObject(token);
                        }
                        catch (TypeSystemException)
                        {
                            // The method being referred to may be missing. In that situation,
                            // use the metadataNotResolvable sentinel to indicate that this record should be ignored
                            metadataObject = metadataNotResolvable;
                        }
                        switch (state)
                        {
                        case MibcGroupParseState.ProcessingCallgraphToken:
                            state = MibcGroupParseState.ProcessingCallgraphWeight;
                            break;

                        case MibcGroupParseState.LookingForNextMethod:
                            methodInProgress = metadataObject;
                            state            = MibcGroupParseState.LookingForOptionalData;
                            break;

                        default:
                            state = MibcGroupParseState.LookingForOptionalData;
                            break;
                        }
                    }
                }
                break;

                case ILOpcode.ldc_r4:
                {
                    float fltValue = ilReader.ReadILFloat();

                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = fltValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }

                    break;
                }

                case ILOpcode.ldc_r8:
                {
                    double dblValue = ilReader.ReadILDouble();

                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = dblValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }
                    break;
                }

                case ILOpcode.ldc_i4_0:
                    intValue        = 0;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_1:
                    intValue        = 1;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_2:
                    intValue        = 2;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_3:
                    intValue        = 3;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_4:
                    intValue        = 4;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_5:
                    intValue        = 5;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_6:
                    intValue        = 6;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_7:
                    intValue        = 7;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_8:
                    intValue        = 8;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_m1:
                    intValue        = -1;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_s:
                    intValue        = (sbyte)ilReader.ReadILByte();
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4:
                    intValue        = (int)ilReader.ReadILUInt32();
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i8:
                    if (state == MibcGroupParseState.ProcessingInstrumentationData)
                    {
                        instrumentationDataLongs.Add((long)ilReader.ReadILUInt64());
                    }
                    break;

                case ILOpcode.ldstr:
                {
                    int    userStringToken  = ilReader.ReadILToken();
                    string optionalDataName = (string)ilBody.GetObject(userStringToken);
                    switch (optionalDataName)
                    {
                    case "ExclusiveWeight":
                        state = MibcGroupParseState.ProcessingExclusiveWeight;
                        break;

                    case "WeightedCallData":
                        state = MibcGroupParseState.ProcessingCallgraphCount;
                        break;

                    case "InstrumentationDataStart":
                        state = MibcGroupParseState.ProcessingInstrumentationData;
                        instrumentationDataLongs = new List <long>();
                        break;

                    case "InstrumentationDataEnd":
                        if (instrumentationDataLongs != null)
                        {
                            instrumentationDataLongs.Add(2);             // MarshalMask 2 (Type)
                            instrumentationDataLongs.Add(0);             // PgoInstrumentationKind.Done (0)
                            pgoSchemaData = PgoProcessor.ParsePgoData <TypeSystemEntityOrUnknown>(metadataLoader, instrumentationDataLongs, false).ToArray();
                        }
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }
                }
                break;

                case ILOpcode.pop:
                    if (methodInProgress != metadataNotResolvable)
                    {
                        profileEntryFound++;
                        if (exclusiveWeight == 0)
                        {
                            // If no exclusive weight is found assign a non zero value that assumes the order in the pgo file is significant.
                            exclusiveWeight = Math.Min(1000000.0 - profileEntryFound, 0.0) / 1000000.0;
                        }
                        MethodProfileData mibcData = new MethodProfileData((MethodDesc)methodInProgress, MethodProfilingDataFlags.ReadMethodCode, exclusiveWeight, weights, 0xFFFFFFFF, pgoSchemaData);
                        state                    = MibcGroupParseState.LookingForNextMethod;
                        exclusiveWeight          = 0;
                        weights                  = null;
                        instrumentationDataLongs = null;
                        pgoSchemaData            = null;
                        yield return(mibcData);
                    }
                    methodInProgress = null;
                    break;

                default:
                    state = MibcGroupParseState.LookingForOptionalData;
                    ilReader.Skip(opcode);
                    break;
                }

                if (processIntValue)
                {
                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = intValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    case MibcGroupParseState.ProcessingCallgraphCount:
                        weightedCallGraphSize = intValue;
                        weights = new Dictionary <MethodDesc, int>();
                        if (weightedCallGraphSize > 0)
                        {
                            state = MibcGroupParseState.ProcessingCallgraphToken;
                        }
                        else
                        {
                            state = MibcGroupParseState.LookingForOptionalData;
                        }
                        break;

                    case MibcGroupParseState.ProcessingCallgraphWeight:
                        if (metadataObject != metadataNotResolvable)
                        {
                            weights.Add((MethodDesc)metadataObject, intValue);
                        }
                        weightedCallGraphSize--;
                        if (weightedCallGraphSize > 0)
                        {
                            state = MibcGroupParseState.ProcessingCallgraphToken;
                        }
                        else
                        {
                            state = MibcGroupParseState.LookingForOptionalData;
                        }
                        break;

                    case MibcGroupParseState.ProcessingInstrumentationData:
                        instrumentationDataLongs.Add(intValue);
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        instrumentationDataLongs = null;
                        break;
                    }
                }
            }
        }
Ejemplo n.º 16
0
        public void Run(ILFunction function, ILTransformContext context)
        {
            this.context = context;
            foreach (var inst in function.Descendants.OfType <CallInstruction>())
            {
                MethodDefinition methodDef = context.TypeSystem.GetCecil(inst.Method) as MethodDefinition;
                if (methodDef != null && methodDef.Body != null)
                {
                    if (IsDefinedInCurrentOrOuterClass(inst.Method, context.Function.Method.DeclaringTypeDefinition) && inst.Method.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
                    {
                        // partially copied from CSharpDecompiler
                        var specializingTypeSystem = this.context.TypeSystem.GetSpecializingTypeSystem(inst.Method.Substitution);
                        var ilReader = new ILReader(specializingTypeSystem);
                        System.Threading.CancellationToken cancellationToken = new System.Threading.CancellationToken();
                        var proxyFunction    = ilReader.ReadIL(methodDef.Body, cancellationToken);
                        var transformContext = new ILTransformContext(proxyFunction, specializingTypeSystem, this.context.Settings)
                        {
                            CancellationToken = cancellationToken,
                            DecompileRun      = context.DecompileRun
                        };
                        foreach (var transform in CSharp.CSharpDecompiler.GetILTransforms())
                        {
                            if (transform.GetType() != typeof(ProxyCallReplacer))                               // don't call itself on itself
                            {
                                cancellationToken.ThrowIfCancellationRequested();
                                transform.Run(proxyFunction, transformContext);
                            }
                        }

                        if (!(proxyFunction.Body is BlockContainer blockContainer))
                        {
                            return;
                        }
                        if (blockContainer.Blocks.Count != 1)
                        {
                            return;
                        }
                        var  block = blockContainer.Blocks[0];
                        Call call  = null;
                        if (block.Instructions.Count == 1)
                        {
                            // leave IL_0000 (call Test(ldloc this, ldloc A_1))
                            if (!block.Instructions[0].MatchLeave(blockContainer, out ILInstruction returnValue))
                            {
                                return;
                            }
                            call = returnValue as Call;
                        }
                        else if (block.Instructions.Count == 2)
                        {
                            // call Test(ldloc this, ldloc A_1)
                            // leave IL_0000(nop)
                            call = block.Instructions[0] as Call;
                            if (!block.Instructions[1].MatchLeave(blockContainer, out ILInstruction returnValue))
                            {
                                return;
                            }
                            if (!returnValue.MatchNop())
                            {
                                return;
                            }
                        }
                        if (call == null)
                        {
                            return;
                        }
                        if (call.Method.IsConstructor)
                        {
                            return;
                        }

                        // check if original arguments are only correct ldloc calls
                        for (int i = 0; i < call.Arguments.Count; i++)
                        {
                            var originalArg = call.Arguments[i];
                            if (!originalArg.MatchLdLoc(out ILVariable var) ||
                                var.Kind != VariableKind.Parameter ||
                                var.Index != i - 1)
                            {
                                return;
                            }
                        }

                        Call newInst = (Call)call.Clone();

                        newInst.Arguments.ReplaceList(inst.Arguments);
                        inst.ReplaceWith(newInst);
                    }
                }
            }
        }
Ejemplo n.º 17
0
        /// <summary>Checks the specified assemblies for any obvious Lingo-related problems, including unused strings, mismatched enum translations.</summary>
        /// <typeparam name="TTranslation">The type of the translation class.</typeparam>
        /// <param name="rep">Post-build step reporter.</param>
        /// <param name="assemblies">A list of assemblies to check. The Lingo assembly is included automatically to ensure correct operation.</param>
        public static void PostBuildStep <TTranslation>(IPostBuildReporter rep, params Assembly[] assemblies)
        {
            if (!assemblies.Contains(Assembly.GetExecutingAssembly()))
            {
                assemblies = assemblies.Concat(Assembly.GetExecutingAssembly()).ToArray();
            }

            // Check that all enum translations are sensible
            var allEnumTrs = allEnumTranslations(assemblies).ToList();

            foreach (var tr in allEnumTrs)
            {
                checkEnumTranslation(rep, tr.EnumType, tr.TranslationType);
            }

            // Check all component model member translations
            foreach (var type in assemblies.SelectMany(a => a.GetTypes()))
            {
                // All functions returning MemberTr and accepting a TranslationBase descendant must conform
                var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(p => p.Name).ToHashSet();
                foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
                {
                    if (method.ReturnType == typeof(MemberTr) && method.GetParameters().Length == 1 && typeof(TranslationBase).IsAssignableFrom(method.GetParameters()[0].ParameterType))
                    {
                        if (!method.IsStatic)
                        {
                            rep.Error("A member translation method must be static. Translation method: {0}".Fmt(method.DeclaringType.FullName + "." + method.Name), "class " + method.DeclaringType.Name, typeof(MemberTr).Name + " " + method.Name);
                        }
                        if (!method.Name.EndsWith("Tr"))
                        {
                            rep.Error("The name of a member translation method must end with the letters \"Tr\". Translation method: {0}".Fmt(method.DeclaringType.FullName + "." + method.Name), "class " + method.DeclaringType.Name, typeof(MemberTr).Name + " " + method.Name);
                        }
                        var propertyName = method.Name.Substring(0, method.Name.Length - 2);
                        if (!properties.Contains(propertyName))
                        {
                            rep.Error("Member translation method has no corresponding property named \"{1}\". Translation method: {0}".Fmt(method.DeclaringType.FullName + "." + method.Name, propertyName), "class " + method.DeclaringType.Name, typeof(MemberTr).Name + " " + method.Name);
                        }
                    }
                }
            }

            // Find unused strings
            var fields = new HashSet <FieldInfo>();

            addAllLingoRelevantFields(typeof(TTranslation), fields);

            // Treat all fields used for enum translations as used
            foreach (var f in allEnumTrs.SelectMany(et => et.TranslationType.GetAllFields()))
            {
                fields.Remove(f);
            }

            // Treat all fields that occur in a ldfld / ldflda instruction as used
            foreach (var mod in assemblies.SelectMany(a => a.GetModules(false)))
            {
                foreach (var typ in mod.GetTypes())
                {
                    foreach (var meth in
                             typ.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).Where(m => m.DeclaringType == typ).Cast <MethodBase>().Concat(
                                 typ.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).Where(c => c.DeclaringType == typ).Cast <MethodBase>()))
                    {
                        foreach (var instr in ILReader.ReadIL(meth, typ))
                        {
                            if (instr.OpCode == OpCodes.Ldfld || instr.OpCode == OpCodes.Ldflda)
                            {
                                fields.Remove((FieldInfo)instr.Operand);
                                if (fields.Count == 0)
                                {
                                    goto done; // don't have to break the loop early, but there's really no point in searching the rest of the code now
                                }
                            }
                        }
                    }
                }
            }

            // Report warnings for all unused strings (not errors so that the developer can test things in the presence of unused strings)
done:
            foreach (var field in fields)
            {
                rep.Warning("Unused Lingo field: " + field.DeclaringType.FullName + "." + field.Name, "class " + field.DeclaringType.Name, field.FieldType.Name, field.Name);
            }
        }
Ejemplo n.º 18
0
        private void Transform(ModuleDefinition mod, MethodDefinition method, MethodDefinition newMethod, FieldDefinition expressionField, out TypeDefinition closureType)
        {
            var writer = newMethod.Body.GetILProcessor();
            Dictionary <ParameterReference, VariableDefinition> oldParameterToNNewVariable = new Dictionary <ParameterReference, VariableDefinition>();

            newMethod.Body.InitLocals = true;
            writer.Emit(OpCodes.Nop);
            var allParameters = method.Parameters.ToList();

            if (method.Body.ThisParameter != null)
            {
                allParameters.Insert(0, method.Body.ThisParameter);
            }

            foreach (var p in allParameters)
            {
                var variable = new VariableDefinition(mod.ImportReference(ParameterExpression));
                newMethod.Body.Variables.Add(variable);
                writer.Emit(OpCodes.Ldtoken, p.ParameterType);
                writer.Emit(OpCodes.Call, mod.ImportReference(this.Type_GetTypeFromHandle));
                writer.Emit(OpCodes.Ldstr, p == method.Body.ThisParameter ? "this" : p.Name);
                writer.Emit(OpCodes.Call, mod.ImportReference(this.Expression_Parameter));
                writer.Emit(OpCodes.Stloc, variable.Index);
                oldParameterToNNewVariable.Add(p, variable);
            }

            method.Body.SimplifyMacros();
            var reader = new ILReader(method.Body);
            //var c = new <>__DisplayClass
            bool isDup = false;
            Dictionary <MetadataToken, ParameterReference> captureFieldToParameter = new Dictionary <MetadataToken, ParameterReference>();

            closureType = null;
            if (reader.Is(OpCodes.Newobj))
            {
                var newObj = reader.Get(OpCodes.Newobj);
                closureType = ((MethodDefinition)newObj.Operand).DeclaringType;
                if (reader.TryGet(OpCodes.Stloc) != null) //General case
                {
                    //c.a = a;
                    while (LookaheadClosureAssignment(isDup, ref reader, out var oldParameter, out var fieldReference))
                    {
                        captureFieldToParameter.Add(fieldReference.MetadataToken, oldParameter);
                    }
                }
                else if (reader.TryGet(OpCodes.Dup) != null) //only found for 1 parameter in release
                {
                    isDup = true;
                    if (!LookaheadClosureAssignment(isDup, ref reader, out var oldParameter, out var fieldReference))
                    {
                        throw new InvalidOperationException($"Not expected (in {method.FullName})");
                    }

                    captureFieldToParameter.Add(fieldReference.MetadataToken, oldParameter);
                }
            }

            Dictionary <VariableDefinition, VariableDefinition> rebasedVariables = new Dictionary <VariableDefinition, VariableDefinition>();

            foreach (var v in method.Body.Variables)
            {
                if (closureType != null && v.VariableType == closureType)
                {
                }
                else
                {
                    var newVariable = new VariableDefinition(mod.ImportReference(v.VariableType));
                    rebasedVariables.Add(v, newVariable);
                    newMethod.Body.Variables.Add(newVariable);
                }
            }

            while (reader.HasMore())
            {
                if (LookaheadExpressionFieldConstant(isDup, ref reader, out var token))
                {
                    var param = captureFieldToParameter[token.Value];
                    writer.Emit(OpCodes.Ldloc, oldParameterToNNewVariable[param].Index);
                }
                else if (!method.IsStatic && LookaheadExpressionThisConstant(ref reader, method.DeclaringType))
                {
                    writer.Emit(OpCodes.Ldloc, oldParameterToNNewVariable[method.Body.ThisParameter].Index);
                }
                else if (LookaheadArray(ref reader))
                {
                    if (reader.HasMore())
                    {
                        throw new InvalidOperationException($"The method {method.FullName} should only call As.Expression with an expression tree lambda");
                    }

                    if (oldParameterToNNewVariable.Count == 0)
                    {
                        writer.Emit(OpCodes.Call, mod.ImportReference(new GenericInstanceMethod(this.Array_Empty)
                        {
                            GenericArguments = { this.ParameterExpression }
                        }));
                    }
                    else
                    {
                        writer.Emit(OpCodes.Ldc_I4, oldParameterToNNewVariable.Count);
                        writer.Emit(OpCodes.Newarr, mod.ImportReference(this.ParameterExpression));
                        for (int i = 0; i < oldParameterToNNewVariable.Count; i++)
                        {
                            writer.Emit(OpCodes.Dup);
                            writer.Emit(OpCodes.Ldc_I4, i);
                            writer.Emit(OpCodes.Ldloc, i);
                            writer.Emit(OpCodes.Stelem_Ref);
                        }
                    }

                    var funcType = ((GenericInstanceType)expressionField.FieldType).GenericArguments.Single();
                    writer.Emit(OpCodes.Call, mod.ImportReference(new GenericInstanceMethod(this.Expression_Lambda)
                    {
                        GenericArguments = { funcType }
                    }));
                    writer.Emit(OpCodes.Stsfld, expressionField);
                    writer.Emit(OpCodes.Ret);
                    writer.Body.OptimizeMacros();


                    {
                        method.Body.Instructions.Clear();
                        method.Body.Variables.Clear();
                        var oldWriter = method.Body.GetILProcessor();
                        oldWriter.Emit(OpCodes.Ldsfld, expressionField);
                        for (int i = 0; i < allParameters.Count; i++)
                        {
                            oldWriter.Emit(OpCodes.Ldarg, allParameters[i]);
                        }

                        var evaluate         = ExpressionExtensions.Methods.Single(a => a.Name == "Evaluate" && a.GenericParameters.Count == allParameters.Count + 1);
                        var evaluateInstance = new GenericInstanceMethod(evaluate);
                        foreach (var p in allParameters)
                        {
                            evaluateInstance.GenericArguments.Add(p.ParameterType);
                        }
                        evaluateInstance.GenericArguments.Add(method.ReturnType);

                        oldWriter.Emit(OpCodes.Call, mod.ImportReference(evaluateInstance));
                        oldWriter.Emit(OpCodes.Ret);
                        oldWriter.Body.Optimize();
                    }
                    return;
                }
                else if (reader.TryGet(OpCodes.Ldloc) is Instruction ldloc)
                {
                    writer.Emit(ldloc.OpCode, rebasedVariables[(VariableDefinition)ldloc.Operand]);
                }
                else if (reader.TryGet(OpCodes.Stloc) is Instruction stloc)
                {
                    writer.Emit(stloc.OpCode, rebasedVariables[(VariableDefinition)stloc.Operand]);
                }
                else if (reader.TryGet(OpCodes.Ldloca) is Instruction ldloca)
                {
                    writer.Emit(ldloca.OpCode, rebasedVariables[(VariableDefinition)ldloca.Operand]);
                }
                else
                {
                    var ins = reader.Get();
                    writer.Append(ins);
                }
            }

            throw new InvalidOperationException($"The method {method.FullName} should only call As.Expression with an expression tree lambda");
        }
Ejemplo n.º 19
0
            private void WalkMethod(EcmaMethod method)
            {
                Instantiation typeContext   = method.OwningType.Instantiation;
                Instantiation methodContext = method.Instantiation;

                MethodSignature methodSig = method.Signature;

                ProcessTypeReference(methodSig.ReturnType, typeContext, methodContext);
                foreach (TypeDesc parameterType in methodSig)
                {
                    ProcessTypeReference(parameterType, typeContext, methodContext);
                }

                if (method.IsAbstract)
                {
                    return;
                }

                var methodIL = EcmaMethodIL.Create(method);

                if (methodIL == null)
                {
                    return;
                }

                // Walk the method body looking at referenced things that have some genericness.
                // Nongeneric things cannot be forming cycles.
                // In particular, we don't care about MemberRefs to non-generic things, TypeDefs/MethodDefs/FieldDefs.
                // Avoid the work to even materialize type system entities for those.

                ILReader reader = new ILReader(methodIL.GetILBytes());

                while (reader.HasNext)
                {
                    ILOpcode opcode = reader.ReadILOpcode();
                    switch (opcode)
                    {
                    case ILOpcode.sizeof_:
                    case ILOpcode.newarr:
                    case ILOpcode.initobj:
                    case ILOpcode.stelem:
                    case ILOpcode.ldelem:
                    case ILOpcode.ldelema:
                    case ILOpcode.box:
                    case ILOpcode.unbox:
                    case ILOpcode.unbox_any:
                    case ILOpcode.cpobj:
                    case ILOpcode.ldobj:
                    case ILOpcode.castclass:
                    case ILOpcode.isinst:
                    case ILOpcode.stobj:
                    case ILOpcode.refanyval:
                    case ILOpcode.mkrefany:
                    case ILOpcode.constrained:
                        EntityHandle accessedType = MetadataTokens.EntityHandle(reader.ReadILToken());
typeCase:
                        if (accessedType.Kind == HandleKind.TypeSpecification)
                        {
                            var t = methodIL.GetObject(MetadataTokens.GetToken(accessedType), NotFoundBehavior.ReturnNull) as TypeDesc;
                            if (t != null)
                            {
                                ProcessTypeReference(t, typeContext, methodContext);
                            }
                        }
                        break;

                    case ILOpcode.stsfld:
                    case ILOpcode.ldsfld:
                    case ILOpcode.ldsflda:
                    case ILOpcode.stfld:
                    case ILOpcode.ldfld:
                    case ILOpcode.ldflda:
                        EntityHandle accessedField = MetadataTokens.EntityHandle(reader.ReadILToken());
fieldCase:
                        if (accessedField.Kind == HandleKind.MemberReference)
                        {
                            accessedType = _metadataReader.GetMemberReference((MemberReferenceHandle)accessedField).Parent;
                            goto typeCase;
                        }
                        break;

                    case ILOpcode.call:
                    case ILOpcode.callvirt:
                    case ILOpcode.newobj:
                    case ILOpcode.ldftn:
                    case ILOpcode.ldvirtftn:
                    case ILOpcode.jmp:
                        EntityHandle accessedMethod = MetadataTokens.EntityHandle(reader.ReadILToken());
methodCase:
                        if (accessedMethod.Kind == HandleKind.MethodSpecification ||
                            (accessedMethod.Kind == HandleKind.MemberReference &&
                             _metadataReader.GetMemberReference((MemberReferenceHandle)accessedMethod).Parent.Kind == HandleKind.TypeSpecification))
                        {
                            var m = methodIL.GetObject(MetadataTokens.GetToken(accessedMethod), NotFoundBehavior.ReturnNull) as MethodDesc;
                            if (m != null)
                            {
                                ProcessTypeReference(m.OwningType, typeContext, methodContext);
                                ProcessMethodCall(m, typeContext, methodContext);
                            }
                        }
                        break;

                    case ILOpcode.ldtoken:
                        EntityHandle accessedEntity = MetadataTokens.EntityHandle(reader.ReadILToken());
                        if (accessedEntity.Kind == HandleKind.MethodSpecification ||
                            (accessedEntity.Kind == HandleKind.MemberReference && _metadataReader.GetMemberReference((MemberReferenceHandle)accessedEntity).GetKind() == MemberReferenceKind.Method))
                        {
                            accessedMethod = accessedEntity;
                            goto methodCase;
                        }
                        else if (accessedEntity.Kind == HandleKind.MemberReference)
                        {
                            accessedField = accessedEntity;
                            goto fieldCase;
                        }
                        else if (accessedEntity.Kind == HandleKind.TypeSpecification)
                        {
                            accessedType = accessedEntity;
                            goto typeCase;
                        }
                        break;

                    default:
                        reader.Skip(opcode);
                        break;
                    }
                }
            }
Ejemplo n.º 20
0
        public void Scan(MethodIL methodBody)
        {
            MethodDesc thisMethod = methodBody.OwningMethod;

            ValueBasicBlockPair[] locals = new ValueBasicBlockPair[methodBody.GetLocals().Length];

            Dictionary <int, Stack <StackSlot> > knownStacks = new Dictionary <int, Stack <StackSlot> >();
            Stack <StackSlot> currentStack = new Stack <StackSlot>(methodBody.MaxStack);

            ScanExceptionInformation(knownStacks, methodBody);

            BasicBlockIterator blockIterator = new BasicBlockIterator(methodBody);

            MethodReturnValue = null;
            ILReader reader = new ILReader(methodBody.GetILBytes());

            while (reader.HasNext)
            {
                int curBasicBlock = blockIterator.MoveNext(reader.Offset);

                if (knownStacks.ContainsKey(reader.Offset))
                {
                    if (currentStack == null)
                    {
                        // The stack copy constructor reverses the stack
                        currentStack = new Stack <StackSlot>(knownStacks[reader.Offset].Reverse());
                    }
                    else
                    {
                        currentStack = MergeStack(currentStack, knownStacks[reader.Offset]);
                    }
                }

                if (currentStack == null)
                {
                    currentStack = new Stack <StackSlot>(methodBody.MaxStack);
                }

                int      offset = reader.Offset;
                ILOpcode opcode = reader.ReadILOpcode();

                switch (opcode)
                {
                case ILOpcode.add:
                case ILOpcode.add_ovf:
                case ILOpcode.add_ovf_un:
                case ILOpcode.and:
                case ILOpcode.div:
                case ILOpcode.div_un:
                case ILOpcode.mul:
                case ILOpcode.mul_ovf:
                case ILOpcode.mul_ovf_un:
                case ILOpcode.or:
                case ILOpcode.rem:
                case ILOpcode.rem_un:
                case ILOpcode.sub:
                case ILOpcode.sub_ovf:
                case ILOpcode.sub_ovf_un:
                case ILOpcode.xor:
                case ILOpcode.cgt:
                case ILOpcode.cgt_un:
                case ILOpcode.clt:
                case ILOpcode.clt_un:
                case ILOpcode.shl:
                case ILOpcode.shr:
                case ILOpcode.shr_un:
                case ILOpcode.ceq:
                    PopUnknown(currentStack, 2, methodBody, offset);
                    PushUnknown(currentStack);
                    reader.Skip(opcode);
                    break;

                case ILOpcode.dup:
                    currentStack.Push(currentStack.Peek());
                    break;

                case ILOpcode.ldnull:
                    currentStack.Push(new StackSlot(NullValue.Instance));
                    break;


                case ILOpcode.ldc_i4_0:
                case ILOpcode.ldc_i4_1:
                case ILOpcode.ldc_i4_2:
                case ILOpcode.ldc_i4_3:
                case ILOpcode.ldc_i4_4:
                case ILOpcode.ldc_i4_5:
                case ILOpcode.ldc_i4_6:
                case ILOpcode.ldc_i4_7:
                case ILOpcode.ldc_i4_8:
                {
                    int           value = opcode - ILOpcode.ldc_i4_0;
                    ConstIntValue civ   = new ConstIntValue(value);
                    StackSlot     slot  = new StackSlot(civ);
                    currentStack.Push(slot);
                }
                break;

                case ILOpcode.ldc_i4_m1:
                {
                    ConstIntValue civ  = new ConstIntValue(-1);
                    StackSlot     slot = new StackSlot(civ);
                    currentStack.Push(slot);
                }
                break;

                case ILOpcode.ldc_i4:
                {
                    int           value = (int)reader.ReadILUInt32();
                    ConstIntValue civ   = new ConstIntValue(value);
                    StackSlot     slot  = new StackSlot(civ);
                    currentStack.Push(slot);
                }
                break;

                case ILOpcode.ldc_i4_s:
                {
                    int           value = (sbyte)reader.ReadILByte();
                    ConstIntValue civ   = new ConstIntValue(value);
                    StackSlot     slot  = new StackSlot(civ);
                    currentStack.Push(slot);
                }
                break;

                case ILOpcode.arglist:
                case ILOpcode.ldftn:
                case ILOpcode.sizeof_:
                case ILOpcode.ldc_i8:
                case ILOpcode.ldc_r4:
                case ILOpcode.ldc_r8:
                    PushUnknown(currentStack);
                    reader.Skip(opcode);
                    break;

                case ILOpcode.ldarg:
                case ILOpcode.ldarg_0:
                case ILOpcode.ldarg_1:
                case ILOpcode.ldarg_2:
                case ILOpcode.ldarg_3:
                case ILOpcode.ldarg_s:
                case ILOpcode.ldarga:
                case ILOpcode.ldarga_s:
                    ScanLdarg(opcode, opcode switch
                    {
                        ILOpcode.ldarg => reader.ReadILUInt16(),
                        ILOpcode.ldarga => reader.ReadILUInt16(),
                        ILOpcode.ldarg_s => reader.ReadILByte(),
                        ILOpcode.ldarga_s => reader.ReadILByte(),
                        _ => opcode - ILOpcode.ldarg_0
                    }, currentStack, thisMethod);
                    break;
Ejemplo n.º 21
0
            internal TypeCache(MetadataType type, Logger?logger, ILProvider ilProvider)
            {
                Debug.Assert(type == type.GetTypeDefinition());
                Debug.Assert(!CompilerGeneratedNames.IsGeneratedMemberName(type.Name));

                Type = type;

                var callGraph          = new CompilerGeneratedCallGraph();
                var userDefinedMethods = new HashSet <MethodDesc>();

                void ProcessMethod(MethodDesc method)
                {
                    Debug.Assert(method == method.GetTypicalMethodDefinition());

                    bool isStateMachineMember = CompilerGeneratedNames.IsStateMachineType(((MetadataType)method.OwningType).Name);

                    if (!CompilerGeneratedNames.IsLambdaOrLocalFunction(method.Name))
                    {
                        if (!isStateMachineMember)
                        {
                            // If it's not a nested function, track as an entry point to the call graph.
                            var added = userDefinedMethods.Add(method);
                            Debug.Assert(added);
                        }
                    }
                    else
                    {
                        // We don't expect lambdas or local functions to be emitted directly into
                        // state machine types.
                        Debug.Assert(!isStateMachineMember);
                    }

                    // Discover calls or references to lambdas or local functions. This includes
                    // calls to local functions, and lambda assignments (which use ldftn).
                    var methodBody = ilProvider.GetMethodIL(method);

                    if (methodBody != null)
                    {
                        ILReader reader = new ILReader(methodBody.GetILBytes());
                        while (reader.HasNext)
                        {
                            ILOpcode opcode = reader.ReadILOpcode();
                            switch (opcode)
                            {
                            case ILOpcode.ldftn:
                            case ILOpcode.ldtoken:
                            case ILOpcode.call:
                            case ILOpcode.callvirt:
                            case ILOpcode.newobj:
                            {
                                MethodDesc?referencedMethod = methodBody.GetObject(reader.ReadILToken(), NotFoundBehavior.ReturnNull) as MethodDesc;
                                if (referencedMethod == null)
                                {
                                    continue;
                                }

                                referencedMethod = referencedMethod.GetTypicalMethodDefinition();

                                if (referencedMethod.IsConstructor &&
                                    referencedMethod.OwningType is MetadataType generatedType &&
                                    // Don't consider calls in the same type, like inside a static constructor
                                    method.OwningType != generatedType &&
                                    CompilerGeneratedNames.IsLambdaDisplayClass(generatedType.Name))
                                {
                                    Debug.Assert(generatedType.IsTypeDefinition);

                                    // fill in null for now, attribute providers will be filled in later
                                    _generatedTypeToTypeArgumentInfo ??= new Dictionary <MetadataType, TypeArgumentInfo>();

                                    if (!_generatedTypeToTypeArgumentInfo.TryAdd(generatedType, new TypeArgumentInfo(method, null)))
                                    {
                                        var alreadyAssociatedMethod = _generatedTypeToTypeArgumentInfo[generatedType].CreatingMethod;
                                        logger?.LogWarning(new MessageOrigin(method), DiagnosticId.MethodsAreAssociatedWithUserMethod, method.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), generatedType.GetDisplayName());
                                    }
                                    continue;
                                }

                                if (!CompilerGeneratedNames.IsLambdaOrLocalFunction(referencedMethod.Name))
                                {
                                    continue;
                                }

                                if (isStateMachineMember)
                                {
                                    callGraph.TrackCall((MetadataType)method.OwningType, referencedMethod);
                                }
                                else
                                {
                                    callGraph.TrackCall(method, referencedMethod);
                                }
                            }
                            break;

                            case ILOpcode.stsfld:
                            {
                                // Same as above, but stsfld instead of a call to the constructor
                                FieldDesc?field = methodBody.GetObject(reader.ReadILToken()) as FieldDesc;
                                if (field == null)
                                {
                                    continue;
                                }

                                field = field.GetTypicalFieldDefinition();

                                if (field.OwningType is MetadataType generatedType &&
                                    // Don't consider field accesses in the same type, like inside a static constructor
                                    method.OwningType != generatedType &&
                                    CompilerGeneratedNames.IsLambdaDisplayClass(generatedType.Name))
                                {
                                    Debug.Assert(generatedType.IsTypeDefinition);

                                    _generatedTypeToTypeArgumentInfo ??= new Dictionary <MetadataType, TypeArgumentInfo>();

                                    if (!_generatedTypeToTypeArgumentInfo.TryAdd(generatedType, new TypeArgumentInfo(method, null)))
                                    {
                                        // It's expected that there may be multiple methods associated with the same static closure environment.
                                        // All of these methods will substitute the same type arguments into the closure environment
                                        // (if it is generic). Don't warn.
                                    }
                                    continue;
                                }
                            }
                            break;

                            default:
                                reader.Skip(opcode);
                                break;
                            }
                        }
                    }

                    if (TryGetStateMachineType(method, out MetadataType? stateMachineType))
                    {
                        Debug.Assert(stateMachineType.ContainingType == type ||
                                     (CompilerGeneratedNames.IsGeneratedMemberName(stateMachineType.ContainingType.Name) &&
                                      stateMachineType.ContainingType.ContainingType == type));
                        Debug.Assert(stateMachineType == stateMachineType.GetTypeDefinition());

                        callGraph.TrackCall(method, stateMachineType);

                        _compilerGeneratedTypeToUserCodeMethod ??= new Dictionary <MetadataType, MethodDesc>();
                        if (!_compilerGeneratedTypeToUserCodeMethod.TryAdd(stateMachineType, method))
                        {
                            var alreadyAssociatedMethod = _compilerGeneratedTypeToUserCodeMethod[stateMachineType];
                            logger?.LogWarning(new MessageOrigin(method), DiagnosticId.MethodsAreAssociatedWithStateMachine, method.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), stateMachineType.GetDisplayName());
                        }
                        // Already warned above if multiple methods map to the same type
                        // Fill in null for argument providers now, the real providers will be filled in later
                        _generatedTypeToTypeArgumentInfo ??= new Dictionary <MetadataType, TypeArgumentInfo>();
                        _generatedTypeToTypeArgumentInfo[stateMachineType] = new TypeArgumentInfo(method, null);
                    }
                }

                // Look for state machine methods, and methods which call local functions.
                foreach (MethodDesc method in type.GetMethods())
                {
                    ProcessMethod(method);
                }

                // Also scan compiler-generated state machine methods (in case they have calls to nested functions),
                // and nested functions inside compiler-generated closures (in case they call other nested functions).

                // State machines can be emitted into lambda display classes, so we need to go down at least two
                // levels to find calls from iterator nested functions to other nested functions. We just recurse into
                // all compiler-generated nested types to avoid depending on implementation details.

                foreach (var nestedType in GetCompilerGeneratedNestedTypes(type))
                {
                    foreach (var method in nestedType.GetMethods())
                    {
                        ProcessMethod(method);
                    }
                }

                // Now we've discovered the call graphs for calls to nested functions.
                // Use this to map back from nested functions to the declaring user methods.

                // Note: This maps all nested functions back to the user code, not to the immediately
                // declaring local function. The IL doesn't contain enough information in general for
                // us to determine the nesting of local functions and lambdas.

                // Note: this only discovers nested functions which are referenced from the user
                // code or its referenced nested functions. There is no reliable way to determine from
                // IL which user code an unused nested function belongs to.

                foreach (var userDefinedMethod in userDefinedMethods)
                {
                    var callees = callGraph.GetReachableMembers(userDefinedMethod);
                    if (!callees.Any())
                    {
                        continue;
                    }

                    _compilerGeneratedMembers ??= new Dictionary <MethodDesc, List <TypeSystemEntity> >();
                    _compilerGeneratedMembers.Add(userDefinedMethod, new List <TypeSystemEntity>(callees));

                    foreach (var compilerGeneratedMember in callees)
                    {
                        switch (compilerGeneratedMember)
                        {
                        case MethodDesc nestedFunction:
                            Debug.Assert(CompilerGeneratedNames.IsLambdaOrLocalFunction(nestedFunction.Name));
                            // Nested functions get suppressions from the user method only.
                            _compilerGeneratedMethodToUserCodeMethod ??= new Dictionary <MethodDesc, MethodDesc>();
                            if (!_compilerGeneratedMethodToUserCodeMethod.TryAdd(nestedFunction, userDefinedMethod))
                            {
                                var alreadyAssociatedMethod = _compilerGeneratedMethodToUserCodeMethod[nestedFunction];
                                logger?.LogWarning(new MessageOrigin(userDefinedMethod), DiagnosticId.MethodsAreAssociatedWithUserMethod, userDefinedMethod.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), nestedFunction.GetDisplayName());
                            }
                            break;

                        case MetadataType stateMachineType:
                            // Types in the call graph are always state machine types
                            // For those all their methods are not tracked explicitly in the call graph; instead, they
                            // are represented by the state machine type itself.
                            // We are already tracking the association of the state machine type to the user code method
                            // above, so no need to track it here.
                            Debug.Assert(CompilerGeneratedNames.IsStateMachineType(stateMachineType.Name));
                            break;

                        default:
                            throw new InvalidOperationException();
                        }
                    }
                }

                // Now that we have instantiating methods fully filled out, walk the generated types and fill in the attribute
                // providers
                if (_generatedTypeToTypeArgumentInfo != null)
                {
                    foreach (var generatedType in _generatedTypeToTypeArgumentInfo.Keys)
                    {
                        Debug.Assert(generatedType == generatedType.GetTypeDefinition());

                        if (HasGenericParameters(generatedType))
                        {
                            MapGeneratedTypeTypeParameters(generatedType);
                        }
                    }
                }
Ejemplo n.º 22
0
        private bool IsNonVersionableWithILTokensThatDoNotNeedTranslationUncached(EcmaMethod method)
        {
            bool result = false;

            try
            {
                // Validate that there are no tokens in the IL other than tokens associated with the following
                // instructions with the
                // 1. ldfld, ldflda, and stfld to instance fields of NonVersionable structs and NonVersionable classes
                // 2. cpobj, initobj, ldobj, stobj, ldelem, ldelema or sizeof, to NonVersionable structures, signature variables, pointers, function pointers, byrefs, classes, or arrays
                // 3. stelem, to NonVersionable structures
                // In addition, the method must not have any EH.
                // The method may only have locals which are NonVersionable structures, or classes

                MethodIL methodIL = new ReadyToRunILProvider().GetMethodIL(method);
                if (methodIL.GetExceptionRegions().Length > 0)
                {
                    return(false);
                }

                foreach (var local in methodIL.GetLocals())
                {
                    if (local.Type.IsPrimitive)
                    {
                        continue;
                    }

                    if (local.Type.IsArray)
                    {
                        continue;
                    }

                    if (local.Type.IsSignatureVariable)
                    {
                        continue;
                    }
                    MetadataType metadataType = local.Type as MetadataType;

                    if (metadataType == null)
                    {
                        return(false);
                    }

                    if (metadataType.IsValueType)
                    {
                        if (metadataType.IsNonVersionable())
                        {
                            continue;
                        }
                        else
                        {
                            return(false);
                        }
                    }
                }

                ILReader ilReader = new ILReader(methodIL.GetILBytes());
                while (ilReader.HasNext)
                {
                    ILOpcode opcode = ilReader.ReadILOpcode();
                    switch (opcode)
                    {
                    case ILOpcode.ldfld:
                    case ILOpcode.ldflda:
                    case ILOpcode.stfld:
                    {
                        int       token = ilReader.ReadILToken();
                        FieldDesc field = methodIL.GetObject(token) as FieldDesc;
                        if (field == null)
                        {
                            return(false);
                        }
                        if (field.IsStatic)
                        {
                            return(false);
                        }
                        MetadataType owningMetadataType = (MetadataType)field.OwningType;
                        if (!owningMetadataType.IsNonVersionable())
                        {
                            return(false);
                        }
                        break;
                    }

                    case ILOpcode.ldelem:
                    case ILOpcode.ldelema:
                    case ILOpcode.stobj:
                    case ILOpcode.ldobj:
                    case ILOpcode.initobj:
                    case ILOpcode.cpobj:
                    case ILOpcode.sizeof_:
                    {
                        int      token = ilReader.ReadILToken();
                        TypeDesc type  = methodIL.GetObject(token) as TypeDesc;
                        if (type == null)
                        {
                            return(false);
                        }

                        MetadataType metadataType = type as MetadataType;
                        if (metadataType == null)
                        {
                            continue;         // Types which are not metadata types are all well defined in size
                        }
                        if (!metadataType.IsValueType)
                        {
                            continue;         // Reference types are all well defined in size for the sizeof instruction
                        }
                        if (metadataType.IsNonVersionable())
                        {
                            continue;
                        }
                        return(false);
                    }

                    case ILOpcode.stelem:
                    {
                        int          token = ilReader.ReadILToken();
                        MetadataType type  = methodIL.GetObject(token) as MetadataType;
                        if (type == null)
                        {
                            return(false);
                        }

                        if (!type.IsValueType)
                        {
                            return(false);
                        }
                        if (!type.IsNonVersionable())
                        {
                            return(false);
                        }
                        break;
                    }

                    // IL instructions which refer to tokens which are not safe for NonVersionable methods
                    case ILOpcode.box:
                    case ILOpcode.call:
                    case ILOpcode.calli:
                    case ILOpcode.callvirt:
                    case ILOpcode.castclass:
                    case ILOpcode.jmp:
                    case ILOpcode.isinst:
                    case ILOpcode.ldstr:
                    case ILOpcode.ldsfld:
                    case ILOpcode.ldsflda:
                    case ILOpcode.ldtoken:
                    case ILOpcode.ldvirtftn:
                    case ILOpcode.ldftn:
                    case ILOpcode.mkrefany:
                    case ILOpcode.newarr:
                    case ILOpcode.newobj:
                    case ILOpcode.refanyval:
                    case ILOpcode.stsfld:
                    case ILOpcode.unbox:
                    case ILOpcode.unbox_any:
                    case ILOpcode.constrained:
                        return(false);

                    default:
                        // Unless its a opcode known to be permitted with a
                        ilReader.Skip(opcode);
                        break;
                    }
                }

                result = true;
            }
            catch (TypeSystemException)
            {
                return(false);
            }

            return(result);
        }
Ejemplo n.º 23
0
        public Dictionary <long, EventRegistration[]> DecompileEventMappings(string fullTypeName, CancellationToken cancellationToken)
        {
            var            result = new Dictionary <long, EventRegistration[]>();
            TypeDefinition type   = this.assembly.MainModule.GetType(fullTypeName);

            if (type == null)
            {
                return(result);
            }

            MethodDefinition method = null;

            foreach (var m in type.Methods)
            {
                if (m.Name == "System.Windows.Markup.IComponentConnector.Connect")
                {
                    method = m;
                    break;
                }
            }

            if (method == null)
            {
                return(result);
            }

            // decompile method and optimize the switch
            var typeSystem = new DecompilerTypeSystem(method.Module);
            var ilReader   = new ILReader(typeSystem);
            var function   = ilReader.ReadIL(method.Body, cancellationToken);

            var context = new ILTransformContext(function, typeSystem)
            {
                CancellationToken = cancellationToken
            };

            function.RunTransforms(CSharpDecompiler.GetILTransforms(), context);

            var block    = function.Body.Children.OfType <Block>().First();
            var ilSwitch = block.Children.OfType <SwitchInstruction>().FirstOrDefault();

            if (ilSwitch != null)
            {
                foreach (var section in ilSwitch.Sections)
                {
                    var events = FindEvents(section.Body);
                    foreach (long id in section.Labels.Values)
                    {
                        result.Add(id, events);
                    }
                }
            }
            else
            {
                foreach (var ifInst in function.Descendants.OfType <IfInstruction>())
                {
                    var comp = ifInst.Condition as Comp;
                    if (comp.Kind != ComparisonKind.Inequality && comp.Kind != ComparisonKind.Equality)
                    {
                        continue;
                    }
                    int id;
                    if (!comp.Right.MatchLdcI4(out id))
                    {
                        continue;
                    }
                    var events = FindEvents(comp.Kind == ComparisonKind.Inequality ? ifInst.FalseInst : ifInst.TrueInst);
                    result.Add(id, events);
                }
            }
            return(result);
        }
Ejemplo n.º 24
0
        public static void GetAllExceptions(MethodBase method, HashSet <Type> exceptionTypes,
                                            HashSet <MethodBase> visitedMethods, int depth)
        {
            var ilReader        = new ILReader(method);
            var allInstructions = ilReader.ToArray();

            var           localVars = new Type[255];
            var           stack     = new Stack <Type>();
            ILInstruction instruction;

            for (int i = 0; i < allInstructions.Length; i++)
            {
                instruction = allInstructions[i];
                if (instruction is InlineMethodInstruction)
                {
                    var methodInstruction = (InlineMethodInstruction)instruction;
                    var curMethod         = methodInstruction.Method;
                    if (curMethod is ConstructorInfo)
                    {
                        stack.Push(((ConstructorInfo)curMethod).DeclaringType);
                    }
                    else if (method is MethodInfo)
                    {
                        stack.Push(((MethodInfo)curMethod).ReturnParameter.ParameterType);
                    }

                    if (!visitedMethods.Contains(methodInstruction.Method))
                    {
                        visitedMethods.Add(methodInstruction.Method);
                        GetAllExceptions(methodInstruction.Method, exceptionTypes, visitedMethods,
                                         depth + 1);
                    }
                }
                else if (instruction is InlineFieldInstruction)
                {
                    var fieldInstruction = (InlineFieldInstruction)instruction;
                    stack.Push(fieldInstruction.Field.FieldType);
                }
                else if (instruction is ShortInlineBrTargetInstruction)
                {
                    //
                }
                else if (instruction is InlineBrTargetInstruction)
                {
                    //
                }
                else
                {
                    switch (instruction.OpCode.Value)
                    {
                    case 0x06:
                        stack.Push(localVars[0]);
                        break;

                    case 0x07:
                        stack.Push(localVars[1]);
                        break;

                    case 0x08:
                        stack.Push(localVars[2]);
                        break;

                    case 0x09:
                        stack.Push(localVars[3]);
                        break;

                    case 0x0A:
                        localVars[0] = stack.Pop();
                        break;

                    case 0x0B:
                        localVars[1] = stack.Pop();
                        break;

                    case 0x0C:
                        localVars[2] = stack.Pop();
                        break;

                    case 0x0D:
                        localVars[3] = stack.Pop();
                        break;

                    case 0x11:
                    {
                        int index = allInstructions[i + 1].OpCode.Value;
                        stack.Push(localVars[index]);
                        break;
                    }

                    case 0x13:
                    {
                        int index = allInstructions[i + 1].OpCode.Value;
                        localVars[index] = stack.Pop();
                        break;
                    }

                    case 0x7A:         // throw
                        exceptionTypes.Add(stack.Pop());
                        break;
                    }
                }
            }
        }
Ejemplo n.º 25
0
 public CallCollector(Mono.Cecil.ModuleDefinition module)
 {
     typeSystem = new DecompilerTypeSystem(module);
     ilReader   = new ILReader(typeSystem);
     decompiler = new CSharpDecompiler(typeSystem, new ICSharpCode.Decompiler.DecompilerSettings());
 }
Ejemplo n.º 26
0
        /// <summary>
        /// Parse an MIBC file for the methods that are interesting.
        /// The version bubble must be specified and will describe the restrict the set of methods parsed to those relevant to the compilation
        /// The onlyDefinedInAssembly parameter is used to restrict the set of types parsed to include only those which are defined in a specific module. Specify null to allow definitions from all modules.
        /// This limited parsing is not necessarily an exact set of prevention, so detailed algorithms that work at the individual method level are still necessary, but this allows avoiding excessive parsing.
        ///
        /// The format of the Mibc file is that of a .NET dll, with a global method named "AssemblyDictionary". Inside of that file are a series of references that are broken up by which assemblies define the individual methods.
        /// These references are encoded as IL code that represents the details.
        /// The format of these IL instruction is as follows.
        ///
        /// ldstr mibcGroupName
        /// ldtoken mibcGroupMethod
        /// pop
        /// {Repeat the above pattern N times, once per Mibc group}
        ///
        /// See comment above ReadMIbcGroup for details of the group format
        ///
        /// The mibcGroupName is in the following format "Assembly_{definingAssemblyName};{OtherAssemblyName};{OtherAssemblyName};...; (OtherAssemblyName is ; delimited)
        ///
        /// </summary>
        /// <returns></returns>
        public static ProfileData ParseMIbcFile(TypeSystemContext tsc, PEReader peReader, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly)
        {
            var mibcModule = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc));

            var assemblyDictionary = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod("AssemblyDictionary", null);
            IEnumerable <MethodProfileData> loadedMethodProfileData = Enumerable.Empty <MethodProfileData>();

            EcmaMethodIL ilBody   = EcmaMethodIL.Create(assemblyDictionary);
            ILReader     ilReader = new ILReader(ilBody.GetILBytes());

            string mibcGroupName = "";

            while (ilReader.HasNext)
            {
                ILOpcode opcode = ilReader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldstr:
                    int userStringToken = ilReader.ReadILToken();
                    Debug.Assert(mibcGroupName == "");
                    if (mibcGroupName == "")
                    {
                        mibcGroupName = (string)ilBody.GetObject(userStringToken);
                    }
                    break;

                case ILOpcode.ldtoken:
                    int token = ilReader.ReadILToken();

                    if (String.IsNullOrEmpty(mibcGroupName))
                    {
                        break;
                    }

                    string[] assembliesByName = mibcGroupName.Split(';');

                    bool hasMatchingDefinition = (onlyDefinedInAssembly == null) || assembliesByName[0].Equals(onlyDefinedInAssembly);

                    if (!hasMatchingDefinition)
                    {
                        break;
                    }

                    if (assemblyNamesInVersionBubble != null)
                    {
                        bool areAllEntriesInVersionBubble = true;
                        foreach (string s in assembliesByName)
                        {
                            if (string.IsNullOrEmpty(s))
                            {
                                continue;
                            }

                            if (!assemblyNamesInVersionBubble.Contains(s))
                            {
                                areAllEntriesInVersionBubble = false;
                                break;
                            }
                        }

                        if (!areAllEntriesInVersionBubble)
                        {
                            break;
                        }
                    }

                    loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject(token)));
                    break;

                case ILOpcode.pop:
                    mibcGroupName = "";
                    break;

                default:
                    ilReader.Skip(opcode);
                    break;
                }
            }

            return(new IBCProfileData(false, loadedMethodProfileData));
        }
Ejemplo n.º 27
0
        private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[] flags, int offset, int argIndex, out int constant)
        {
            if ((flags[offset] & OpcodeFlags.BasicBlockStart) != 0)
            {
                constant = 0;
                return(false);
            }

            for (int currentOffset = offset - 1; currentOffset >= 0; currentOffset--)
            {
                if ((flags[currentOffset] & OpcodeFlags.InstructionStart) == 0)
                {
                    continue;
                }

                ILReader reader = new ILReader(body, currentOffset);
                ILOpcode opcode = reader.ReadILOpcode();
                if (opcode == ILOpcode.call || opcode == ILOpcode.callvirt)
                {
                    MethodDesc method = (MethodDesc)methodIL.GetObject(reader.ReadILToken());
                    if (argIndex == 0)
                    {
                        BodySubstitution substitution = GetSubstitution(method);
                        if (substitution != null && substitution.Value is int &&
                            (opcode != ILOpcode.callvirt || !method.IsVirtual))
                        {
                            constant = (int)substitution.Value;
                            return(true);
                        }
                        else
                        {
                            constant = 0;
                            return(false);
                        }
                    }

                    argIndex--;

                    if (method.Signature.Length > 0 || !method.Signature.IsStatic)
                    {
                        // We don't know how to skip over the parameters
                        break;
                    }
                }
                else if (opcode == ILOpcode.ldsfld)
                {
                    FieldDesc field = (FieldDesc)methodIL.GetObject(reader.ReadILToken());
                    if (argIndex == 0)
                    {
                        object substitution = GetSubstitution(field);
                        if (substitution is int)
                        {
                            constant = (int)substitution;
                            return(true);
                        }
                        else
                        {
                            constant = 0;
                            return(false);
                        }
                    }

                    argIndex--;
                }
                else if (opcode >= ILOpcode.ldc_i4_0 && opcode <= ILOpcode.ldc_i4_8)
                {
                    if (argIndex == 0)
                    {
                        constant = opcode - ILOpcode.ldc_i4_0;
                        return(true);
                    }

                    argIndex--;
                }
                else if (opcode == ILOpcode.ldc_i4)
                {
                    if (argIndex == 0)
                    {
                        constant = (int)reader.ReadILUInt32();
                        return(true);
                    }

                    argIndex--;
                }
                else if (opcode == ILOpcode.ldc_i4_s)
                {
                    if (argIndex == 0)
                    {
                        constant = (int)(sbyte)reader.ReadILByte();
                        return(true);
                    }

                    argIndex--;
                }
                else if ((opcode == ILOpcode.ldloc || opcode == ILOpcode.ldloc_s ||
                          (opcode >= ILOpcode.ldloc_0 && opcode <= ILOpcode.ldloc_3)) &&
                         ((flags[currentOffset] & OpcodeFlags.BasicBlockStart) == 0))
                {
                    // Paired stloc/ldloc that the C# compiler generates in debug code?
                    int locIndex = opcode switch
                    {
                        ILOpcode.ldloc => reader.ReadILUInt16(),
                        ILOpcode.ldloc_s => reader.ReadILByte(),
                        _ => opcode - ILOpcode.ldloc_0,
                    };

                    for (int potentialStlocOffset = currentOffset - 1; potentialStlocOffset >= 0; potentialStlocOffset--)
                    {
                        if ((flags[potentialStlocOffset] & OpcodeFlags.InstructionStart) == 0)
                        {
                            continue;
                        }

                        ILReader nestedReader = new ILReader(body, potentialStlocOffset);
                        ILOpcode otherOpcode  = nestedReader.ReadILOpcode();
                        if ((otherOpcode == ILOpcode.stloc || otherOpcode == ILOpcode.stloc_s ||
                             (otherOpcode >= ILOpcode.stloc_0 && otherOpcode <= ILOpcode.stloc_3)) &&
                            otherOpcode switch
                        {
                            ILOpcode.stloc => nestedReader.ReadILUInt16(),
                            ILOpcode.stloc_s => nestedReader.ReadILByte(),
                            _ => otherOpcode - ILOpcode.stloc_0,
                        } == locIndex)
Ejemplo n.º 28
0
 public ILStreamReader(MethodIL methodIL)
 {
     _methodIL = methodIL;
     _reader   = new ILReader(methodIL.GetILBytes());
 }
Ejemplo n.º 29
0
            private void WalkMethod(EcmaMethod method)
            {
                Instantiation typeContext   = method.OwningType.Instantiation;
                Instantiation methodContext = method.Instantiation;

                MethodSignature methodSig = method.Signature;

                ProcessTypeReference(methodSig.ReturnType, typeContext, methodContext);
                foreach (TypeDesc parameterType in methodSig)
                {
                    ProcessTypeReference(parameterType, typeContext, methodContext);
                }

                if (method.IsAbstract)
                {
                    return;
                }

                var methodIL = EcmaMethodIL.Create(method);

                if (methodIL == null)
                {
                    return;
                }

                // If this is a generic virtual method, add an edge from each of the generic parameters
                // of the implementation to the generic parameters of the declaration - any call to the
                // declaration will be modeled as if the declaration was calling into the implementation.
                if (method.IsVirtual && method.HasInstantiation)
                {
                    var decl = (EcmaMethod)MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method).GetTypicalMethodDefinition();
                    if (decl != method)
                    {
                        Instantiation declInstantiation = decl.Instantiation;
                        Instantiation implInstantiation = method.Instantiation;
                        for (int i = 0; i < declInstantiation.Length; i++)
                        {
                            RecordBinding(
                                (EcmaGenericParameter)implInstantiation[i],
                                (EcmaGenericParameter)declInstantiation[i],
                                isProperEmbedding: false);
                        }
                    }
                }

                // Walk the method body looking at referenced things that have some genericness.
                // Nongeneric things cannot be forming cycles.
                // In particular, we don't care about MemberRefs to non-generic things, TypeDefs/MethodDefs/FieldDefs.
                // Avoid the work to even materialize type system entities for those.

                ILReader reader = new ILReader(methodIL.GetILBytes());

                while (reader.HasNext)
                {
                    ILOpcode opcode = reader.ReadILOpcode();
                    switch (opcode)
                    {
                    case ILOpcode.sizeof_:
                    case ILOpcode.newarr:
                    case ILOpcode.initobj:
                    case ILOpcode.stelem:
                    case ILOpcode.ldelem:
                    case ILOpcode.ldelema:
                    case ILOpcode.box:
                    case ILOpcode.unbox:
                    case ILOpcode.unbox_any:
                    case ILOpcode.cpobj:
                    case ILOpcode.ldobj:
                    case ILOpcode.castclass:
                    case ILOpcode.isinst:
                    case ILOpcode.stobj:
                    case ILOpcode.refanyval:
                    case ILOpcode.mkrefany:
                    case ILOpcode.constrained:
                        EntityHandle accessedType = MetadataTokens.EntityHandle(reader.ReadILToken());
typeCase:
                        if (accessedType.Kind == HandleKind.TypeSpecification)
                        {
                            var t = methodIL.GetObject(MetadataTokens.GetToken(accessedType), NotFoundBehavior.ReturnNull) as TypeDesc;
                            if (t != null)
                            {
                                ProcessTypeReference(t, typeContext, methodContext);
                            }
                        }
                        break;

                    case ILOpcode.stsfld:
                    case ILOpcode.ldsfld:
                    case ILOpcode.ldsflda:
                    case ILOpcode.stfld:
                    case ILOpcode.ldfld:
                    case ILOpcode.ldflda:
                        EntityHandle accessedField = MetadataTokens.EntityHandle(reader.ReadILToken());
fieldCase:
                        if (accessedField.Kind == HandleKind.MemberReference)
                        {
                            accessedType = _metadataReader.GetMemberReference((MemberReferenceHandle)accessedField).Parent;
                            goto typeCase;
                        }
                        break;

                    case ILOpcode.call:
                    case ILOpcode.callvirt:
                    case ILOpcode.newobj:
                    case ILOpcode.ldftn:
                    case ILOpcode.ldvirtftn:
                    case ILOpcode.jmp:
                        EntityHandle accessedMethod = MetadataTokens.EntityHandle(reader.ReadILToken());
methodCase:
                        if (accessedMethod.Kind == HandleKind.MethodSpecification ||
                            (accessedMethod.Kind == HandleKind.MemberReference &&
                             _metadataReader.GetMemberReference((MemberReferenceHandle)accessedMethod).Parent.Kind == HandleKind.TypeSpecification))
                        {
                            var m = methodIL.GetObject(MetadataTokens.GetToken(accessedMethod), NotFoundBehavior.ReturnNull) as MethodDesc;
                            ProcessTypeReference(m.OwningType, typeContext, methodContext);
                            ProcessMethodCall(m, typeContext, methodContext);
                        }
                        break;

                    case ILOpcode.ldtoken:
                        EntityHandle accessedEntity = MetadataTokens.EntityHandle(reader.ReadILToken());
                        if (accessedEntity.Kind == HandleKind.MethodSpecification ||
                            (accessedEntity.Kind == HandleKind.MemberReference && _metadataReader.GetMemberReference((MemberReferenceHandle)accessedEntity).GetKind() == MemberReferenceKind.Method))
                        {
                            accessedMethod = accessedEntity;
                            goto methodCase;
                        }
                        else if (accessedEntity.Kind == HandleKind.MemberReference)
                        {
                            accessedField = accessedEntity;
                            goto fieldCase;
                        }
                        else if (accessedEntity.Kind == HandleKind.TypeSpecification)
                        {
                            accessedType = accessedEntity;
                            goto typeCase;
                        }
                        break;

                    default:
                        reader.Skip(opcode);
                        break;
                    }
                }
            }
Ejemplo n.º 30
0
        public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
        {
            // This attempts to find all basic blocks that are unreachable after applying the substitutions.
            //
            // On a high level, we first find all the basic blocks and instruction boundaries in the IL stream.
            // This is tracked in a sidecar `flags` array that has flags for each byte of the IL stream.
            //
            // Once we have all the basic blocks and instruction boundaries, we do a marking phase to mark
            // the reachable blocks. We use substitutions to tell us what's unreachable. We consider conditional
            // branches "interesting" and whenever we see one, we seek backwards in the IL instruction stream
            // to find the instruction that feeds it. We make sure we don't cross the basic block boundary while
            // doing that. If the conditional instruction is fed by known values (either through the substitutions
            // or because it's an IL constant), we simulate the result of the comparison and only mark
            // the taken branch. We also mark any associated EH regions.
            //
            // The "seek backwards to find what feeds the comparison" only works for a couple known instructions
            // (load constant, call). It can't e.g. skip over arguments to the call.
            //
            // Last step is a sweep - we replace the tail of all unreachable blocks with "br $-2"
            // and nop out the rest. If the basic block is smaller than 2 bytes, we don't touch it.
            // We also eliminate any EH records that correspond to the stubbed out basic block.

            Debug.Assert(method.GetMethodILDefinition() == method);

            ILExceptionRegion[] ehRegions = method.GetExceptionRegions();
            byte[]        methodBytes     = method.GetILBytes();
            OpcodeFlags[] flags           = new OpcodeFlags[methodBytes.Length];

            // Offset 0 is the first basic block
            Stack <int> offsetsToVisit = new Stack <int>();

            offsetsToVisit.Push(0);

            // Basic blocks also start around EH regions
            foreach (ILExceptionRegion ehRegion in ehRegions)
            {
                if (ehRegion.Kind == ILExceptionRegionKind.Filter)
                {
                    offsetsToVisit.Push(ehRegion.FilterOffset);
                }

                offsetsToVisit.Push(ehRegion.HandlerOffset);
            }

            // Identify basic blocks and instruction boundaries
            while (offsetsToVisit.TryPop(out int offset))
            {
                // If this was already visited, we're done
                if (flags[offset] != 0)
                {
                    // Also mark as basic block start in case this was a target of a backwards branch.
                    flags[offset] |= OpcodeFlags.BasicBlockStart;
                    continue;
                }

                flags[offset] |= OpcodeFlags.BasicBlockStart;

                // Read until we reach the end of the basic block
                ILReader reader = new ILReader(methodBytes, offset);
                while (reader.HasNext)
                {
                    offset         = reader.Offset;
                    flags[offset] |= OpcodeFlags.InstructionStart;
                    ILOpcode opcode = reader.ReadILOpcode();
                    if (opcode >= ILOpcode.br_s && opcode <= ILOpcode.blt_un ||
                        opcode == ILOpcode.leave || opcode == ILOpcode.leave_s)
                    {
                        int destination = reader.ReadBranchDestination(opcode);
                        offsetsToVisit.Push(destination);

                        if (opcode != ILOpcode.leave && opcode != ILOpcode.leave_s &&
                            opcode != ILOpcode.br && opcode != ILOpcode.br_s)
                        {
                            // Branches not tested for above are conditional and the flow falls through.
                            offsetsToVisit.Push(reader.Offset);
                        }

                        flags[offset] |= OpcodeFlags.EndBasicBlock;
                    }
                    else if (opcode == ILOpcode.ret ||
                             opcode == ILOpcode.endfilter ||
                             opcode == ILOpcode.endfinally ||
                             opcode == ILOpcode.throw_ ||
                             opcode == ILOpcode.rethrow ||
                             opcode == ILOpcode.jmp)
                    {
                        // Ends basic block.
                        flags[offset] |= OpcodeFlags.EndBasicBlock;

                        reader.Skip(opcode);
                    }
                    else if (opcode == ILOpcode.switch_)
                    {
                        uint count   = reader.ReadILUInt32();
                        int  jmpBase = reader.Offset + (int)(4 * count);
                        for (uint i = 0; i < count; i++)
                        {
                            int destination = (int)reader.ReadILUInt32() + jmpBase;
                            offsetsToVisit.Push(destination);
                        }
                        // We fall through to the next basic block.
                        offsetsToVisit.Push(reader.Offset);
                        flags[offset] |= OpcodeFlags.EndBasicBlock;
                    }
                    else
                    {
                        reader.Skip(opcode);
                    }

                    if ((flags[offset] & OpcodeFlags.EndBasicBlock) != 0)
                    {
                        if (reader.HasNext)
                        {
                            // If the bytes following this basic block are not reachable from anywhere,
                            // the sweeping step would consider them to be part of the last instruction
                            // of the current basic block because of how instruction boundaries are identified.
                            // We wouldn't NOP them out if the current basic block is reachable.
                            //
                            // That's a problem for RyuJIT because RyuJIT looks at these bytes for... reasons.
                            //
                            // We can just do the same thing as RyuJIT and consider those a basic block.
                            offsetsToVisit.Push(reader.Offset);
                        }
                        break;
                    }
                }
            }

            // Mark all reachable basic blocks
            //
            // We also do another round of basic block marking to mark beginning of visible basic blocks
            // after dead branch elimination. This allows us to limit the number of potential small basic blocks
            // that are not interesting (because no code jumps to them anymore), but could prevent us from
            // finishing the process. Unreachable basic blocks smaller than 2 bytes abort the substitution
            // inlining process because we can't neutralize them (turn them into an infinite loop).
            offsetsToVisit.Push(0);
            while (offsetsToVisit.TryPop(out int offset))
            {
                // Mark as a basic block visible after constant propagation.
                flags[offset] |= OpcodeFlags.VisibleBasicBlockStart;

                // If this was already marked, we're done.
                if ((flags[offset] & OpcodeFlags.Mark) != 0)
                {
                    continue;
                }

                ILReader reader = new ILReader(methodBytes, offset);
                while (reader.HasNext)
                {
                    offset         = reader.Offset;
                    flags[offset] |= OpcodeFlags.Mark;
                    ILOpcode opcode = reader.ReadILOpcode();

                    // Mark any applicable EH blocks
                    foreach (ILExceptionRegion ehRegion in ehRegions)
                    {
                        int delta = offset - ehRegion.TryOffset;
                        if (delta >= 0 && delta < ehRegion.TryLength)
                        {
                            if (ehRegion.Kind == ILExceptionRegionKind.Filter)
                            {
                                offsetsToVisit.Push(ehRegion.FilterOffset);
                            }

                            offsetsToVisit.Push(ehRegion.HandlerOffset);

                            // RyuJIT is going to look at this basic block even though it's unreachable.
                            // Consider it visible so that we replace the tail with an endless loop.
                            int handlerEnd = ehRegion.HandlerOffset + ehRegion.HandlerLength;
                            if (handlerEnd < flags.Length)
                            {
                                flags[handlerEnd] |= OpcodeFlags.VisibleBasicBlockStart;
                            }
                        }
                    }

                    // All branches are relevant to basic block tracking
                    if (opcode == ILOpcode.brfalse || opcode == ILOpcode.brfalse_s ||
                        opcode == ILOpcode.brtrue || opcode == ILOpcode.brtrue_s)
                    {
                        int destination = reader.ReadBranchDestination(opcode);
                        if (!TryGetConstantArgument(method, methodBytes, flags, offset, 0, out int constant))
                        {
                            // Can't get the constant - both branches are live.
                            offsetsToVisit.Push(destination);
                            offsetsToVisit.Push(reader.Offset);
                        }
                        else if ((constant == 0 && (opcode == ILOpcode.brfalse || opcode == ILOpcode.brfalse_s)) ||
                                 (constant != 0 && (opcode == ILOpcode.brtrue || opcode == ILOpcode.brtrue_s)))
                        {
                            // Only the "branch taken" is live.
                            // The fallthrough marks the beginning of a visible (but not live) basic block.
                            offsetsToVisit.Push(destination);
                            flags[reader.Offset] |= OpcodeFlags.VisibleBasicBlockStart;
                        }
                        else
                        {
                            // Only fallthrough is live.
                            // The "brach taken" marks the beginning of a visible (but not live) basic block.
                            flags[destination] |= OpcodeFlags.VisibleBasicBlockStart;
                            offsetsToVisit.Push(reader.Offset);
                        }
                    }
                    else if (opcode == ILOpcode.beq || opcode == ILOpcode.beq_s ||
                             opcode == ILOpcode.bne_un || opcode == ILOpcode.bne_un_s)
                    {
                        int destination = reader.ReadBranchDestination(opcode);
                        if (!TryGetConstantArgument(method, methodBytes, flags, offset, 0, out int left) ||
                            !TryGetConstantArgument(method, methodBytes, flags, offset, 1, out int right))
                        {
                            // Can't get the constant - both branches are live.
                            offsetsToVisit.Push(destination);
                            offsetsToVisit.Push(reader.Offset);
                        }
                        else if ((left == right && (opcode == ILOpcode.beq || opcode == ILOpcode.beq_s) ||
                                  (left != right) && (opcode == ILOpcode.bne_un || opcode == ILOpcode.bne_un_s)))
                        {
                            // Only the "branch taken" is live.
                            // The fallthrough marks the beginning of a visible (but not live) basic block.
                            offsetsToVisit.Push(destination);
                            flags[reader.Offset] |= OpcodeFlags.VisibleBasicBlockStart;
                        }
                        else
                        {
                            // Only fallthrough is live.
                            // The "brach taken" marks the beginning of a visible (but not live) basic block.
                            flags[destination] |= OpcodeFlags.VisibleBasicBlockStart;
                            offsetsToVisit.Push(reader.Offset);
                        }
                    }
                    else if (opcode >= ILOpcode.br_s && opcode <= ILOpcode.blt_un ||
                             opcode == ILOpcode.leave || opcode == ILOpcode.leave_s)
                    {
                        int destination = reader.ReadBranchDestination(opcode);
                        offsetsToVisit.Push(destination);
                        if (opcode != ILOpcode.leave && opcode != ILOpcode.leave_s &&
                            opcode != ILOpcode.br && opcode != ILOpcode.br_s)
                        {
                            // Branches not tested for above are conditional and the flow falls through.
                            offsetsToVisit.Push(reader.Offset);
                        }
                        else
                        {
                            // RyuJIT is going to look at this basic block even though it's unreachable.
                            // Consider it visible so that we replace the tail with an endless loop.
                            if (reader.HasNext)
                            {
                                flags[reader.Offset] |= OpcodeFlags.VisibleBasicBlockStart;
                            }
                        }
                    }
                    else if (opcode == ILOpcode.switch_)
                    {
                        uint count   = reader.ReadILUInt32();
                        int  jmpBase = reader.Offset + (int)(4 * count);
                        for (uint i = 0; i < count; i++)
                        {
                            int destination = (int)reader.ReadILUInt32() + jmpBase;
                            offsetsToVisit.Push(destination);
                        }
                        offsetsToVisit.Push(reader.Offset);
                    }
                    else if (opcode == ILOpcode.ret ||
                             opcode == ILOpcode.endfilter ||
                             opcode == ILOpcode.endfinally ||
                             opcode == ILOpcode.throw_ ||
                             opcode == ILOpcode.rethrow ||
                             opcode == ILOpcode.jmp)
                    {
                        reader.Skip(opcode);

                        // RyuJIT is going to look at this basic block even though it's unreachable.
                        // Consider it visible so that we replace the tail with an endless loop.
                        if (reader.HasNext)
                        {
                            flags[reader.Offset] |= OpcodeFlags.VisibleBasicBlockStart;
                        }
                    }
                    else
                    {
                        reader.Skip(opcode);
                    }

                    if ((flags[offset] & OpcodeFlags.EndBasicBlock) != 0)
                    {
                        break;
                    }
                }
            }

            // Now sweep unreachable basic blocks by replacing them with nops
            bool hasUnmarkedIntructions = false;

            foreach (var flag in flags)
            {
                if ((flag & OpcodeFlags.InstructionStart) != 0 &&
                    (flag & OpcodeFlags.Mark) == 0)
                {
                    hasUnmarkedIntructions = true;
                }
            }

            if (!hasUnmarkedIntructions)
            {
                return(method);
            }

            byte[] newBody  = (byte[])methodBytes.Clone();
            int    position = 0;

            while (position < newBody.Length)
            {
                Debug.Assert((flags[position] & OpcodeFlags.InstructionStart) != 0);
                Debug.Assert((flags[position] & OpcodeFlags.VisibleBasicBlockStart) != 0);

                bool erase = (flags[position] & OpcodeFlags.Mark) == 0;

                int basicBlockStart = position;
                do
                {
                    if (erase)
                    {
                        newBody[position] = (byte)ILOpCode.Nop;
                    }
                    position++;
                } while (position < newBody.Length && (flags[position] & OpcodeFlags.VisibleBasicBlockStart) == 0);

                // If we had to nop out this basic block, we need to neutralize it by appending
                // an infinite loop ("br $-2").
                // We append instead of prepend because RyuJIT's importer has trouble with junk unreachable bytes.
                if (erase)
                {
                    if (position - basicBlockStart < 2)
                    {
                        // We cannot neutralize the basic block, so better leave the method alone.
                        // The control would fall through to the next basic block.
                        return(method);
                    }

                    newBody[position - 2] = (byte)ILOpCode.Br_s;
                    newBody[position - 1] = unchecked ((byte)-2);
                }
            }

            // EH regions with unmarked handlers belong to unmarked basic blocks
            // Need to eliminate them because they're not usable.
            ArrayBuilder <ILExceptionRegion> newEHRegions = new ArrayBuilder <ILExceptionRegion>();

            foreach (ILExceptionRegion ehRegion in ehRegions)
            {
                if ((flags[ehRegion.HandlerOffset] & OpcodeFlags.Mark) != 0)
                {
                    newEHRegions.Add(ehRegion);
                }
            }

            // Existing debug information might not match new instruction boundaries (plus there's little point
            // in generating debug information for NOPs) - generate new debug information by filtering
            // out the sequence points associated with nopped out instructions.
            MethodDebugInformation        debugInfo         = method.GetDebugInfo();
            IEnumerable <ILSequencePoint> oldSequencePoints = debugInfo?.GetSequencePoints();

            if (oldSequencePoints != null)
            {
                ArrayBuilder <ILSequencePoint> sequencePoints = new ArrayBuilder <ILSequencePoint>();
                foreach (var sequencePoint in oldSequencePoints)
                {
                    if (sequencePoint.Offset < flags.Length && (flags[sequencePoint.Offset] & OpcodeFlags.Mark) != 0)
                    {
                        sequencePoints.Add(sequencePoint);
                    }
                }

                debugInfo = new SubstitutedDebugInformation(debugInfo, sequencePoints.ToArray());
            }

            return(new SubstitutedMethodIL(method, newBody, newEHRegions.ToArray(), debugInfo));
        }
Ejemplo n.º 31
-1
 Instruction(ILReader reader, OpCode op, Operand arg, ushort label)
 {
     this.reader = reader;
     this.OpCode = op;
     this.Operand = arg;
     this.label = (ushort)label;
 }
Ejemplo n.º 32
-1
        public static IEnumerable<MethodBase> GetMethods(MethodBase caller, bool recursive = false, string namespacePrefix = DefaultPrefix)
        {
            ILReader reader = new ILReader(caller);
            foreach (InlineMethodInstruction method in
                reader.OfType<InlineMethodInstruction>())
            {

                yield return method.Method;
                if (recursive && method.Method.DeclaringType != null && method.Method.DeclaringType.FullName.StartsWith(namespacePrefix, StringComparison.InvariantCultureIgnoreCase))
                {
                    foreach (var innerMethod in GetMethods(method.Method))
                    {
                        yield return innerMethod;
                    }
                }
            }
        }
Ejemplo n.º 33
-1
 /// <summary>
 /// Construct an instruction.
 /// </summary>
 /// <param name="reader">The reader that created this instruction.</param>
 /// <param name="op">The instruction opcode.</param>
 /// <param name="arg">The instruction operand.</param>
 /// <param name="label">The instruction's address in the bytecode.</param>
 public Instruction(ILReader reader, OpCode op, Operand arg, IL.Label label)
     : this(reader, op, arg, (ushort)label.pos)
 {
 }
Ejemplo n.º 34
-1
 /// <summary>
 /// Construct an instruction.
 /// </summary>
 /// <param name="reader">The reader that created this instruction.</param>
 /// <param name="op">The instruction opcode.</param>
 /// <param name="label">The instruction's address in the bytecode.</param>
 public Instruction(ILReader reader, OpCode op, IL.Label label)
     : this(reader, op, default(Operand), label)
 {
 }