예제 #1
0
        void ReadCilBody(MethodBody body, BinaryReader br)
        {
            long        start = br.BaseStream.Position;
            Instruction last  = null;

            m_instructions.Clear();
            InstructionCollection code    = body.Instructions;
            GenericContext        context = new GenericContext(body.Method);

            while (br.BaseStream.Position < start + body.CodeSize)
            {
                OpCode op;
                long   offset = br.BaseStream.Position - start;
                int    cursor = br.ReadByte();
                if (cursor == 0xfe)
                {
                    op = OpCodes.TwoBytesOpCode [br.ReadByte()];
                }
                else
                {
                    op = OpCodes.OneByteOpCode [cursor];
                }

                Instruction instr = new Instruction((int)offset, op);
                switch (op.OperandType)
                {
                case OperandType.InlineNone:
                    break;

                case OperandType.InlineSwitch:
                    uint   length   = br.ReadUInt32();
                    int [] branches = new int [length];
                    int [] buf      = new int [length];
                    for (int i = 0; i < length; i++)
                    {
                        buf [i] = br.ReadInt32();
                    }
                    for (int i = 0; i < length; i++)
                    {
                        branches [i] = Convert.ToInt32(br.BaseStream.Position - start + buf [i]);
                    }
                    instr.Operand = branches;
                    break;

                case OperandType.ShortInlineBrTarget:
                    sbyte sbrtgt = br.ReadSByte();
                    instr.Operand = Convert.ToInt32(br.BaseStream.Position - start + sbrtgt);
                    break;

                case OperandType.InlineBrTarget:
                    int brtgt = br.ReadInt32();
                    instr.Operand = Convert.ToInt32(br.BaseStream.Position - start + brtgt);
                    break;

                case OperandType.ShortInlineI:
                    if (op == OpCodes.Ldc_I4_S)
                    {
                        instr.Operand = br.ReadSByte();
                    }
                    else
                    {
                        instr.Operand = br.ReadByte();
                    }
                    break;

                case OperandType.ShortInlineVar:
                    instr.Operand = GetVariable(body, br.ReadByte());
                    break;

                case OperandType.ShortInlineParam:
                    instr.Operand = GetParameter(body, br.ReadByte());
                    break;

                case OperandType.InlineSig:
                    instr.Operand = GetCallSiteAt(br.ReadInt32(), context);
                    break;

                case OperandType.InlineI:
                    instr.Operand = br.ReadInt32();
                    break;

                case OperandType.InlineVar:
                    instr.Operand = GetVariable(body, br.ReadInt16());
                    break;

                case OperandType.InlineParam:
                    instr.Operand = GetParameter(body, br.ReadInt16());
                    break;

                case OperandType.InlineI8:
                    instr.Operand = br.ReadInt64();
                    break;

                case OperandType.ShortInlineR:
                    instr.Operand = br.ReadSingle();
                    break;

                case OperandType.InlineR:
                    instr.Operand = br.ReadDouble();
                    break;

                case OperandType.InlineString:
                    instr.Operand = m_root.Streams.UserStringsHeap [GetRid(br.ReadInt32())];
                    break;

                case OperandType.InlineField:
                case OperandType.InlineMethod:
                case OperandType.InlineType:
                case OperandType.InlineTok:
                    MetadataToken token = new MetadataToken(br.ReadInt32());
                    switch (token.TokenType)
                    {
                    case TokenType.TypeDef:
                        instr.Operand = m_reflectReader.GetTypeDefAt(token.RID);
                        break;

                    case TokenType.TypeRef:
                        instr.Operand = m_reflectReader.GetTypeRefAt(token.RID);
                        break;

                    case TokenType.TypeSpec:
                        instr.Operand = m_reflectReader.GetTypeSpecAt(token.RID, context);
                        break;

                    case TokenType.Field:
                        instr.Operand = m_reflectReader.GetFieldDefAt(token.RID);
                        break;

                    case TokenType.Method:
                        instr.Operand = m_reflectReader.GetMethodDefAt(token.RID);
                        break;

                    case TokenType.MethodSpec:
                        instr.Operand = m_reflectReader.GetMethodSpecAt(token.RID, context);
                        break;

                    case TokenType.MemberRef:
                        instr.Operand = m_reflectReader.GetMemberRefAt(token.RID, context);
                        break;

                    default:
                        throw new ReflectionException("Wrong token: " + token);
                    }
                    break;
                }

                m_instructions.Add(instr.Offset, instr);

                if (last != null)
                {
                    last.Next      = instr;
                    instr.Previous = last;
                }

                last = instr;

                code.Add(instr);
            }

            // resolve branches
            foreach (Instruction i in code)
            {
                switch (i.OpCode.OperandType)
                {
                case OperandType.ShortInlineBrTarget:
                case OperandType.InlineBrTarget:
                    i.Operand = GetInstruction(body, (int)i.Operand);
                    break;

                case OperandType.InlineSwitch:
                    int []         lbls   = (int [])i.Operand;
                    Instruction [] instrs = new Instruction [lbls.Length];
                    for (int j = 0; j < lbls.Length; j++)
                    {
                        instrs [j] = GetInstruction(body, lbls [j]);
                    }
                    i.Operand = instrs;
                    break;
                }
            }

            if (m_reflectReader.SymbolReader != null)
            {
                m_reflectReader.SymbolReader.Read(body, m_instructions);
            }
        }
