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); } }
internal CilWorker(MethodBody body) { m_mbody = body; m_instrs = m_mbody.Instructions; }
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 }
static bool IsRangeFat(Instruction start, Instruction end, InstructionCollection instructions) { return(GetLength(start, end, instructions) >= 256 || start.Offset >= 65536); }
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); }
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; }