|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Reflection.Emit
{
internal sealed partial class RuntimeModuleBuilder : ModuleBuilder
{
internal static string UnmangleTypeName(string typeName)
{
// Gets the original type name, without '+' name mangling.
int i = typeName.Length - 1;
while (true)
{
i = typeName.LastIndexOf('+', i);
if (i < 0)
{
break;
}
bool evenSlashes = true;
int iSlash = i;
while (typeName[--iSlash] == '\\')
{
evenSlashes = !evenSlashes;
}
// Even number of slashes means this '+' is a name separator
if (evenSlashes)
{
break;
}
i = iSlash;
}
return typeName.Substring(i + 1);
}
#region Internal Data Members
// _typeBuilderDict contains both TypeBuilder and EnumBuilder objects
private readonly Dictionary<string, Type> _typeBuilderDict;
private readonly TypeBuilder _globalTypeBuilder;
private bool _hasGlobalBeenCreated;
internal readonly RuntimeModule _internalModule;
// This is the "external" AssemblyBuilder
// only the "external" ModuleBuilder has this set
private readonly RuntimeAssemblyBuilder _assemblyBuilder;
internal RuntimeAssemblyBuilder ContainingAssemblyBuilder => _assemblyBuilder;
internal const string ManifestModuleName = "RefEmit_InMemoryManifestModule";
#endregion
#region Constructor
internal RuntimeModuleBuilder(RuntimeAssemblyBuilder assemblyBuilder, RuntimeModule internalModule)
{
_internalModule = internalModule;
_assemblyBuilder = assemblyBuilder;
_globalTypeBuilder = new RuntimeTypeBuilder(this);
_typeBuilderDict = new Dictionary<string, Type>();
}
#endregion
#region Private Members
internal void AddType(string name, Type type) => _typeBuilderDict.Add(name, type);
internal void CheckTypeNameConflict(string strTypeName, Type? enclosingType)
{
if (_typeBuilderDict.TryGetValue(strTypeName, out Type? foundType) &&
ReferenceEquals(foundType.DeclaringType, enclosingType))
{
// Cannot have two types with the same name
throw new ArgumentException(SR.Argument_DuplicateTypeName);
}
}
private static Type? GetType(string strFormat, Type baseType)
{
// This function takes a string to describe the compound type, such as "[,][]", and a baseType.
if (string.IsNullOrEmpty(strFormat))
{
return baseType;
}
// convert the format string to byte array and then call FormCompoundType
return SymbolType.FormCompoundType(strFormat, baseType, 0);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_GetTypeRef", StringMarshalling = StringMarshalling.Utf16)]
private static partial int GetTypeRef(QCallModule module, string strFullName, QCallModule refedModule, int tkResolution);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_GetMemberRef")]
private static partial int GetMemberRef(QCallModule module, QCallModule refedModule, int tr, int defToken);
private int GetMemberRef(Module? refedModule, int tr, int defToken)
{
RuntimeModuleBuilder thisModule = this;
RuntimeModule refedRuntimeModule = GetRuntimeModuleFromModule(refedModule);
return GetMemberRef(new QCallModule(ref thisModule), new QCallModule(ref refedRuntimeModule), tr, defToken);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_GetMemberRefFromSignature", StringMarshalling = StringMarshalling.Utf16)]
private static partial int GetMemberRefFromSignature(QCallModule module, int tr, string methodName, byte[] signature, int length);
private int GetMemberRefFromSignature(int tr, string methodName, byte[] signature, int length)
{
RuntimeModuleBuilder thisModule = this;
return GetMemberRefFromSignature(new QCallModule(ref thisModule), tr, methodName, signature, length);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_GetMemberRefOfMethodInfo")]
private static partial int GetMemberRefOfMethodInfo(QCallModule module, int tr, RuntimeMethodHandleInternal method);
private int GetMemberRefOfMethodInfo(int tr, RuntimeMethodInfo method)
{
Debug.Assert(method != null);
RuntimeModuleBuilder thisModule = this;
int result = GetMemberRefOfMethodInfo(new QCallModule(ref thisModule), tr, ((IRuntimeMethodInfo)method).Value);
GC.KeepAlive(method);
return result;
}
private int GetMemberRefOfMethodInfo(int tr, RuntimeConstructorInfo method)
{
Debug.Assert(method != null);
RuntimeModuleBuilder thisModule = this;
int result = GetMemberRefOfMethodInfo(new QCallModule(ref thisModule), tr, ((IRuntimeMethodInfo)method).Value);
GC.KeepAlive(method);
return result;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_GetMemberRefOfFieldInfo")]
private static partial int GetMemberRefOfFieldInfo(QCallModule module, int tkType, QCallTypeHandle declaringType, int tkField);
private int GetMemberRefOfFieldInfo(int tkType, RuntimeTypeHandle declaringType, RuntimeFieldInfo runtimeField)
{
Debug.Assert(runtimeField != null);
RuntimeModuleBuilder thisModule = this;
return GetMemberRefOfFieldInfo(new QCallModule(ref thisModule), tkType, new QCallTypeHandle(ref declaringType), runtimeField.MetadataToken);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_GetTokenFromTypeSpec")]
private static partial int GetTokenFromTypeSpec(QCallModule pModule, byte[] signature, int length);
private int GetTokenFromTypeSpec(byte[] signature, int length)
{
RuntimeModuleBuilder thisModule = this;
return GetTokenFromTypeSpec(new QCallModule(ref thisModule), signature, length);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_GetArrayMethodToken", StringMarshalling = StringMarshalling.Utf16)]
private static partial int GetArrayMethodToken(QCallModule module, int tkTypeSpec, string methodName, byte[] signature, int sigLength);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_GetStringConstant", StringMarshalling = StringMarshalling.Utf16)]
private static partial int GetStringConstant(QCallModule module, string str, int length);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleBuilder_SetFieldRVAContent")]
internal static partial void SetFieldRVAContent(QCallModule module, int fdToken, byte[]? data, int length);
#endregion
#region Internal Members
internal Type? FindTypeBuilderWithName(string strTypeName, bool ignoreCase)
{
if (ignoreCase)
{
foreach (string name in _typeBuilderDict.Keys)
{
if (string.Equals(name, strTypeName, StringComparison.OrdinalIgnoreCase))
{
return _typeBuilderDict[name];
}
}
}
else
{
if (_typeBuilderDict.TryGetValue(strTypeName, out Type? foundType))
{
return foundType;
}
}
return null;
}
private int GetTypeRefNested(Type type, Module? refedModule)
{
// This function will generate correct TypeRef token for top level type and nested type.
Type? enclosingType = type.DeclaringType;
int tkResolution = 0;
string typeName = type.FullName!;
if (enclosingType != null)
{
tkResolution = GetTypeRefNested(enclosingType, refedModule);
typeName = UnmangleTypeName(typeName);
}
Debug.Assert(!type.IsByRef, "Must not be ByRef. Get token from TypeSpec.");
Debug.Assert(!type.IsGenericType || type.IsGenericTypeDefinition, "Must not have generic arguments.");
RuntimeModuleBuilder thisModule = this;
RuntimeModule refedRuntimeModule = GetRuntimeModuleFromModule(refedModule);
return GetTypeRef(new QCallModule(ref thisModule), typeName, new QCallModule(ref refedRuntimeModule), tkResolution);
}
public override int GetMethodMetadataToken(ConstructorInfo constructor)
{
// Helper to get constructor token.
int tr;
int mr;
if (constructor is ConstructorBuilder conBuilder)
{
if (conBuilder.Module.Equals(this))
return conBuilder.MetadataToken;
// constructor is defined in a different module
tr = GetTypeTokenInternal(constructor.ReflectedType!);
mr = GetMemberRef(constructor.ReflectedType!.Module, tr, conBuilder.MetadataToken);
}
else if (constructor is ConstructorOnTypeBuilderInstantiation conOnTypeBuilderInst)
{
tr = GetTypeTokenInternal(constructor.DeclaringType!);
mr = GetMemberRef(constructor.DeclaringType!.Module, tr, conOnTypeBuilderInst.MetadataToken);
}
else if (constructor is RuntimeConstructorInfo rtCon && !constructor.ReflectedType!.IsArray)
{
// constructor is not a dynamic field
// We need to get the TypeRef tokens
tr = GetTypeTokenInternal(constructor.ReflectedType);
mr = GetMemberRefOfMethodInfo(tr, rtCon);
}
else
{
// some user derived ConstructorInfo
// go through the slower code path, i.e. retrieve parameters and form signature helper.
ParameterInfo[] parameters = constructor.GetParameters() ??
throw new ArgumentException(SR.Argument_InvalidConstructorInfo);
Type[] parameterTypes = new Type[parameters.Length];
Type[][] requiredCustomModifiers = new Type[parameters.Length][];
Type[][] optionalCustomModifiers = new Type[parameters.Length][];
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i] == null)
{
throw new ArgumentException(SR.Argument_InvalidConstructorInfo);
}
parameterTypes[i] = parameters[i].ParameterType;
requiredCustomModifiers[i] = parameters[i].GetRequiredCustomModifiers();
optionalCustomModifiers[i] = parameters[i].GetOptionalCustomModifiers();
}
tr = GetTypeTokenInternal(constructor.ReflectedType!);
SignatureHelper sigHelp = SignatureHelper.GetMethodSigHelper(this, constructor.CallingConvention, null, null, null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
byte[] sigBytes = sigHelp.InternalGetSignature(out int length);
mr = GetMemberRefFromSignature(tr, constructor.Name, sigBytes, length);
}
return mr;
}
internal object SyncRoot => ContainingAssemblyBuilder.SyncRoot;
#endregion
#region Module Overrides
internal RuntimeModule InternalModule => _internalModule;
private protected override ModuleHandle GetModuleHandleImpl() => new ModuleHandle(InternalModule);
internal static RuntimeModule GetRuntimeModuleFromModule(Module? m)
{
if (m is RuntimeModuleBuilder mb)
{
return mb.InternalModule;
}
return (m as RuntimeModule)!;
}
private int GetMemberRefToken(MethodBase method, Type[]? optionalParameterTypes)
{
int tkParent;
int cGenericParameters = 0;
SignatureHelper sigHelp;
if (method.IsGenericMethod)
{
if (!method.IsGenericMethodDefinition)
{
throw new InvalidOperationException();
}
cGenericParameters = method.GetGenericArguments().Length;
}
if (optionalParameterTypes != null)
{
if ((method.CallingConvention & CallingConventions.VarArgs) == 0)
{
// Client should not supply optional parameter in default calling convention
throw new InvalidOperationException(SR.InvalidOperation_NotAVarArgCallingConvention);
}
}
MethodInfo? masmi = method as MethodInfo;
if (method.DeclaringType!.IsGenericType)
{
MethodBase methDef = GetGenericMethodBaseDefinition(method);
sigHelp = GetMemberRefSignature(methDef, cGenericParameters);
}
else
{
sigHelp = GetMemberRefSignature(method, cGenericParameters);
}
if (optionalParameterTypes?.Length > 0)
{
sigHelp.AddSentinel();
sigHelp.AddArguments(optionalParameterTypes, null, null);
}
byte[] sigBytes = sigHelp.InternalGetSignature(out int sigLength);
if (method.DeclaringType!.IsGenericType)
{
byte[] sig = SignatureHelper.GetTypeSigToken(this, method.DeclaringType).InternalGetSignature(out int length);
tkParent = GetTokenFromTypeSpec(sig, length);
}
else if (!method.Module.Equals(this))
{
// Use typeRef as parent because the method's declaringType lives in a different assembly
tkParent = GetTypeMetadataToken(method.DeclaringType);
}
else
{
// Use methodDef as parent because the method lives in this assembly and its declaringType has no generic arguments
if (masmi != null)
tkParent = GetMethodMetadataToken(masmi);
else
tkParent = GetMethodMetadataToken((method as ConstructorInfo)!);
}
return GetMemberRefFromSignature(tkParent, method.Name, sigBytes, sigLength);
}
internal SignatureHelper GetMemberRefSignature(CallingConventions call, Type? returnType,
Type[]? parameterTypes, Type[][]? requiredCustomModifiers, Type[][]? optionalCustomModifiers,
Type[]? optionalParameterTypes, int cGenericParameters)
{
SignatureHelper sig = SignatureHelper.GetMethodSigHelper(this, call, cGenericParameters, returnType, null, null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
if (optionalParameterTypes != null && optionalParameterTypes.Length != 0)
{
sig.AddSentinel();
sig.AddArguments(optionalParameterTypes, null, null);
}
return sig;
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "Module.ResolveMethod is marked as RequiresUnreferencedCode because it relies on tokens " +
"which are not guaranteed to be stable across trimming. So if somebody hardcodes a token it could break. " +
"The usage here is not like that as all these tokens come from existing metadata loaded from some IL " +
"and so trimming has no effect (the tokens are read AFTER trimming occurred).")]
private static MethodBase GetGenericMethodBaseDefinition(MethodBase methodBase)
{
// methodInfo = G<Foo>.M<Bar> ==> methDef = G<T>.M<S>
MethodInfo? masmi = methodBase as MethodInfo;
MethodBase methDef;
if (methodBase is MethodOnTypeBuilderInstantiation motbi)
{
methDef = motbi._method;
}
else if (methodBase is ConstructorOnTypeBuilderInstantiation cotbi)
{
methDef = cotbi._ctor;
}
else if (methodBase is MethodBuilder || methodBase is ConstructorBuilder)
{
// methodInfo must be GenericMethodDefinition; trying to emit G<?>.M<S>
methDef = methodBase;
}
else
{
Debug.Assert(methodBase is RuntimeMethodInfo || methodBase is RuntimeConstructorInfo);
if (methodBase.IsGenericMethod)
{
Debug.Assert(masmi != null);
methDef = masmi.GetGenericMethodDefinition()!;
methDef = methDef.Module.ResolveMethod(
methodBase.MetadataToken,
methDef.DeclaringType?.GetGenericArguments(),
methDef.GetGenericArguments())!;
}
else
{
methDef = methodBase.Module.ResolveMethod(
methodBase.MetadataToken,
methodBase.DeclaringType?.GetGenericArguments(),
null)!;
}
}
return methDef;
}
internal SignatureHelper GetMemberRefSignature(MethodBase? method, int cGenericParameters)
{
switch (method)
{
case RuntimeMethodBuilder methodBuilder:
return methodBuilder.GetMethodSignature();
case RuntimeConstructorBuilder constructorBuilder:
return constructorBuilder.GetMethodSignature();
case MethodOnTypeBuilderInstantiation motbi when motbi._method is RuntimeMethodBuilder methodBuilder:
return methodBuilder.GetMethodSignature();
case MethodOnTypeBuilderInstantiation motbi:
method = motbi._method;
break;
case ConstructorOnTypeBuilderInstantiation cotbi when cotbi._ctor is RuntimeConstructorBuilder constructorBuilder:
return constructorBuilder.GetMethodSignature();
case ConstructorOnTypeBuilderInstantiation cotbi:
method = cotbi._ctor;
break;
}
Debug.Assert(method is RuntimeMethodInfo || method is RuntimeConstructorInfo);
ReadOnlySpan<ParameterInfo> parameters = method.GetParametersAsSpan();
Type[] parameterTypes = new Type[parameters.Length];
Type[][] requiredCustomModifiers = new Type[parameterTypes.Length][];
Type[][] optionalCustomModifiers = new Type[parameterTypes.Length][];
for (int i = 0; i < parameters.Length; i++)
{
parameterTypes[i] = parameters[i].ParameterType;
requiredCustomModifiers[i] = parameters[i].GetRequiredCustomModifiers();
optionalCustomModifiers[i] = parameters[i].GetOptionalCustomModifiers();
}
ParameterInfo? returnParameter = method is MethodInfo mi ? mi.ReturnParameter : null;
SignatureHelper sigHelp = SignatureHelper.GetMethodSigHelper(this, method.CallingConvention, cGenericParameters, returnParameter?.ParameterType, returnParameter?.GetRequiredCustomModifiers(), returnParameter?.GetOptionalCustomModifiers(), parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
return sigHelp;
}
#endregion
public override bool Equals(object? obj) => base.Equals(obj);
public override int GetHashCode() => base.GetHashCode();
#region ICustomAttributeProvider Members
public override object[] GetCustomAttributes(bool inherit)
{
return InternalModule.GetCustomAttributes(inherit);
}
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
{
return InternalModule.GetCustomAttributes(attributeType, inherit);
}
public override bool IsDefined(Type attributeType, bool inherit)
{
return InternalModule.IsDefined(attributeType, inherit);
}
public override IList<CustomAttributeData> GetCustomAttributesData()
{
return InternalModule.GetCustomAttributesData();
}
#endregion
#region Module Overrides
[RequiresUnreferencedCode("Types might be removed")]
public override Type[] GetTypes()
{
lock (SyncRoot)
{
return GetTypesNoLock();
}
}
internal Type[] GetTypesNoLock()
{
Type[] typeList = new Type[_typeBuilderDict.Count];
int i = 0;
foreach (Type builder in _typeBuilderDict.Values)
{
RuntimeTypeBuilder tmpTypeBldr;
if (builder is RuntimeEnumBuilder enumBldr)
tmpTypeBldr = enumBldr.m_typeBuilder;
else
tmpTypeBldr = (RuntimeTypeBuilder)builder;
// We should not return TypeBuilders.
// Otherwise anyone can emit code in it.
if (tmpTypeBldr.IsCreated())
typeList[i++] = tmpTypeBldr.UnderlyingSystemType;
else
typeList[i++] = builder;
}
return typeList;
}
[RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")]
public override Type? GetType(string className)
{
return GetType(className, false, false);
}
[RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")]
public override Type? GetType(string className, bool ignoreCase)
{
return GetType(className, false, ignoreCase);
}
[RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")]
public override Type? GetType(string className, bool throwOnError, bool ignoreCase)
{
lock (SyncRoot)
{
return GetTypeNoLock(className, throwOnError, ignoreCase);
}
}
[RequiresUnreferencedCode("Types might be removed")]
private Type? GetTypeNoLock(string className, bool throwOnError, bool ignoreCase)
{
// public API to a type. The reason that we need this function override from module
// is because clients might need to get foo[] when foo is being built. For example, if
// foo class contains a data member of type foo[].
// This API first delegate to the Module.GetType implementation. If succeeded, great!
// If not, we have to look up the current module to find the TypeBuilder to represent the base
// type and form the Type object for "foo[,]".
// Module.GetType() will verify className.
Type? baseType = InternalModule.GetType(className, throwOnError, ignoreCase);
if (baseType != null)
return baseType;
// Now try to see if we contain a TypeBuilder for this type or not.
// Might have a compound type name, indicated via an unescaped
// '[', '*' or '&'. Split the name at this point.
string? baseName = null;
string? parameters = null;
int startIndex = 0;
while (startIndex <= className.Length)
{
// Are there any possible special characters left?
int i = className.AsSpan(startIndex).IndexOfAny('[', '*', '&');
if (i < 0)
{
// No, type name is simple.
baseName = className;
parameters = null;
break;
}
i += startIndex;
// Found a potential special character, but it might be escaped.
int slashes = 0;
for (int j = i - 1; j >= 0 && className[j] == '\\'; j--)
slashes++;
// Odd number of slashes indicates escaping.
if (slashes % 2 == 1)
{
startIndex = i + 1;
continue;
}
// Found the end of the base type name.
baseName = className.Substring(0, i);
parameters = className.Substring(i);
break;
}
// If we didn't find a basename yet, the entire class name is
// the base name and we don't have a composite type.
if (baseName == null)
{
baseName = className;
parameters = null;
}
baseName = baseName.Replace(@"\\", @"\").Replace(@"\[", "[").Replace(@"\*", "*").Replace(@"\&", "&");
if (parameters != null)
{
// try to see if reflection can find the base type. It can be such that reflection
// does not support the complex format string yet!
baseType = InternalModule.GetType(baseName, false, ignoreCase);
}
if (baseType == null)
{
// try to find it among the unbaked types.
baseType = FindTypeBuilderWithName(baseName, ignoreCase);
if (baseType == null)
{
return null;
}
}
if (parameters == null)
{
return baseType;
}
return GetType(parameters, baseType);
}
[RequiresAssemblyFiles(UnknownStringMessageInRAF)]
public override string FullyQualifiedName => ManifestModuleName;
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public override byte[] ResolveSignature(int metadataToken)
{
return InternalModule.ResolveSignature(metadataToken);
}
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public override MethodBase? ResolveMethod(int metadataToken, Type[]? genericTypeArguments, Type[]? genericMethodArguments)
{
return InternalModule.ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);
}
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public override FieldInfo? ResolveField(int metadataToken, Type[]? genericTypeArguments, Type[]? genericMethodArguments)
{
return InternalModule.ResolveField(metadataToken, genericTypeArguments, genericMethodArguments);
}
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public override Type ResolveType(int metadataToken, Type[]? genericTypeArguments, Type[]? genericMethodArguments)
{
return InternalModule.ResolveType(metadataToken, genericTypeArguments, genericMethodArguments);
}
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public override MemberInfo? ResolveMember(int metadataToken, Type[]? genericTypeArguments, Type[]? genericMethodArguments)
{
return InternalModule.ResolveMember(metadataToken, genericTypeArguments, genericMethodArguments);
}
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public override string ResolveString(int metadataToken)
{
return InternalModule.ResolveString(metadataToken);
}
public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
{
InternalModule.GetPEKind(out peKind, out machine);
}
public override int MDStreamVersion => InternalModule.MDStreamVersion;
public override Guid ModuleVersionId => InternalModule.ModuleVersionId;
public override int MetadataToken => InternalModule.MetadataToken;
public override bool IsResource() => InternalModule.IsResource();
[RequiresUnreferencedCode("Fields might be removed")]
public override FieldInfo[] GetFields(BindingFlags bindingFlags)
{
return InternalModule.GetFields(bindingFlags);
}
[RequiresUnreferencedCode("Fields might be removed")]
public override FieldInfo? GetField(string name, BindingFlags bindingAttr)
{
return InternalModule.GetField(name, bindingAttr);
}
[RequiresUnreferencedCode("Methods might be removed")]
public override MethodInfo[] GetMethods(BindingFlags bindingFlags)
{
return InternalModule.GetMethods(bindingFlags);
}
[RequiresUnreferencedCode("Methods might be removed")]
protected override MethodInfo? GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder,
CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers)
{
// Cannot call InternalModule.GetMethods because it doesn't allow types to be null
return InternalModule.GetMethodInternal(name, bindingAttr, binder, callConvention, types, modifiers);
}
public override string ScopeName => InternalModule.ScopeName;
[RequiresAssemblyFiles(UnknownStringMessageInRAF)]
public override string Name => InternalModule.Name;
public override Assembly Assembly => _assemblyBuilder;
#endregion
#region Public Members
#region Define Type
protected override TypeBuilder DefineTypeCore(string name, TypeAttributes attr, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent, Type[]? interfaces, PackingSize packingSize, int typesize)
{
lock (SyncRoot)
{
return new RuntimeTypeBuilder(name, attr, parent, interfaces, this, packingSize, typesize, null);
}
}
#endregion
#region Define Enum
// This API can only be used to construct a top-level (not nested) enum type.
// Nested enum types can be defined manually using ModuleBuilder.DefineType.
protected override EnumBuilder DefineEnumCore(string name, TypeAttributes visibility, Type underlyingType)
{
lock (SyncRoot)
{
RuntimeEnumBuilder enumBuilder = new RuntimeEnumBuilder(name, underlyingType, visibility, this);
// This enum is not generic, nested, and cannot have any element type.
// Replace the TypeBuilder object in _typeBuilderDict with this EnumBuilder object.
_typeBuilderDict[name] = enumBuilder;
return enumBuilder;
}
}
#endregion
#region Define Global Method
[RequiresUnreferencedCode("P/Invoke marshalling may dynamically access members that could be trimmed.")]
protected override MethodBuilder DefinePInvokeMethodCore(string name, string dllName, string entryName,
MethodAttributes attributes, CallingConventions callingConvention, Type? returnType,
Type[]? parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
{
lock (SyncRoot)
{
// Global methods must be static.
if ((attributes & MethodAttributes.Static) == 0)
{
throw new ArgumentException(SR.Argument_GlobalMembersMustBeStatic);
}
return _globalTypeBuilder.DefinePInvokeMethod(name, dllName, entryName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
}
}
protected override MethodBuilder DefineGlobalMethodCore(string name, MethodAttributes attributes, CallingConventions callingConvention,
Type? returnType, Type[]? requiredReturnTypeCustomModifiers, Type[]? optionalReturnTypeCustomModifiers,
Type[]? parameterTypes, Type[][]? requiredParameterTypeCustomModifiers, Type[][]? optionalParameterTypeCustomModifiers)
{
lock (SyncRoot)
{
return DefineGlobalMethodNoLock(name, attributes, callingConvention, returnType,
requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers,
parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
}
}
private MethodBuilder DefineGlobalMethodNoLock(string name, MethodAttributes attributes, CallingConventions callingConvention,
Type? returnType, Type[]? requiredReturnTypeCustomModifiers, Type[]? optionalReturnTypeCustomModifiers,
Type[]? parameterTypes, Type[][]? requiredParameterTypeCustomModifiers, Type[][]? optionalParameterTypeCustomModifiers)
{
if (_hasGlobalBeenCreated)
{
throw new InvalidOperationException(SR.InvalidOperation_GlobalsHaveBeenCreated);
}
if ((attributes & MethodAttributes.Static) == 0)
{
throw new ArgumentException(SR.Argument_GlobalMembersMustBeStatic);
}
return _globalTypeBuilder.DefineMethod(name, attributes, callingConvention,
returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers,
parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
}
protected override void CreateGlobalFunctionsCore()
{
lock (SyncRoot)
{
if (_hasGlobalBeenCreated)
{
// cannot create globals twice
throw new InvalidOperationException(SR.InvalidOperation_GlobalsHaveBeenCreated);
}
_globalTypeBuilder.CreateType();
_hasGlobalBeenCreated = true;
}
}
#endregion
#region Define Data
protected override FieldBuilder DefineInitializedDataCore(string name, byte[] data, FieldAttributes attributes)
{
lock (SyncRoot)
{
// This method will define an initialized Data in .sdata.
// We will create a fake TypeDef to represent the data with size. This TypeDef
// will be the signature for the Field.
if (_hasGlobalBeenCreated)
{
throw new InvalidOperationException(SR.InvalidOperation_GlobalsHaveBeenCreated);
}
return _globalTypeBuilder.DefineInitializedData(name, data, attributes);
}
}
protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes)
{
lock (SyncRoot)
{
// This method will define an uninitialized Data in .sdata.
// We will create a fake TypeDef to represent the data with size. This TypeDef
// will be the signature for the Field.
if (_hasGlobalBeenCreated)
{
throw new InvalidOperationException(SR.InvalidOperation_GlobalsHaveBeenCreated);
}
return _globalTypeBuilder.DefineUninitializedData(name, size, attributes);
}
}
#endregion
#region GetToken
// For a generic type definition, we should return the token for the generic type definition itself in two cases:
// 1. GetTypeToken
// 2. ldtoken (see ILGenerator)
// For all other occasions we should return the generic type instantiated on its formal parameters.
internal int GetTypeTokenInternal(Type type, bool getGenericDefinition = false)
{
lock (SyncRoot)
{
return GetTypeTokenWorkerNoLock(type, getGenericDefinition);
}
}
public override int GetTypeMetadataToken(Type type)
{
return GetTypeTokenInternal(type, getGenericDefinition: true);
}
private int GetTypeTokenWorkerNoLock(Type type, bool getGenericDefinition)
{
ArgumentNullException.ThrowIfNull(type);
// Return a token for the class relative to the Module. Tokens
// are used to indentify objects when the objects are used in IL
// instructions. Tokens are always relative to the Module. For example,
// the token value for System.String is likely to be different from
// Module to Module. Calling GetTypeToken will cause a reference to be
// added to the Module. This reference becomes a permanent part of the Module,
// multiple calls to this method with the same class have no additional side-effects.
// This function is optimized to use the TypeDef token if the Type is within the
// same module. We should also be aware of multiple dynamic modules and multiple
// implementations of a Type.
if ((type.IsGenericType && (!type.IsGenericTypeDefinition || !getGenericDefinition))
|| type.IsGenericParameter
|| type.IsArray
|| type.IsPointer
|| type.IsByRef)
{
byte[] sig = SignatureHelper.GetTypeSigToken(this, type).InternalGetSignature(out int length);
return GetTokenFromTypeSpec(sig, length);
}
Module refedModule = type.Module;
if (refedModule.Equals(this))
{
// no need to do anything additional other than defining the TypeRef Token
RuntimeTypeBuilder? typeBuilder;
typeBuilder = type is RuntimeEnumBuilder enumBuilder ? enumBuilder.m_typeBuilder : type as RuntimeTypeBuilder;
if (typeBuilder != null)
{
// If the type is defined in this module, just return the token.
return typeBuilder.TypeToken;
}
else if (type is GenericTypeParameterBuilder paramBuilder)
{
return paramBuilder.MetadataToken;
}
return GetTypeRefNested(type, this);
}
return GetTypeRefNested(type, refedModule);
}
public override int GetMethodMetadataToken(MethodInfo method)
{
lock (SyncRoot)
{
return GetMethodTokenNoLock(method, false);
}
}
// For a method on a generic type, we should return the methoddef token on the generic type definition in two cases
// 1. GetMethodToken
// 2. ldtoken (see ILGenerator)
// For all other occasions we should return the method on the generic type instantiated on the formal parameters.
private int GetMethodTokenNoLock(MethodInfo method, bool getGenericTypeDefinition)
{
ArgumentNullException.ThrowIfNull(method);
// Return a MemberRef token if MethodInfo is not defined in this module. Or
// return the MethodDef token.
int tr;
int mr;
if (method is MethodBuilder methBuilder)
{
int methodToken = methBuilder.MetadataToken;
if (method.Module.Equals(this))
{
return methodToken;
}
if (method.DeclaringType == null)
{
throw new InvalidOperationException(SR.InvalidOperation_CannotImportGlobalFromDifferentModule);
}
// method is defined in a different module
tr = getGenericTypeDefinition ? GetTypeMetadataToken(method.DeclaringType) : GetTypeTokenInternal(method.DeclaringType);
mr = GetMemberRef(method.DeclaringType.Module, tr, methodToken);
}
else if (method is MethodOnTypeBuilderInstantiation)
{
return GetMemberRefToken(method, null);
}
else if (method is SymbolMethod symMethod)
{
if (symMethod.GetModule() == this)
return symMethod.MetadataToken;
// form the method token
return symMethod.GetToken(this);
}
else
{
Type declaringType = method.DeclaringType ??
throw new InvalidOperationException(SR.InvalidOperation_CannotImportGlobalFromDifferentModule);
if (declaringType.IsArray)
{
// use reflection to build signature to work around the E_T_VAR problem in EEClass
ParameterInfo[] paramInfo = method.GetParameters();
Type[] tt = new Type[paramInfo.Length];
for (int i = 0; i < paramInfo.Length; i++)
tt[i] = paramInfo[i].ParameterType;
return GetArrayMethodToken(declaringType, method.Name, method.CallingConvention, method.ReturnType, tt);
}
else if (method is RuntimeMethodInfo rtMeth)
{
tr = getGenericTypeDefinition ? GetTypeMetadataToken(declaringType) : GetTypeTokenInternal(declaringType);
mr = GetMemberRefOfMethodInfo(tr, rtMeth);
}
else
{
// some user derived ConstructorInfo
// go through the slower code path, i.e. retrieve parameters and form signature helper.
ParameterInfo[] parameters = method.GetParameters();
Type[] parameterTypes = new Type[parameters.Length];
Type[][] requiredCustomModifiers = new Type[parameterTypes.Length][];
Type[][] optionalCustomModifiers = new Type[parameterTypes.Length][];
for (int i = 0; i < parameters.Length; i++)
{
parameterTypes[i] = parameters[i].ParameterType;
requiredCustomModifiers[i] = parameters[i].GetRequiredCustomModifiers();
optionalCustomModifiers[i] = parameters[i].GetOptionalCustomModifiers();
}
tr = getGenericTypeDefinition ? GetTypeMetadataToken(declaringType) : GetTypeTokenInternal(declaringType);
SignatureHelper sigHelp;
try
{
sigHelp = SignatureHelper.GetMethodSigHelper(
this, method.CallingConvention, method.ReturnType,
method.ReturnParameter.GetRequiredCustomModifiers(), method.ReturnParameter.GetOptionalCustomModifiers(),
parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
}
catch (NotImplementedException)
{
// Legacy code deriving from MethodInfo may not have implemented ReturnParameter.
sigHelp = SignatureHelper.GetMethodSigHelper(this, method.ReturnType, parameterTypes);
}
byte[] sigBytes = sigHelp.InternalGetSignature(out int length);
mr = GetMemberRefFromSignature(tr, method.Name, sigBytes, length);
}
}
return mr;
}
internal int GetMethodTokenInternal(MethodBase method, Type[]? optionalParameterTypes, bool useMethodDef)
{
int tk;
MethodInfo? methodInfo = method as MethodInfo;
if (method.IsGenericMethod)
{
// Constructors cannot be generic.
Debug.Assert(methodInfo != null);
// Given M<Bar> unbind to M<S>
MethodInfo methodInfoUnbound = methodInfo;
bool isGenericMethodDef = methodInfo.IsGenericMethodDefinition;
if (!isGenericMethodDef)
{
methodInfoUnbound = methodInfo.GetGenericMethodDefinition()!;
}
if (!Equals(methodInfoUnbound.Module)
|| (methodInfoUnbound.DeclaringType != null && methodInfoUnbound.DeclaringType.IsGenericType))
{
tk = GetMemberRefToken(methodInfoUnbound, null);
}
else
{
tk = GetMethodMetadataToken(methodInfoUnbound);
}
// For Ldtoken, Ldftn, and Ldvirtftn, we should emit the method def/ref token for a generic method definition.
if (isGenericMethodDef && useMethodDef)
{
return tk;
}
// Create signature of method instantiation M<Bar>
// Create MethodSepc M<Bar> with parent G?.M<S>
byte[] sigBytes = SignatureHelper.GetMethodSpecSigHelper(
this, methodInfo.GetGenericArguments()).InternalGetSignature(out int sigLength);
RuntimeModuleBuilder thisModule = this;
tk = RuntimeTypeBuilder.DefineMethodSpec(new QCallModule(ref thisModule), tk, sigBytes, sigLength);
}
else
{
if (((method.CallingConvention & CallingConventions.VarArgs) == 0) &&
(method.DeclaringType == null || !method.DeclaringType.IsGenericType))
{
if (methodInfo != null)
{
tk = GetMethodMetadataToken(methodInfo);
}
else
{
tk = GetMethodMetadataToken((method as ConstructorInfo)!);
}
}
else
{
tk = GetMemberRefToken(method, optionalParameterTypes);
}
}
return tk;
}
internal int GetArrayMethodToken(Type arrayClass, string methodName, CallingConventions callingConvention,
Type? returnType, Type[]? parameterTypes)
{
lock (SyncRoot)
{
return GetArrayMethodTokenNoLock(arrayClass, methodName, callingConvention, returnType, parameterTypes);
}
}
private int GetArrayMethodTokenNoLock(Type arrayClass, string methodName, CallingConventions callingConvention,
Type? returnType, Type[]? parameterTypes)
{
if (!arrayClass.IsArray)
{
throw new ArgumentException(SR.Argument_HasToBeArrayClass);
}
// Return a token for the MethodInfo for a method on an Array. This is primarily
// used to get the LoadElementAddress method.
SignatureHelper sigHelp = SignatureHelper.GetMethodSigHelper(
this, callingConvention, returnType, null, null, parameterTypes, null, null);
byte[] sigBytes = sigHelp.InternalGetSignature(out int length);
int typeSpec = GetTypeTokenInternal(arrayClass);
RuntimeModuleBuilder thisModule = this;
return GetArrayMethodToken(new QCallModule(ref thisModule),
typeSpec, methodName, sigBytes, length);
}
protected override MethodInfo GetArrayMethodCore(Type arrayClass, string methodName, CallingConventions callingConvention,
Type? returnType, Type[]? parameterTypes)
{
// GetArrayMethod is useful when you have an array of a type whose definition has not been completed and
// you want to access methods defined on Array. For example, you might define a type and want to define a
// method that takes an array of the type as a parameter. In order to access the elements of the array,
// you will need to call methods of the Array class.
int token = GetArrayMethodToken(arrayClass, methodName, callingConvention, returnType, parameterTypes);
return new SymbolMethod(this, token, arrayClass, methodName, callingConvention, returnType, parameterTypes);
}
public override int GetFieldMetadataToken(FieldInfo field)
{
lock (SyncRoot)
{
return GetFieldTokenNoLock(field);
}
}
private int GetFieldTokenNoLock(FieldInfo field)
{
ArgumentNullException.ThrowIfNull(field);
int tr;
int mr;
if (field is FieldBuilder fdBuilder)
{
if (field.DeclaringType != null && field.DeclaringType.IsGenericType)
{
byte[] sig = SignatureHelper.GetTypeSigToken(this, field.DeclaringType).InternalGetSignature(out int length);
tr = GetTokenFromTypeSpec(sig, length);
mr = GetMemberRef(this, tr, fdBuilder.MetadataToken);
}
else if (fdBuilder.Module.Equals(this))
{
// field is defined in the same module
return fdBuilder.MetadataToken;
}
else
{
// field is defined in a different module
if (field.DeclaringType == null)
{
throw new InvalidOperationException(SR.InvalidOperation_CannotImportGlobalFromDifferentModule);
}
tr = GetTypeTokenInternal(field.DeclaringType);
mr = GetMemberRef(field.ReflectedType!.Module, tr, fdBuilder.MetadataToken);
}
}
else if (field is RuntimeFieldInfo rtField)
{
// FieldInfo is not an dynamic field
// We need to get the TypeRef tokens
if (field.DeclaringType == null)
{
throw new InvalidOperationException(SR.InvalidOperation_CannotImportGlobalFromDifferentModule);
}
if (field.DeclaringType != null && field.DeclaringType.IsGenericType)
{
byte[] sig = SignatureHelper.GetTypeSigToken(this, field.DeclaringType).InternalGetSignature(out int length);
tr = GetTokenFromTypeSpec(sig, length);
mr = GetMemberRefOfFieldInfo(tr, field.DeclaringType.TypeHandle, rtField);
}
else
{
tr = GetTypeTokenInternal(field.DeclaringType!);
mr = GetMemberRefOfFieldInfo(tr, field.DeclaringType!.TypeHandle, rtField);
}
}
else if (field is FieldOnTypeBuilderInstantiation fOnTB)
{
FieldInfo fb = fOnTB.FieldInfo;
byte[] sig = SignatureHelper.GetTypeSigToken(this, field.DeclaringType!).InternalGetSignature(out int length);
tr = GetTokenFromTypeSpec(sig, length);
mr = GetMemberRef(fb.ReflectedType!.Module, tr, fOnTB.MetadataToken);
}
else
{
// user defined FieldInfo
tr = GetTypeTokenInternal(field.ReflectedType!);
SignatureHelper sigHelp = SignatureHelper.GetFieldSigHelper(this);
sigHelp.AddArgument(field.FieldType, field.GetRequiredCustomModifiers(), field.GetOptionalCustomModifiers());
byte[] sigBytes = sigHelp.InternalGetSignature(out int length);
mr = GetMemberRefFromSignature(tr, field.Name, sigBytes, length);
}
return mr;
}
public override int GetStringMetadataToken(string stringConstant)
{
ArgumentNullException.ThrowIfNull(stringConstant);
// Returns a token representing a String constant. If the string
// value has already been defined, the existing token will be returned.
RuntimeModuleBuilder thisModule = this;
return GetStringConstant(new QCallModule(ref thisModule), stringConstant, stringConstant.Length);
}
public override int GetSignatureMetadataToken(SignatureHelper signature)
{
ArgumentNullException.ThrowIfNull(signature);
// Define signature token given a signature helper. This will define a metadata
// token for the signature described by SignatureHelper.
// Get the signature in byte form.
byte[] sigBytes = signature.InternalGetSignature(out int sigLength);
RuntimeModuleBuilder thisModule = this;
return RuntimeTypeBuilder.GetTokenFromSig(new QCallModule(ref thisModule), sigBytes, sigLength);
}
internal int GetSignatureToken(byte[] sigBytes, int sigLength)
{
ArgumentNullException.ThrowIfNull(sigBytes);
byte[] localSigBytes = new byte[sigBytes.Length];
Buffer.BlockCopy(sigBytes, 0, localSigBytes, 0, sigBytes.Length);
RuntimeModuleBuilder thisModule = this;
return RuntimeTypeBuilder.GetTokenFromSig(new QCallModule(ref thisModule), localSigBytes, sigLength);
}
#endregion
#region Other
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
RuntimeTypeBuilder.DefineCustomAttribute(
this,
1, // This is hard coding the module token to 1
GetMethodMetadataToken(con),
binaryAttribute);
}
#endregion
#endregion
}
}
|