public bool TryReadLdcI4(out int value)
        {
            ILOpcode opcode = _reader.PeekILOpcode();

            if (opcode == ILOpcode.ldc_i4) // ldc.i4
            {
                _reader.ReadILOpcode();
                value = unchecked ((int)_reader.ReadILUInt32());
                return(true);
            }

            if ((opcode >= ILOpcode.ldc_i4_m1) && (opcode <= ILOpcode.ldc_i4_8)) // ldc.m1 to ldc.i4.8
            {
                _reader.ReadILOpcode();
                value = -1 + ((int)opcode) - 0x15;
                return(true);
            }

            if (opcode == ILOpcode.ldc_i4_s) // ldc.i4.s
            {
                _reader.ReadILOpcode();

                value = (int)unchecked ((sbyte)_reader.ReadILByte());
                return(true);
            }
            value = 0;
            return(false);
        }
Beispiel #2
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;
                    }
                }
            }
        }
Beispiel #3
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)
Beispiel #4
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;