|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// <OWNER>Microsoft</OWNER>
//
namespace System.Reflection.Emit
{
using System.Text;
using System;
using CultureInfo = System.Globalization.CultureInfo;
using System.Diagnostics.SymbolStore;
using System.Reflection;
using System.Security;
using System.Collections;
using System.Collections.Generic;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Diagnostics.Contracts;
[HostProtection(MayLeakOnAbort = true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(_MethodBuilder))]
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class MethodBuilder : MethodInfo, _MethodBuilder
{
#region Private Data Members
// Identity
internal String m_strName; // The name of the method
private MethodToken m_tkMethod; // The token of this method
private ModuleBuilder m_module;
internal TypeBuilder m_containingType;
// IL
private int[] m_mdMethodFixups; // The location of all of the token fixups. Null means no fixups.
private byte[] m_localSignature; // Local signature if set explicitly via DefineBody. Null otherwise.
internal LocalSymInfo m_localSymInfo; // keep track debugging local information
internal ILGenerator m_ilGenerator; // Null if not used.
private byte[] m_ubBody; // The IL for the method
private ExceptionHandler[] m_exceptions; // Exception handlers or null if there are none.
private const int DefaultMaxStack = 16;
private int m_maxStack = DefaultMaxStack;
// Flags
internal bool m_bIsBaked;
private bool m_bIsGlobalMethod;
private bool m_fInitLocals; // indicating if the method stack frame will be zero initialized or not.
// Attributes
private MethodAttributes m_iAttributes;
private CallingConventions m_callingConvention;
private MethodImplAttributes m_dwMethodImplFlags;
// Parameters
private SignatureHelper m_signature;
internal Type[] m_parameterTypes;
private ParameterBuilder m_retParam;
private Type m_returnType;
private Type[] m_returnTypeRequiredCustomModifiers;
private Type[] m_returnTypeOptionalCustomModifiers;
private Type[][] m_parameterTypeRequiredCustomModifiers;
private Type[][] m_parameterTypeOptionalCustomModifiers;
// Generics
private GenericTypeParameterBuilder[] m_inst;
private bool m_bIsGenMethDef;
#endregion
#region Constructor
internal MethodBuilder(String name, MethodAttributes attributes, CallingConventions callingConvention,
Type returnType, Type[] parameterTypes, ModuleBuilder mod, TypeBuilder type, bool bIsGlobalMethod)
{
Init(name, attributes, callingConvention, returnType, null, null, parameterTypes, null, null, mod, type, bIsGlobalMethod);
}
internal MethodBuilder(String name, MethodAttributes attributes, CallingConventions callingConvention,
Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers,
Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers,
ModuleBuilder mod, TypeBuilder type, bool bIsGlobalMethod)
{
Init(name, attributes, callingConvention,
returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers,
parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers,
mod, type, bIsGlobalMethod);
}
private void Init(String name, MethodAttributes attributes, CallingConventions callingConvention,
Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers,
Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers,
ModuleBuilder mod, TypeBuilder type, bool bIsGlobalMethod)
{
if (name == null)
throw new ArgumentNullException("name");
if (name.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "name");
if (name[0] == '\0')
throw new ArgumentException(Environment.GetResourceString("Argument_IllegalName"), "name");
if (mod == null)
throw new ArgumentNullException("mod");
Contract.EndContractBlock();
if (parameterTypes != null)
{
foreach(Type t in parameterTypes)
{
if (t == null)
throw new ArgumentNullException("parameterTypes");
}
}
m_strName = name;
m_module = mod;
m_containingType = type;
//
//if (returnType == null)
//{
// m_returnType = typeof(void);
//}
//else
{
m_returnType = returnType;
}
if ((attributes & MethodAttributes.Static) == 0)
{
// turn on the has this calling convention
callingConvention = callingConvention | CallingConventions.HasThis;
}
else if ((attributes & MethodAttributes.Virtual) != 0)
{
// A method can't be both static and virtual
throw new ArgumentException(Environment.GetResourceString("Arg_NoStaticVirtual"));
}
if ((attributes & MethodAttributes.SpecialName) != MethodAttributes.SpecialName)
{
if ((type.Attributes & TypeAttributes.Interface) == TypeAttributes.Interface)
{
// methods on interface have to be abstract + virtual except special name methods such as type initializer
if ((attributes & (MethodAttributes.Abstract | MethodAttributes.Virtual)) !=
(MethodAttributes.Abstract | MethodAttributes.Virtual) &&
(attributes & MethodAttributes.Static) == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_BadAttributeOnInterfaceMethod"));
}
}
m_callingConvention = callingConvention;
if (parameterTypes != null)
{
m_parameterTypes = new Type[parameterTypes.Length];
Array.Copy(parameterTypes, m_parameterTypes, parameterTypes.Length);
}
else
{
m_parameterTypes = null;
}
m_returnTypeRequiredCustomModifiers = returnTypeRequiredCustomModifiers;
m_returnTypeOptionalCustomModifiers = returnTypeOptionalCustomModifiers;
m_parameterTypeRequiredCustomModifiers = parameterTypeRequiredCustomModifiers;
m_parameterTypeOptionalCustomModifiers = parameterTypeOptionalCustomModifiers;
// m_signature = SignatureHelper.GetMethodSigHelper(mod, callingConvention,
// returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers,
// parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers);
m_iAttributes = attributes;
m_bIsGlobalMethod = bIsGlobalMethod;
m_bIsBaked = false;
m_fInitLocals = true;
m_localSymInfo = new LocalSymInfo();
m_ubBody = null;
m_ilGenerator = null;
// Default is managed IL. Manged IL has bit flag 0x0020 set off
m_dwMethodImplFlags = MethodImplAttributes.IL;
}
#endregion
#region Internal Members
internal void CheckContext(params Type[][] typess)
{
m_module.CheckContext(typess);
}
internal void CheckContext(params Type[] types)
{
m_module.CheckContext(types);
}
[System.Security.SecurityCritical] // auto-generated
internal void CreateMethodBodyHelper(ILGenerator il)
{
// Sets the IL of the method. An ILGenerator is passed as an argument and the method
// queries this instance to get all of the information which it needs.
if (il == null)
{
throw new ArgumentNullException("il");
}
Contract.EndContractBlock();
__ExceptionInfo[] excp;
int counter=0;
int[] filterAddrs;
int[] catchAddrs;
int[] catchEndAddrs;
Type[] catchClass;
int[] type;
int numCatch;
int start, end;
ModuleBuilder dynMod = (ModuleBuilder) m_module;
m_containingType.ThrowIfCreated();
if (m_bIsBaked)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MethodHasBody"));
}
if (il.m_methodBuilder != this && il.m_methodBuilder != null)
{
// you don't need to call DefineBody when you get your ILGenerator
// through MethodBuilder::GetILGenerator.
//
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_BadILGeneratorUsage"));
}
ThrowIfShouldNotHaveBody();
if (il.m_ScopeTree.m_iOpenScopeCount != 0)
{
// There are still unclosed local scope
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_OpenLocalVariableScope"));
}
m_ubBody = il.BakeByteArray();
m_mdMethodFixups = il.GetTokenFixups();
//Okay, now the fun part. Calculate all of the exceptions.
excp = il.GetExceptions();
int numExceptions = CalculateNumberOfExceptions(excp);
if (numExceptions > 0)
{
m_exceptions = new ExceptionHandler[numExceptions];
for (int i = 0; i < excp.Length; i++)
{
filterAddrs = excp[i].GetFilterAddresses();
catchAddrs = excp[i].GetCatchAddresses();
catchEndAddrs = excp[i].GetCatchEndAddresses();
catchClass = excp[i].GetCatchClass();
numCatch = excp[i].GetNumberOfCatches();
start = excp[i].GetStartAddress();
end = excp[i].GetEndAddress();
type = excp[i].GetExceptionTypes();
for (int j = 0; j < numCatch; j++)
{
int tkExceptionClass = 0;
if (catchClass[j] != null)
{
tkExceptionClass = dynMod.GetTypeTokenInternal(catchClass[j]).Token;
}
switch (type[j])
{
case __ExceptionInfo.None:
case __ExceptionInfo.Fault:
case __ExceptionInfo.Filter:
m_exceptions[counter++] = new ExceptionHandler(start, end, filterAddrs[j], catchAddrs[j], catchEndAddrs[j], type[j], tkExceptionClass);
break;
case __ExceptionInfo.Finally:
m_exceptions[counter++] = new ExceptionHandler(start, excp[i].GetFinallyEndAddress(), filterAddrs[j], catchAddrs[j], catchEndAddrs[j], type[j], tkExceptionClass);
break;
}
}
}
}
m_bIsBaked=true;
if (dynMod.GetSymWriter() != null)
{
// set the debugging information such as scope and line number
// if it is in a debug module
//
SymbolToken tk = new SymbolToken(MetadataTokenInternal);
ISymbolWriter symWriter = dynMod.GetSymWriter();
// call OpenMethod to make this method the current method
symWriter.OpenMethod(tk);
// call OpenScope because OpenMethod no longer implicitly creating
// the top-levelsmethod scope
//
symWriter.OpenScope(0);
if (m_symCustomAttrs != null)
{
foreach(SymCustomAttr symCustomAttr in m_symCustomAttrs)
dynMod.GetSymWriter().SetSymAttribute(
new SymbolToken (MetadataTokenInternal),
symCustomAttr.m_name,
symCustomAttr.m_data);
}
if (m_localSymInfo != null)
m_localSymInfo.EmitLocalSymInfo(symWriter);
il.m_ScopeTree.EmitScopeTree(symWriter);
il.m_LineNumberInfo.EmitLineNumberInfo(symWriter);
symWriter.CloseScope(il.ILOffset);
symWriter.CloseMethod();
}
}
// This is only called from TypeBuilder.CreateType after the method has been created
internal void ReleaseBakedStructures()
{
if (!m_bIsBaked)
{
// We don't need to do anything here if we didn't baked the method body
return;
}
m_ubBody = null;
m_localSymInfo = null;
m_mdMethodFixups = null;
m_localSignature = null;
m_exceptions = null;
}
internal override Type[] GetParameterTypes()
{
if (m_parameterTypes == null)
m_parameterTypes = EmptyArray<Type>.Value;
return m_parameterTypes;
}
internal static Type GetMethodBaseReturnType(MethodBase method)
{
MethodInfo mi = null;
ConstructorInfo ci = null;
if ( (mi = method as MethodInfo) != null )
{
return mi.ReturnType;
}
else if ( (ci = method as ConstructorInfo) != null)
{
return ci.GetReturnType();
}
else
{
Contract.Assert(false, "We should never get here!");
return null;
}
}
internal void SetToken(MethodToken token)
{
m_tkMethod = token;
}
internal byte[] GetBody()
{
// Returns the il bytes of this method.
// This il is not valid until somebody has called BakeByteArray
return m_ubBody;
}
internal int[] GetTokenFixups()
{
return m_mdMethodFixups;
}
[System.Security.SecurityCritical] // auto-generated
internal SignatureHelper GetMethodSignature()
{
if (m_parameterTypes == null)
m_parameterTypes = EmptyArray<Type>.Value;
m_signature = SignatureHelper.GetMethodSigHelper (m_module, m_callingConvention, m_inst != null ? m_inst.Length : 0,
m_returnType == null ? typeof(void) : m_returnType, m_returnTypeRequiredCustomModifiers, m_returnTypeOptionalCustomModifiers,
m_parameterTypes, m_parameterTypeRequiredCustomModifiers, m_parameterTypeOptionalCustomModifiers);
return m_signature;
}
// Returns a buffer whose initial signatureLength bytes contain encoded local signature.
internal byte[] GetLocalSignature(out int signatureLength)
{
if (m_localSignature != null)
{
signatureLength = m_localSignature.Length;
return m_localSignature;
}
if (m_ilGenerator != null)
{
if (m_ilGenerator.m_localCount != 0)
{
// If user is using ILGenerator::DeclareLocal, then get local signaturefrom there.
return m_ilGenerator.m_localSignature.InternalGetSignature(out signatureLength);
}
}
return SignatureHelper.GetLocalVarSigHelper(m_module).InternalGetSignature(out signatureLength);
}
internal int GetMaxStack()
{
if (m_ilGenerator != null)
{
return m_ilGenerator.GetMaxStackSize() + ExceptionHandlerCount;
}
else
{
// this is the case when client provide an array of IL byte stream rather than going through ILGenerator.
return m_maxStack;
}
}
internal ExceptionHandler[] GetExceptionHandlers()
{
return m_exceptions;
}
internal int ExceptionHandlerCount
{
get { return m_exceptions != null ? m_exceptions.Length : 0; }
}
internal int CalculateNumberOfExceptions(__ExceptionInfo[] excp)
{
int num=0;
if (excp==null)
{
return 0;
}
for (int i=0; i<excp.Length; i++)
{
num+=excp[i].GetNumberOfCatches();
}
return num;
}
internal bool IsTypeCreated()
{
return (m_containingType != null && m_containingType.IsCreated());
}
internal TypeBuilder GetTypeBuilder()
{
return m_containingType;
}
internal ModuleBuilder GetModuleBuilder()
{
return m_module;
}
#endregion
#region Object Overrides
[System.Security.SecuritySafeCritical] // auto-generated
public override bool Equals(Object obj) {
if (!(obj is MethodBuilder)) {
return false;
}
if (!(this.m_strName.Equals(((MethodBuilder)obj).m_strName))) {
return false;
}
if (m_iAttributes!=(((MethodBuilder)obj).m_iAttributes)) {
return false;
}
SignatureHelper thatSig = ((MethodBuilder)obj).GetMethodSignature();
if (thatSig.Equals(GetMethodSignature())) {
return true;
}
return false;
}
public override int GetHashCode()
{
return this.m_strName.GetHashCode();
}
[System.Security.SecuritySafeCritical] // auto-generated
public override String ToString()
{
StringBuilder sb = new StringBuilder(1000);
sb.Append("Name: " + m_strName + " " + Environment.NewLine);
sb.Append("Attributes: " + (int)m_iAttributes + Environment.NewLine);
sb.Append("Method Signature: " + GetMethodSignature() + Environment.NewLine);
sb.Append(Environment.NewLine);
return sb.ToString();
}
#endregion
#region MemberInfo Overrides
public override String Name
{
get
{
return m_strName;
}
}
internal int MetadataTokenInternal
{
get
{
return GetToken().Token;
}
}
public override Module Module
{
get
{
return m_containingType.Module;
}
}
public override Type DeclaringType
{
get
{
if (m_containingType.m_isHiddenGlobalType == true)
return null;
return m_containingType;
}
}
public override ICustomAttributeProvider ReturnTypeCustomAttributes
{
get
{
return null;
}
}
public override Type ReflectedType
{
get
{
return DeclaringType;
}
}
#endregion
#region MethodBase Overrides
public override Object Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_DynamicModule"));
}
public override MethodImplAttributes GetMethodImplementationFlags()
{
return m_dwMethodImplFlags;
}
public override MethodAttributes Attributes
{
get { return m_iAttributes; }
}
public override CallingConventions CallingConvention
{
get {return m_callingConvention;}
}
public override RuntimeMethodHandle MethodHandle
{
get { throw new NotSupportedException(Environment.GetResourceString("NotSupported_DynamicModule")); }
}
public override bool IsSecurityCritical
{
get { throw new NotSupportedException(Environment.GetResourceString("NotSupported_DynamicModule")); }
}
public override bool IsSecuritySafeCritical
{
get { throw new NotSupportedException(Environment.GetResourceString("NotSupported_DynamicModule")); }
}
public override bool IsSecurityTransparent
{
get { throw new NotSupportedException(Environment.GetResourceString("NotSupported_DynamicModule")); }
}
#endregion
#region MethodInfo Overrides
public override MethodInfo GetBaseDefinition()
{
return this;
}
public override Type ReturnType
{
get
{
return m_returnType;
}
}
[Pure]
public override ParameterInfo[] GetParameters()
{
if (!m_bIsBaked || m_containingType == null || m_containingType.BakedRuntimeType == null)
throw new NotSupportedException(Environment.GetResourceString("InvalidOperation_TypeNotCreated"));
MethodInfo rmi = m_containingType.GetMethod(m_strName, m_parameterTypes);
return rmi.GetParameters();
}
public override ParameterInfo ReturnParameter
{
get
{
if (!m_bIsBaked || m_containingType == null || m_containingType.BakedRuntimeType == null)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TypeNotCreated"));
MethodInfo rmi = m_containingType.GetMethod(m_strName, m_parameterTypes);
return rmi.ReturnParameter;
}
}
#endregion
#region ICustomAttributeProvider Implementation
public override Object[] GetCustomAttributes(bool inherit)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_DynamicModule"));
}
public override Object[] GetCustomAttributes(Type attributeType, bool inherit)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_DynamicModule"));
}
public override bool IsDefined(Type attributeType, bool inherit)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_DynamicModule"));
}
#endregion
#region Generic Members
public override bool IsGenericMethodDefinition { get { return m_bIsGenMethDef; } }
public override bool ContainsGenericParameters { get { throw new NotSupportedException(); } }
public override MethodInfo GetGenericMethodDefinition() { if (!IsGenericMethod) throw new InvalidOperationException(); return this; }
public override bool IsGenericMethod { get { return m_inst != null; } }
public override Type[] GetGenericArguments() { return m_inst; }
public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
{
return MethodBuilderInstantiation.MakeGenericMethod(this, typeArguments);
}
public GenericTypeParameterBuilder[] DefineGenericParameters (params string[] names)
{
if (names == null)
throw new ArgumentNullException("names");
if (names.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Arg_EmptyArray"), "names");
Contract.EndContractBlock();
if (m_inst != null)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_GenericParametersAlreadySet"));
for (int i = 0; i < names.Length; i ++)
if (names[i] == null)
throw new ArgumentNullException("names");
if (m_tkMethod.Token != 0)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MethodBuilderBaked"));
m_bIsGenMethDef = true;
m_inst = new GenericTypeParameterBuilder[names.Length];
for (int i = 0; i < names.Length; i ++)
m_inst[i] = new GenericTypeParameterBuilder(new TypeBuilder(names[i], i, this));
return m_inst;
}
internal void ThrowIfGeneric () { if (IsGenericMethod && !IsGenericMethodDefinition) throw new InvalidOperationException (); }
#endregion
#region Public Members
[System.Security.SecuritySafeCritical] // auto-generated
public MethodToken GetToken()
{
// We used to always "tokenize" a MethodBuilder when it is constructed. After change list 709498
// we only "tokenize" a method when requested. But the order in which the methods are tokenized
// didn't change: the same order the MethodBuilders are constructed. The recursion introduced
// will overflow the stack when there are many methods on the same type (10000 in my experiment).
// The change also introduced race conditions. Before the code change GetToken is called from
// the MethodBuilder .ctor which is protected by lock(ModuleBuilder.SyncRoot). Now it
// could be called more than once on the the same method introducing duplicate (invalid) tokens.
// I don't fully understand this change. So I will keep the logic and only fix the recursion and
// the race condition.
if (m_tkMethod.Token != 0)
{
return m_tkMethod;
}
MethodBuilder currentMethod = null;
MethodToken currentToken = new MethodToken(0);
int i;
// We need to lock here to prevent a method from being "tokenized" twice.
// We don't need to synchronize this with Type.DefineMethod because it only appends newly
// constructed MethodBuilders to the end of m_listMethods
lock (m_containingType.m_listMethods)
{
if (m_tkMethod.Token != 0)
{
return m_tkMethod;
}
// If m_tkMethod is still 0 when we obtain the lock, m_lastTokenizedMethod must be smaller
// than the index of the current method.
for (i = m_containingType.m_lastTokenizedMethod + 1; i < m_containingType.m_listMethods.Count; ++i)
{
currentMethod = m_containingType.m_listMethods[i];
currentToken = currentMethod.GetTokenNoLock();
if (currentMethod == this)
break;
}
m_containingType.m_lastTokenizedMethod = i;
}
Contract.Assert(currentMethod == this, "We should have found this method in m_containingType.m_listMethods");
Contract.Assert(currentToken.Token != 0, "The token should not be 0");
return currentToken;
}
[System.Security.SecurityCritical] // auto-generated
private MethodToken GetTokenNoLock()
{
Contract.Assert(m_tkMethod.Token == 0, "m_tkMethod should not have been initialized");
int sigLength;
byte[] sigBytes = GetMethodSignature().InternalGetSignature(out sigLength);
int token = TypeBuilder.DefineMethod(m_module.GetNativeHandle(), m_containingType.MetadataTokenInternal, m_strName, sigBytes, sigLength, Attributes);
m_tkMethod = new MethodToken(token);
if (m_inst != null)
foreach (GenericTypeParameterBuilder tb in m_inst)
if (!tb.m_type.IsCreated()) tb.m_type.CreateType();
TypeBuilder.SetMethodImpl(m_module.GetNativeHandle(), token, m_dwMethodImplFlags);
return m_tkMethod;
}
public void SetParameters (params Type[] parameterTypes)
{
CheckContext(parameterTypes);
SetSignature (null, null, null, parameterTypes, null, null);
}
public void SetReturnType (Type returnType)
{
CheckContext(returnType);
SetSignature (returnType, null, null, null, null, null);
}
public void SetSignature(
Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers,
Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
{
// We should throw InvalidOperation_MethodBuilderBaked here if the method signature has been baked.
// But we cannot because that would be a breaking change from V2.
if (m_tkMethod.Token != 0)
return;
CheckContext(returnType);
CheckContext(returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers, parameterTypes);
CheckContext(parameterTypeRequiredCustomModifiers);
CheckContext(parameterTypeOptionalCustomModifiers);
ThrowIfGeneric();
if (returnType != null)
{
m_returnType = returnType;
}
if (parameterTypes != null)
{
m_parameterTypes = new Type[parameterTypes.Length];
Array.Copy (parameterTypes, m_parameterTypes, parameterTypes.Length);
}
m_returnTypeRequiredCustomModifiers = returnTypeRequiredCustomModifiers;
m_returnTypeOptionalCustomModifiers = returnTypeOptionalCustomModifiers;
m_parameterTypeRequiredCustomModifiers = parameterTypeRequiredCustomModifiers;
m_parameterTypeOptionalCustomModifiers = parameterTypeOptionalCustomModifiers;
}
[System.Security.SecuritySafeCritical] // auto-generated
public ParameterBuilder DefineParameter(int position, ParameterAttributes attributes, String strParamName)
{
if (position < 0)
throw new ArgumentOutOfRangeException(Environment.GetResourceString("ArgumentOutOfRange_ParamSequence"));
Contract.EndContractBlock();
ThrowIfGeneric();
m_containingType.ThrowIfCreated ();
if (position > 0 && (m_parameterTypes == null || position > m_parameterTypes.Length))
throw new ArgumentOutOfRangeException(Environment.GetResourceString("ArgumentOutOfRange_ParamSequence"));
attributes = attributes & ~ParameterAttributes.ReservedMask;
return new ParameterBuilder(this, position, attributes, strParamName);
}
[System.Security.SecuritySafeCritical] // auto-generated
[Obsolete("An alternate API is available: Emit the MarshalAs custom attribute instead. http://go.microsoft.com/fwlink/?linkid=14202")]
public void SetMarshal(UnmanagedMarshal unmanagedMarshal)
{
ThrowIfGeneric ();
// set Marshal info for the return type
m_containingType.ThrowIfCreated();
if (m_retParam == null)
{
m_retParam = new ParameterBuilder(this, 0, 0, null);
}
m_retParam.SetMarshal(unmanagedMarshal);
}
private List<SymCustomAttr> m_symCustomAttrs;
private struct SymCustomAttr
{
public SymCustomAttr(String name, byte[] data)
{
m_name = name;
m_data = data;
}
public String m_name;
public byte[] m_data;
}
public void SetSymCustomAttribute(String name, byte[] data)
{
// Note that this API is rarely used. Support for custom attributes in PDB files was added in
// Whidbey and as of 8/2007 the only known user is the C# compiler. There seems to be little
// value to this for Reflection.Emit users since they can always use metadata custom attributes.
// Some versions of the symbol writer used in the CLR will ignore these entirely. This API has
// been removed from the Silverlight API surface area, but we should also consider removing it
// from future desktop product versions as well.
ThrowIfGeneric ();
// This is different from CustomAttribute. This is stored into the SymWriter.
m_containingType.ThrowIfCreated();
ModuleBuilder dynMod = (ModuleBuilder) m_module;
if ( dynMod.GetSymWriter() == null)
{
// Cannot SetSymCustomAttribute when it is not a debug module
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotADebugModule"));
}
if (m_symCustomAttrs == null)
m_symCustomAttrs = new List<SymCustomAttr>();
m_symCustomAttrs.Add(new SymCustomAttr(name, data));
}
#if FEATURE_CAS_POLICY
[System.Security.SecuritySafeCritical] // auto-generated
public void AddDeclarativeSecurity(SecurityAction action, PermissionSet pset)
{
if (pset == null)
throw new ArgumentNullException("pset");
Contract.EndContractBlock();
ThrowIfGeneric ();
#pragma warning disable 618
if (!Enum.IsDefined(typeof(SecurityAction), action) ||
action == SecurityAction.RequestMinimum ||
action == SecurityAction.RequestOptional ||
action == SecurityAction.RequestRefuse)
{
throw new ArgumentOutOfRangeException("action");
}
#pragma warning restore 618
// cannot declarative security after type is created
m_containingType.ThrowIfCreated();
// Translate permission set into serialized format (uses standard binary serialization format).
byte[] blob = null;
int length = 0;
if (!pset.IsEmpty())
{
blob = pset.EncodeXml();
length = blob.Length;
}
// Write the blob into the metadata.
TypeBuilder.AddDeclarativeSecurity(m_module.GetNativeHandle(), MetadataTokenInternal, action, blob, length);
}
#endif // FEATURE_CAS_POLICY
#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#endif
public void SetMethodBody(byte[] il, int maxStack, byte[] localSignature, IEnumerable<ExceptionHandler> exceptionHandlers, IEnumerable<int> tokenFixups)
{
if (il == null)
{
throw new ArgumentNullException("il", Environment.GetResourceString("ArgumentNull_Array"));
}
if (maxStack < 0)
{
throw new ArgumentOutOfRangeException("maxStack", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
Contract.EndContractBlock();
if (m_bIsBaked)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MethodBaked"));
}
m_containingType.ThrowIfCreated();
ThrowIfGeneric();
byte[] newLocalSignature = null;
ExceptionHandler[] newHandlers = null;
int[] newTokenFixups = null;
byte[] newIL = (byte[])il.Clone();
if (localSignature != null)
{
newLocalSignature = (byte[])localSignature.Clone();
}
if (exceptionHandlers != null)
{
newHandlers = ToArray(exceptionHandlers);
CheckExceptionHandlerRanges(newHandlers, newIL.Length);
// Note: Fixup entries for type tokens stored in ExceptionHandlers are added by the method body emitter.
}
if (tokenFixups != null)
{
newTokenFixups = ToArray(tokenFixups);
int maxTokenOffset = newIL.Length - 4;
for (int i = 0; i < newTokenFixups.Length; i++)
{
// Check that fixups are within the range of this method's IL, otherwise some random memory might get "fixed up".
if (newTokenFixups[i] < 0 || newTokenFixups[i] > maxTokenOffset)
{
throw new ArgumentOutOfRangeException("tokenFixups[" + i + "]", Environment.GetResourceString("ArgumentOutOfRange_Range", 0, maxTokenOffset));
}
}
}
m_ubBody = newIL;
m_localSignature = newLocalSignature;
m_exceptions = newHandlers;
m_mdMethodFixups = newTokenFixups;
m_maxStack = maxStack;
// discard IL generator, all information stored in it is now irrelevant
m_ilGenerator = null;
m_bIsBaked = true;
}
private static T[] ToArray<T>(IEnumerable<T> sequence)
{
T[] array = sequence as T[];
if (array != null)
{
return (T[])array.Clone();
}
return new List<T>(sequence).ToArray();
}
private static void CheckExceptionHandlerRanges(ExceptionHandler[] exceptionHandlers, int maxOffset)
{
// Basic checks that the handler ranges are within the method body (ranges are end-exclusive).
// Doesn't verify that the ranges are otherwise correct - it is very well possible to emit invalid IL.
for (int i = 0; i < exceptionHandlers.Length; i++)
{
var handler = exceptionHandlers[i];
if (handler.m_filterOffset > maxOffset || handler.m_tryEndOffset > maxOffset || handler.m_handlerEndOffset > maxOffset)
{
throw new ArgumentOutOfRangeException("exceptionHandlers[" + i + "]", Environment.GetResourceString("ArgumentOutOfRange_Range", 0, maxOffset));
}
// Type token might be 0 if the ExceptionHandler was created via a default constructor.
// Other tokens migth also be invalid. We only check nil tokens as the implementation (SectEH_Emit in corhlpr.cpp) requires it,
// and we can't check for valid tokens until the module is baked.
if (handler.Kind == ExceptionHandlingClauseOptions.Clause && handler.ExceptionTypeToken == 0)
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidTypeToken", handler.ExceptionTypeToken), "exceptionHandlers[" + i + "]");
}
}
}
/// <summary>
/// Obsolete.
/// </summary>
#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#endif
public void CreateMethodBody(byte[] il, int count)
{
ThrowIfGeneric();
// Note that when user calls this function, there are a few information that client is
// not able to supply: local signature, exception handlers, max stack size, a list of Token fixup, a list of RVA fixup
if (m_bIsBaked)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MethodBaked"));
}
m_containingType.ThrowIfCreated();
if (il != null && (count < 0 || count > il.Length))
{
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (il == null)
{
m_ubBody = null;
return;
}
m_ubBody = new byte[count];
Array.Copy(il,m_ubBody,count);
m_localSignature = null;
m_exceptions = null;
m_mdMethodFixups = null;
m_maxStack = DefaultMaxStack;
m_bIsBaked = true;
}
[System.Security.SecuritySafeCritical] // auto-generated
public void SetImplementationFlags(MethodImplAttributes attributes)
{
ThrowIfGeneric ();
m_containingType.ThrowIfCreated ();
m_dwMethodImplFlags = attributes;
m_canBeRuntimeImpl = true;
TypeBuilder.SetMethodImpl(m_module.GetNativeHandle(), MetadataTokenInternal, attributes);
}
public ILGenerator GetILGenerator() {
Contract.Ensures(Contract.Result<ILGenerator>() != null);
ThrowIfGeneric();
ThrowIfShouldNotHaveBody();
if (m_ilGenerator == null)
m_ilGenerator = new ILGenerator(this);
return m_ilGenerator;
}
public ILGenerator GetILGenerator(int size) {
Contract.Ensures(Contract.Result<ILGenerator>() != null);
ThrowIfGeneric ();
ThrowIfShouldNotHaveBody();
if (m_ilGenerator == null)
m_ilGenerator = new ILGenerator(this, size);
return m_ilGenerator;
}
private void ThrowIfShouldNotHaveBody() {
if ((m_dwMethodImplFlags & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.IL ||
(m_dwMethodImplFlags & MethodImplAttributes.Unmanaged) != 0 ||
(m_iAttributes & MethodAttributes.PinvokeImpl) != 0 ||
m_isDllImport)
{
// cannot attach method body if methodimpl is marked not marked as managed IL
//
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ShouldNotHaveMethodBody"));
}
}
public bool InitLocals
{
// Property is set to true if user wishes to have zero initialized stack frame for this method. Default to false.
get { ThrowIfGeneric (); return m_fInitLocals; }
set { ThrowIfGeneric (); m_fInitLocals = value; }
}
public Module GetModule()
{
return GetModuleBuilder();
}
public String Signature
{
[System.Security.SecuritySafeCritical] // auto-generated
get
{
return GetMethodSignature().ToString();
}
}
#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#else
[System.Security.SecuritySafeCritical]
#endif
[System.Runtime.InteropServices.ComVisible(true)]
public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
{
if (con == null)
throw new ArgumentNullException("con");
if (binaryAttribute == null)
throw new ArgumentNullException("binaryAttribute");
Contract.EndContractBlock();
ThrowIfGeneric();
TypeBuilder.DefineCustomAttribute(m_module, MetadataTokenInternal,
((ModuleBuilder)m_module).GetConstructorToken(con).Token,
binaryAttribute,
false, false);
if (IsKnownCA(con))
ParseCA(con, binaryAttribute);
}
[System.Security.SecuritySafeCritical] // auto-generated
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
if (customBuilder == null)
throw new ArgumentNullException("customBuilder");
Contract.EndContractBlock();
ThrowIfGeneric();
customBuilder.CreateCustomAttribute((ModuleBuilder)m_module, MetadataTokenInternal);
if (IsKnownCA(customBuilder.m_con))
ParseCA(customBuilder.m_con, customBuilder.m_blob);
}
// this method should return true for any and every ca that requires more work
// than just setting the ca
private bool IsKnownCA(ConstructorInfo con)
{
Type caType = con.DeclaringType;
if (caType == typeof(System.Runtime.CompilerServices.MethodImplAttribute)) return true;
else if (caType == typeof(DllImportAttribute)) return true;
else return false;
}
private void ParseCA(ConstructorInfo con, byte[] blob)
{
Type caType = con.DeclaringType;
if (caType == typeof(System.Runtime.CompilerServices.MethodImplAttribute))
{
// dig through the blob looking for the MethodImplAttributes flag
// that must be in the MethodCodeType field
// for now we simply set a flag that relaxes the check when saving and
// allows this method to have no body when any kind of MethodImplAttribute is present
m_canBeRuntimeImpl = true;
}
else if (caType == typeof(DllImportAttribute)) {
m_canBeRuntimeImpl = true;
m_isDllImport = true;
}
}
internal bool m_canBeRuntimeImpl = false;
internal bool m_isDllImport = false;
#endregion
#if !FEATURE_CORECLR
void _MethodBuilder.GetTypeInfoCount(out uint pcTInfo)
{
throw new NotImplementedException();
}
void _MethodBuilder.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
{
throw new NotImplementedException();
}
void _MethodBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
{
throw new NotImplementedException();
}
void _MethodBuilder.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
{
throw new NotImplementedException();
}
#endif
}
internal class LocalSymInfo
{
// This class tracks the local variable's debugging information
// and namespace information with a given active lexical scope.
#region Internal Data Members
internal String[] m_strName;
internal byte[][] m_ubSignature;
internal int[] m_iLocalSlot;
internal int[] m_iStartOffset;
internal int[] m_iEndOffset;
internal int m_iLocalSymCount; // how many entries in the arrays are occupied
internal String[] m_namespace;
internal int m_iNameSpaceCount;
internal const int InitialSize = 16;
#endregion
#region Constructor
internal LocalSymInfo()
{
// initialize data variables
m_iLocalSymCount = 0;
m_iNameSpaceCount = 0;
}
#endregion
#region Private Members
private void EnsureCapacityNamespace()
{
if (m_iNameSpaceCount == 0)
{
m_namespace = new String[InitialSize];
}
else if (m_iNameSpaceCount == m_namespace.Length)
{
String [] strTemp = new String [checked(m_iNameSpaceCount * 2)];
Array.Copy(m_namespace, strTemp, m_iNameSpaceCount);
m_namespace = strTemp;
}
}
private void EnsureCapacity()
{
if (m_iLocalSymCount == 0)
{
// First time. Allocate the arrays.
m_strName = new String[InitialSize];
m_ubSignature = new byte[InitialSize][];
m_iLocalSlot = new int[InitialSize];
m_iStartOffset = new int[InitialSize];
m_iEndOffset = new int[InitialSize];
}
else if (m_iLocalSymCount == m_strName.Length)
{
// the arrays are full. Enlarge the arrays
// why aren't we just using lists here?
int newSize = checked(m_iLocalSymCount * 2);
int[] temp = new int [newSize];
Array.Copy(m_iLocalSlot, temp, m_iLocalSymCount);
m_iLocalSlot = temp;
temp = new int [newSize];
Array.Copy(m_iStartOffset, temp, m_iLocalSymCount);
m_iStartOffset = temp;
temp = new int [newSize];
Array.Copy(m_iEndOffset, temp, m_iLocalSymCount);
m_iEndOffset = temp;
String [] strTemp = new String [newSize];
Array.Copy(m_strName, strTemp, m_iLocalSymCount);
m_strName = strTemp;
byte[][] ubTemp = new byte[newSize][];
Array.Copy(m_ubSignature, ubTemp, m_iLocalSymCount);
m_ubSignature = ubTemp;
}
}
#endregion
#region Internal Members
internal void AddLocalSymInfo(String strName,byte[] signature,int slot,int startOffset,int endOffset)
{
// make sure that arrays are large enough to hold addition info
EnsureCapacity();
m_iStartOffset[m_iLocalSymCount] = startOffset;
m_iEndOffset[m_iLocalSymCount] = endOffset;
m_iLocalSlot[m_iLocalSymCount] = slot;
m_strName[m_iLocalSymCount] = strName;
m_ubSignature[m_iLocalSymCount] = signature;
checked {m_iLocalSymCount++; }
}
internal void AddUsingNamespace(String strNamespace)
{
EnsureCapacityNamespace();
m_namespace[m_iNameSpaceCount] = strNamespace;
checked { m_iNameSpaceCount++; }
}
#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#endif
internal virtual void EmitLocalSymInfo(ISymbolWriter symWriter)
{
int i;
for (i = 0; i < m_iLocalSymCount; i ++)
{
symWriter.DefineLocalVariable(
m_strName[i],
FieldAttributes.PrivateScope,
m_ubSignature[i],
SymAddressKind.ILOffset,
m_iLocalSlot[i],
0, // addr2 is not used yet
0, // addr3 is not used
m_iStartOffset[i],
m_iEndOffset[i]);
}
for (i = 0; i < m_iNameSpaceCount; i ++)
{
symWriter.UsingNamespace(m_namespace[i]);
}
}
#endregion
}
/// <summary>
/// Describes exception handler in a method body.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[ComVisible(false)]
public struct ExceptionHandler : IEquatable<ExceptionHandler>
{
// Keep in sync with unmanged structure.
internal readonly int m_exceptionClass;
internal readonly int m_tryStartOffset;
internal readonly int m_tryEndOffset;
internal readonly int m_filterOffset;
internal readonly int m_handlerStartOffset;
internal readonly int m_handlerEndOffset;
internal readonly ExceptionHandlingClauseOptions m_kind;
public int ExceptionTypeToken
{
get { return m_exceptionClass; }
}
public int TryOffset
{
get { return m_tryStartOffset; }
}
public int TryLength
{
get { return m_tryEndOffset - m_tryStartOffset; }
}
public int FilterOffset
{
get { return m_filterOffset; }
}
public int HandlerOffset
{
get { return m_handlerStartOffset; }
}
public int HandlerLength
{
get { return m_handlerEndOffset - m_handlerStartOffset; }
}
public ExceptionHandlingClauseOptions Kind
{
get { return m_kind; }
}
#region Constructors
/// <summary>
/// Creates a description of an exception handler.
/// </summary>
/// <param name="tryOffset">The offset of the first instruction protected by this handler.</param>
/// <param name="tryLength">The number of bytes protected by this handler.</param>
/// <param name="filterOffset">The filter code begins at the specified offset and ends at the first instruction of the handler block. Specify 0 if not applicable (this is not a filter handler).</param>
/// <param name="handlerOffset">The offset of the first instruction of this handler.</param>
/// <param name="handlerLength">The number of bytes of the handler.</param>
/// <param name="kind">The kind of handler, the handler might be a catch handler, filter handler, fault handler, or finally handler.</param>
/// <param name="exceptionTypeToken">The token of the exception type handled by this handler. Specify 0 if not applicable (this is finally handler).</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Some of the instruction offset is negative,
/// the end offset of specified range is less than its start offset,
/// or <paramref name="kind"/> has an invalid value.
/// </exception>
public ExceptionHandler(int tryOffset, int tryLength, int filterOffset, int handlerOffset, int handlerLength,
ExceptionHandlingClauseOptions kind, int exceptionTypeToken)
{
if (tryOffset < 0)
{
throw new ArgumentOutOfRangeException("tryOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (tryLength < 0)
{
throw new ArgumentOutOfRangeException("tryLength", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (filterOffset < 0)
{
throw new ArgumentOutOfRangeException("filterOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (handlerOffset < 0)
{
throw new ArgumentOutOfRangeException("handlerOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (handlerLength < 0)
{
throw new ArgumentOutOfRangeException("handlerLength", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if ((long)tryOffset + tryLength > Int32.MaxValue)
{
throw new ArgumentOutOfRangeException("tryLength", Environment.GetResourceString("ArgumentOutOfRange_Range", 0, Int32.MaxValue - tryOffset));
}
if ((long)handlerOffset + handlerLength > Int32.MaxValue)
{
throw new ArgumentOutOfRangeException("handlerLength", Environment.GetResourceString("ArgumentOutOfRange_Range", 0, Int32.MaxValue - handlerOffset));
}
// Other tokens migth also be invalid. We only check nil tokens as the implementation (SectEH_Emit in corhlpr.cpp) requires it,
// and we can't check for valid tokens until the module is baked.
if (kind == ExceptionHandlingClauseOptions.Clause && (exceptionTypeToken & 0x00FFFFFF) == 0)
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidTypeToken", exceptionTypeToken), "exceptionTypeToken");
}
Contract.EndContractBlock();
if (!IsValidKind(kind))
{
throw new ArgumentOutOfRangeException("kind", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
}
m_tryStartOffset = tryOffset;
m_tryEndOffset = tryOffset + tryLength;
m_filterOffset = filterOffset;
m_handlerStartOffset = handlerOffset;
m_handlerEndOffset = handlerOffset + handlerLength;
m_kind = kind;
m_exceptionClass = exceptionTypeToken;
}
internal ExceptionHandler(int tryStartOffset, int tryEndOffset, int filterOffset, int handlerStartOffset, int handlerEndOffset,
int kind, int exceptionTypeToken)
{
Contract.Assert(tryStartOffset >= 0);
Contract.Assert(tryEndOffset >= 0);
Contract.Assert(filterOffset >= 0);
Contract.Assert(handlerStartOffset >= 0);
Contract.Assert(handlerEndOffset >= 0);
Contract.Assert(IsValidKind((ExceptionHandlingClauseOptions)kind));
Contract.Assert(kind != (int)ExceptionHandlingClauseOptions.Clause || (exceptionTypeToken & 0x00FFFFFF) != 0);
m_tryStartOffset = tryStartOffset;
m_tryEndOffset = tryEndOffset;
m_filterOffset = filterOffset;
m_handlerStartOffset = handlerStartOffset;
m_handlerEndOffset = handlerEndOffset;
m_kind = (ExceptionHandlingClauseOptions)kind;
m_exceptionClass = exceptionTypeToken;
}
private static bool IsValidKind(ExceptionHandlingClauseOptions kind)
{
switch (kind)
{
case ExceptionHandlingClauseOptions.Clause:
case ExceptionHandlingClauseOptions.Filter:
case ExceptionHandlingClauseOptions.Finally:
case ExceptionHandlingClauseOptions.Fault:
return true;
default:
return false;
}
}
#endregion
#region Equality
public override int GetHashCode()
{
return m_exceptionClass ^ m_tryStartOffset ^ m_tryEndOffset ^ m_filterOffset ^ m_handlerStartOffset ^ m_handlerEndOffset ^ (int)m_kind;
}
public override bool Equals(Object obj)
{
return obj is ExceptionHandler && Equals((ExceptionHandler)obj);
}
public bool Equals(ExceptionHandler other)
{
return
other.m_exceptionClass == m_exceptionClass &&
other.m_tryStartOffset == m_tryStartOffset &&
other.m_tryEndOffset == m_tryEndOffset &&
other.m_filterOffset == m_filterOffset &&
other.m_handlerStartOffset == m_handlerStartOffset &&
other.m_handlerEndOffset == m_handlerEndOffset &&
other.m_kind == m_kind;
}
public static bool operator ==(ExceptionHandler left, ExceptionHandler right)
{
return left.Equals(right);
}
public static bool operator !=(ExceptionHandler left, ExceptionHandler right)
{
return !left.Equals(right);
}
#endregion
}
}
|