// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
using dnlib.DotNet.Pdb;
using dnlib.PE;
namespace dnlib.DotNet.Emit {
///
/// Method body base class
///
public abstract class MethodBody {
}
///
/// A native method body
///
public sealed class NativeMethodBody : MethodBody {
RVA rva;
///
/// Gets/sets the RVA of the native method body
///
public RVA RVA {
get => rva;
set => rva = value;
}
///
/// Default constructor
///
public NativeMethodBody() {
}
///
/// Constructor
///
/// RVA of method body
public NativeMethodBody(RVA rva) => this.rva = rva;
}
///
/// CIL (managed code) body
///
public sealed class CilBody : MethodBody {
bool keepOldMaxStack;
bool initLocals;
byte headerSize;
ushort maxStack;
uint localVarSigTok;
readonly IList instructions;
readonly IList exceptionHandlers;
readonly LocalList localList;
///
/// Size of a small header
///
public const byte SMALL_HEADER_SIZE = 1;
///
/// Gets/sets a flag indicating whether the original max stack value should be used.
///
public bool KeepOldMaxStack {
get => keepOldMaxStack;
set => keepOldMaxStack = value;
}
///
/// Gets/sets the init locals flag. This is only valid if the method has any locals.
///
public bool InitLocals {
get => initLocals;
set => initLocals = value;
}
///
/// Gets/sets the size in bytes of the method body header. The instructions immediately follow
/// the header.
///
public byte HeaderSize {
get => headerSize;
set => headerSize = value;
}
///
/// true if it was a small body header ( is 1)
///
public bool IsSmallHeader => headerSize == SMALL_HEADER_SIZE;
///
/// true if it was a big body header
///
public bool IsBigHeader => headerSize != SMALL_HEADER_SIZE;
///
/// Gets/sets max stack value from the fat method header.
///
public ushort MaxStack {
get => maxStack;
set => maxStack = value;
}
///
/// Gets/sets the locals metadata token
///
public uint LocalVarSigTok {
get => localVarSigTok;
set => localVarSigTok = value;
}
///
/// true if is not empty
///
public bool HasInstructions => instructions.Count > 0;
///
/// Gets the instructions
///
public IList Instructions => instructions;
///
/// true if is not empty
///
public bool HasExceptionHandlers => exceptionHandlers.Count > 0;
///
/// Gets the exception handlers
///
public IList ExceptionHandlers => exceptionHandlers;
///
/// true if is not empty
///
public bool HasVariables => localList.Count > 0;
///
/// Gets the locals
///
public LocalList Variables => localList;
///
/// Gets/sets the PDB method. This is null if no PDB has been loaded or if there's
/// no PDB info for this method.
///
public PdbMethod PdbMethod {
get => pdbMethod;
set => pdbMethod = value;
}
PdbMethod pdbMethod;
///
/// true if is not null
///
public bool HasPdbMethod => PdbMethod is not null;
///
/// Gets the total size of the body in the PE file, including header, IL bytes, and exception handlers.
/// This property returns 0 if the size is unknown.
///
internal uint MetadataBodySize { get; set; }
///
/// Default constructor
///
public CilBody() {
initLocals = true;
instructions = new List();
exceptionHandlers = new List();
localList = new LocalList();
}
///
/// Constructor
///
/// Init locals flag
/// All instructions. This instance will own the list.
/// All exception handlers. This instance will own the list.
/// All locals. This instance will own the locals in the list.
public CilBody(bool initLocals, IList instructions, IList exceptionHandlers, IList locals) {
this.initLocals = initLocals;
this.instructions = instructions;
this.exceptionHandlers = exceptionHandlers;
localList = new LocalList(locals);
}
///
/// Shorter instructions are converted to the longer form, eg. Ldc_I4_1 is
/// converted to Ldc_I4 with a 1 as the operand.
///
/// All method parameters, including the hidden 'this' parameter
/// if it's an instance method. Use .
public void SimplifyMacros(IList parameters) => instructions.SimplifyMacros(localList, parameters);
///
/// Optimizes instructions by using the shorter form if possible. Eg. Ldc_I4 1
/// will be replaced with Ldc_I4_1.
///
public void OptimizeMacros() => instructions.OptimizeMacros();
///
/// Short branch instructions are converted to the long form, eg. Beq_S is
/// converted to Beq.
///
public void SimplifyBranches() => instructions.SimplifyBranches();
///
/// Optimizes branches by using the smallest possible branch
///
public void OptimizeBranches() => instructions.OptimizeBranches();
///
/// Updates each instruction's offset
///
/// Total size in bytes of all instructions
public uint UpdateInstructionOffsets() => instructions.UpdateInstructionOffsets();
}
}