예제 #2
0
 internal CilWorker(MethodBody body)
 {
     m_mbody  = body;
     m_instrs = m_mbody.Instructions;
 }
예제 #3
0
        void ComputeMaxStack(InstructionCollection instructions)
        {
            int current = 0;
            int max     = 0;

            m_stackSizes.Clear();

            foreach (ExceptionHandler eh in instructions.Container.ExceptionHandlers)
            {
                switch (eh.Type)
                {
                case ExceptionHandlerType.Catch:
                case ExceptionHandlerType.Filter:
                    m_stackSizes [eh.HandlerStart] = 1;
                    max = 1;
                    break;
                }
            }

            foreach (Instruction instr in instructions)
            {
                object savedSize = m_stackSizes [instr];
                if (savedSize != null)
                {
                    current = (int)savedSize;
                }

                current -= GetPopDelta(instructions.Container.Method, instr, current);

                if (current < 0)
                {
                    current = 0;
                }

                current += GetPushDelta(instr);

                if (current > max)
                {
                    max = current;
                }

                // for forward branches, copy the stack size for the instruction that is being branched to
                switch (instr.OpCode.OperandType)
                {
                case OperandType.InlineBrTarget:
                case OperandType.ShortInlineBrTarget:
                    m_stackSizes [instr.Operand] = current;
                    break;

                case OperandType.InlineSwitch:
                    foreach (Instruction target in (Instruction [])instr.Operand)
                    {
                        m_stackSizes [target] = current;
                    }
                    break;
                }

                switch (instr.OpCode.FlowControl)
                {
                case FlowControl.Branch:
                case FlowControl.Throw:
                case FlowControl.Return:
                    // next statement is not reachable from this statement, so reset the stack depth to 0
                    current = 0;
                    break;
                }
            }

            instructions.Container.MaxStack = max + 1;             // you never know
        }
예제 #4
0
 static bool IsRangeFat(Instruction start, Instruction end, InstructionCollection instructions)
 {
     return(GetLength(start, end, instructions) >= 256 ||
            start.Offset >= 65536);
 }
예제 #5
0
        static int GetLength(Instruction start, Instruction end, InstructionCollection instructions)
        {
            Instruction last = instructions [instructions.Count - 1];

            return((end == instructions.Outside ? last.Offset + last.GetSize() : end.Offset) - start.Offset);
        }
