/// <summary> /// Decodes the instruction stream of the reader and populates the compiler. /// </summary> /// <param name="compiler">The compiler to populate.</param> /// <param name="header">The method _header.</param> private void Decode(IMethodCompiler compiler, ref MethodHeader header) { // Start of the code stream long codeStart = _codeReader.BaseStream.Position; // End of the code stream long codeEnd = _codeReader.BaseStream.Position + header.codeSize; // Prefix instruction //PrefixInstruction prefix = null; // Setup context Context ctx = new Context(InstructionSet, -1); while (codeEnd != _codeReader.BaseStream.Position) { // Determine the instruction offset int instOffset = (int)(_codeReader.BaseStream.Position - codeStart); // Read the next opcode From the stream OpCode op = (OpCode)_codeReader.ReadByte(); if (OpCode.Extop == op) { op = (OpCode)(0x100 | _codeReader.ReadByte()); } ICILInstruction instruction = Instruction.Get(op); if (instruction == null) { throw new Exception("CIL " + op + " is not yet supported"); } //if (instruction is PrefixInstruction) { // prefix = instruction as PrefixInstruction; // continue; //} // Create and initialize the corresponding instruction ctx.AppendInstruction(instruction); instruction.Decode(ctx, this); ctx.Label = instOffset; //ctx.Prefix = prefix; Debug.Assert(ctx.Instruction != null); // Do we need to patch branch targets? if (instruction is IBranchInstruction && instruction.FlowControl != FlowControl.Return) { int pc = (int)(_codeReader.BaseStream.Position - codeStart); for (int i = 0; i < ctx.Branch.Targets.Length; i++) { ctx.Branch.Targets[i] += pc; } } //prefix = null; } }
/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> public void Run() { using (Stream code = methodCompiler.GetInstructionStream()) { // Initialize the instruction methodCompiler.InstructionSet = new InstructionSet(256); // update the base class InstructionSet = methodCompiler.InstructionSet; using (codeReader = new BinaryReader(code)) { // The size of the code in bytes MethodHeader header = new MethodHeader(); ReadMethodHeader(codeReader, ref header); if (header.localsSignature.RID != 0) { StandAloneSigRow row = methodCompiler.Method.Module.MetadataModule.Metadata.ReadStandAloneSigRow(header.localsSignature); LocalVariableSignature localsSignature; if (methodCompiler.Method.DeclaringType is CilGenericType) { localsSignature = new LocalVariableSignature(methodCompiler.Method.Module.MetadataModule.Metadata, row.SignatureBlobIdx, (methodCompiler.Method.DeclaringType as CilGenericType).GenericArguments); } else { localsSignature = new LocalVariableSignature(methodCompiler.Method.Module.MetadataModule.Metadata, row.SignatureBlobIdx); } methodCompiler.SetLocalVariableSignature(localsSignature); } /* Decode the instructions */ Decode(methodCompiler, ref header); // When we leave, the operand stack must only contain the locals... //Debug.Assert(_operandStack.Count == _method.Locals.Count); } } }
/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> public void Run() { // The size of the code in bytes MethodHeader header = new MethodHeader(); using (Stream code = MethodCompiler.GetInstructionStream()) { // Initalize the instruction, setting the initalize size to 10 times the code stream MethodCompiler.InstructionSet = new InstructionSet((int)code.Length * 10); // update the base class InstructionSet = MethodCompiler.InstructionSet; using (BinaryReader reader = new BinaryReader(code)) { _compiler = MethodCompiler; _method = MethodCompiler.Method; _codeReader = reader; ReadMethodHeader(reader, ref header); //Debug.WriteLine("Decoding " + compiler.Method.ToString()); if (0 != header.localsSignature) { StandAloneSigRow row; IMetadataProvider md = _method.Module.Metadata; md.Read(header.localsSignature, out row); MethodCompiler.SetLocalVariableSignature(LocalVariableSignature.Parse(md, row.SignatureBlobIdx)); } /* Decode the instructions */ Decode(MethodCompiler, ref header); // When we leave, the operand stack must only contain the locals... //Debug.Assert(_operandStack.Count == _method.Locals.Count); _codeReader = null; _compiler = null; } } }
/// <summary> /// Reads the method header from the instruction stream. /// </summary> /// <param name="reader">The reader used to decode the instruction stream.</param> /// <param name="header">The method header structure to populate.</param> private void ReadMethodHeader(BinaryReader reader, ref MethodHeader header) { // Read first byte header.flags = (MethodFlags)reader.ReadByte(); // Check least significant 2 bits switch (header.flags & MethodFlags.HeaderMask) { case MethodFlags.TinyFormat: header.codeSize = ((uint)(header.flags & MethodFlags.TinyCodeSizeMask) >> 2); header.flags &= MethodFlags.HeaderMask; break; case MethodFlags.FatFormat: // Read second byte of flags header.flags = (MethodFlags)(reader.ReadByte() << 8 | (byte)header.flags); if (MethodFlags.ValidHeader != (header.flags & MethodFlags.HeaderSizeMask)) { throw new InvalidDataException(@"Invalid method _header."); } header.maxStack = reader.ReadUInt16(); header.codeSize = reader.ReadUInt32(); header.localsSignature = new Token(reader.ReadUInt32()); // ReadStandAloneSigRow break; default: throw new InvalidDataException(@"Invalid method header while trying to decode " + this.methodCompiler.Method.ToString() + ". (Flags = " + header.flags.ToString("X") + ", Rva = " + this.methodCompiler.Method.Rva + ")"); } // Are there sections following the code? if (MethodFlags.MoreSections == (header.flags & MethodFlags.MoreSections)) { // Yes, seek to them and process those sections long codepos = reader.BaseStream.Position; // Seek to the end of the code... long dataSectPos = codepos + header.codeSize; if (0 != (dataSectPos & 3)) { dataSectPos += (4 - (dataSectPos % 4)); } reader.BaseStream.Position = dataSectPos; // Read all headers, so the IL decoder knows how to handle these... byte flags; do { flags = reader.ReadByte(); bool isFat = (0x40 == (flags & 0x40)); int length; int blocks; if (isFat) { byte[] buffer = new byte[4]; reader.Read(buffer, 0, 3); length = LittleEndianBitConverter.GetInt32(buffer, 0); blocks = (length - 4) / 24; } else { length = reader.ReadByte(); blocks = (length - 4) / 12; /* Read & skip the padding. */ reader.ReadInt16(); } Debug.Assert(0x01 == (flags & 0x3F), @"Unsupported method data section."); // Read the clause for (int i = 0; i < blocks; i++) { EhClause clause = new EhClause(); clause.Read(reader, isFat); //this.methodCompiler.Method.ExceptionClauseHeader.AddClause(clause); // FIXME: Create proper basic Blocks for each item in the clause } }while (0x80 == (flags & 0x80)); //methodCompiler.Method.ExceptionClauseHeader.Sort(); reader.BaseStream.Position = codepos; } }
/// <summary> /// Reads the method header from the instruction stream. /// </summary> /// <param name="reader">The reader used to decode the instruction stream.</param> /// <param name="header">The method header structure to populate.</param> private void ReadMethodHeader(BinaryReader reader, ref MethodHeader header) { header.flags = (MethodFlags)reader.ReadByte(); switch (header.flags & MethodFlags.HeaderMask) { case MethodFlags.TinyFormat: header.codeSize = ((uint)(header.flags & MethodFlags.TinyCodeSizeMask) >> 2); header.flags &= MethodFlags.HeaderMask; break; case MethodFlags.FatFormat: header.flags = (MethodFlags)(reader.ReadByte() << 8 | (byte)header.flags); if (MethodFlags.ValidHeader != (header.flags & MethodFlags.HeaderSizeMask)) throw new InvalidDataException(@"Invalid method _header."); header.maxStack = reader.ReadUInt16(); header.codeSize = reader.ReadUInt32(); header.localsSignature = (TokenTypes)reader.ReadUInt32(); break; default: throw new InvalidDataException(@"Invalid method header."); } // Are there sections following the code? if (MethodFlags.MoreSections == (header.flags & MethodFlags.MoreSections)) { // Yes, seek to them and process those sections long codepos = reader.BaseStream.Position; // Seek to the end of the code... long dataSectPos = codepos + header.codeSize; if (0 != (dataSectPos & 3)) dataSectPos += (4 - (dataSectPos % 4)); reader.BaseStream.Position = dataSectPos; // Read all headers, so the IL decoder knows how to handle these... byte flags; do { flags = reader.ReadByte(); bool isFat = (0x40 == (flags & 0x40)); int length; int blocks; if (isFat) { byte[] buffer = new byte[4]; reader.Read(buffer, 0, 3); length = LittleEndianBitConverter.GetInt32(buffer, 0); blocks = (length - 4) / 24; } else { length = reader.ReadByte(); blocks = (length - 4) / 12; /* Read & skip the padding. */ reader.ReadInt16(); } Debug.Assert(0x01 == (flags & 0x3F), @"Unsupported method data section."); // Read the clause for (int i = 0; i < blocks; i++) { EhClause clause = new EhClause(); clause.Read(reader, isFat); this.methodCompiler.Method.ExceptionClauseHeader.AddClause(clause); // FIXME: Create proper basic Blocks for each item in the clause } } while (0x80 == (flags & 0x80)); methodCompiler.Method.ExceptionClauseHeader.Sort(); reader.BaseStream.Position = codepos; } }
/// <summary> /// Decodes the instruction stream of the reader and populates the compiler. /// </summary> /// <param name="compiler">The compiler to populate.</param> /// <param name="header">The method _header.</param> private void Decode(IMethodCompiler compiler, ref MethodHeader header) { // Start of the code stream long codeStart = codeReader.BaseStream.Position; // End of the code stream long codeEnd = codeReader.BaseStream.Position + header.codeSize; // Prefix instruction //PrefixInstruction prefix = null; // Setup context Context ctx = new Context(InstructionSet, -1); while (codeEnd != codeReader.BaseStream.Position) { // Determine the instruction offset int instOffset = (int)(codeReader.BaseStream.Position - codeStart); // Read the next opcode from the stream OpCode op = (OpCode)codeReader.ReadByte(); if (OpCode.Extop == op) op = (OpCode)(0x100 | codeReader.ReadByte()); ICILInstruction instruction = Instruction.Get(op); if (instruction == null) throw new Exception("CIL " + op + " is not yet supported"); //if (instruction is PrefixInstruction) { // prefix = instruction as PrefixInstruction; // continue; //} // Create and initialize the corresponding instruction ctx.AppendInstruction(instruction); ctx.Label = instOffset; instruction.Decode(ctx, this); //ctx.Prefix = prefix; Debug.Assert(ctx.Instruction != null); // Do we need to patch branch targets? if (instruction is IBranchInstruction && instruction.FlowControl != FlowControl.Return) { int pc = (int)(codeReader.BaseStream.Position - codeStart); for (int i = 0; i < ctx.Branch.Targets.Length; i++) ctx.Branch.Targets[i] += pc; } //prefix = null; } }
/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> public void Run() { // The size of the code in bytes MethodHeader header = new MethodHeader(); using (Stream code = methodCompiler.GetInstructionStream()) { // Initialize the instruction, setting the initialize size the same as the code stream methodCompiler.InstructionSet = new InstructionSet((int)code.Length); // update the base class InstructionSet = methodCompiler.InstructionSet; using (BinaryReader reader = new BinaryReader(code)) { codeReader = reader; //Debug.WriteLine("Decoding " + methodCompiler.Method.ToString()); ReadMethodHeader(reader, ref header); if (header.localsSignature != 0) { StandAloneSigRow row = methodCompiler.Method.MetadataModule.Metadata.ReadStandAloneSigRow(header.localsSignature); LocalVariableSignature localsSignature = new LocalVariableSignature(methodCompiler.Method.MetadataModule.Metadata, row.SignatureBlobIdx); if (methodCompiler.Method.DeclaringType is CilGenericType) { localsSignature.ApplyGenericType((methodCompiler.Method.DeclaringType as CilGenericType).GenericArguments); } methodCompiler.SetLocalVariableSignature(localsSignature); } /* Decode the instructions */ Decode(methodCompiler, ref header); // When we leave, the operand stack must only contain the locals... //Debug.Assert(_operandStack.Count == _method.Locals.Count); codeReader = null; } } }