예제 #6
0
        public override void VisitInstructionCollection(InstructionCollection instructions)
        {
            MethodBody body  = instructions.Container;
            long       start = m_codeWriter.BaseStream.Position;

            ComputeMaxStack(instructions);

            foreach (Instruction instr in instructions)
            {
                instr.Offset = (int)(m_codeWriter.BaseStream.Position - start);

                if (instr.OpCode.Size == 1)
                {
                    m_codeWriter.Write(instr.OpCode.Op2);
                }
                else
                {
                    m_codeWriter.Write(instr.OpCode.Op1);
                    m_codeWriter.Write(instr.OpCode.Op2);
                }

                if (instr.OpCode.OperandType != OperandType.InlineNone &&
                    instr.Operand == null)
                {
                    throw new ReflectionException("OpCode {0} have null operand", instr.OpCode.Name);
                }

                switch (instr.OpCode.OperandType)
                {
                case OperandType.InlineNone:
                    break;

                case OperandType.InlineSwitch:
                    Instruction [] targets = (Instruction [])instr.Operand;
                    for (int i = 0; i < targets.Length + 1; i++)
                    {
                        m_codeWriter.Write((uint)0);
                    }
                    break;

                case OperandType.ShortInlineBrTarget:
                    m_codeWriter.Write((byte)0);
                    break;

                case OperandType.InlineBrTarget:
                    m_codeWriter.Write(0);
                    break;

                case OperandType.ShortInlineI:
                    if (instr.OpCode == OpCodes.Ldc_I4_S)
                    {
                        m_codeWriter.Write((sbyte)instr.Operand);
                    }
                    else
                    {
                        m_codeWriter.Write((byte)instr.Operand);
                    }
                    break;

                case OperandType.ShortInlineVar:
                    m_codeWriter.Write((byte)body.Variables.IndexOf(
                                           (VariableDefinition)instr.Operand));
                    break;

                case OperandType.ShortInlineParam:
                    m_codeWriter.Write((byte)GetParameterIndex(body, (ParameterDefinition)instr.Operand));
                    break;

                case OperandType.InlineSig:
                    WriteToken(GetCallSiteToken((CallSite)instr.Operand));
                    break;

                case OperandType.InlineI:
                    m_codeWriter.Write((int)instr.Operand);
                    break;

                case OperandType.InlineVar:
                    m_codeWriter.Write((short)body.Variables.IndexOf(
                                           (VariableDefinition)instr.Operand));
                    break;

                case OperandType.InlineParam:
                    m_codeWriter.Write((short)GetParameterIndex(
                                           body, (ParameterDefinition)instr.Operand));
                    break;

                case OperandType.InlineI8:
                    m_codeWriter.Write((long)instr.Operand);
                    break;

                case OperandType.ShortInlineR:
                    m_codeWriter.Write((float)instr.Operand);
                    break;

                case OperandType.InlineR:
                    m_codeWriter.Write((double)instr.Operand);
                    break;

                case OperandType.InlineString:
                    WriteToken(new MetadataToken(TokenType.String,
                                                 m_reflectWriter.MetadataWriter.AddUserString(instr.Operand as string)));
                    break;

                case OperandType.InlineField:
                case OperandType.InlineMethod:
                case OperandType.InlineType:
                case OperandType.InlineTok:
                    if (instr.Operand is TypeReference)
                    {
                        WriteToken(GetTypeToken((TypeReference)instr.Operand));
                    }
                    else if (instr.Operand is GenericInstanceMethod)
                    {
                        WriteToken(m_reflectWriter.GetMethodSpecToken(instr.Operand as GenericInstanceMethod));
                    }
                    else if (instr.Operand is MemberReference)
                    {
                        WriteToken(m_reflectWriter.GetMemberRefToken((MemberReference)instr.Operand));
                    }
                    else if (instr.Operand is IMetadataTokenProvider)
                    {
                        WriteToken(((IMetadataTokenProvider)instr.Operand).MetadataToken);
                    }
                    else
                    {
                        throw new ReflectionException(
                                  string.Format("Wrong operand for {0} OpCode: {1}",
                                                instr.OpCode.OperandType,
                                                instr.Operand.GetType().FullName));
                    }
                    break;
                }
            }

            // patch branches
            long pos = m_codeWriter.BaseStream.Position;

            foreach (Instruction instr in instructions)
            {
                switch (instr.OpCode.OperandType)
                {
                case OperandType.InlineSwitch:
                    m_codeWriter.BaseStream.Position = instr.Offset + instr.OpCode.Size;
                    Instruction [] targets = (Instruction [])instr.Operand;
                    m_codeWriter.Write((uint)targets.Length);
                    foreach (Instruction tgt in targets)
                    {
                        m_codeWriter.Write((tgt.Offset - (instr.Offset +
                                                          instr.OpCode.Size + (4 * (targets.Length + 1)))));
                    }
                    break;

                case OperandType.ShortInlineBrTarget:
                    m_codeWriter.BaseStream.Position = instr.Offset + instr.OpCode.Size;
                    m_codeWriter.Write((byte)(((Instruction)instr.Operand).Offset -
                                              (instr.Offset + instr.OpCode.Size + 1)));
                    break;

                case OperandType.InlineBrTarget:
                    m_codeWriter.BaseStream.Position = instr.Offset + instr.OpCode.Size;
                    m_codeWriter.Write(((Instruction)instr.Operand).Offset -
                                       (instr.Offset + instr.OpCode.Size + 4));
                    break;
                }
            }

            m_codeWriter.BaseStream.Position = pos;
        }