Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update comment for DynamicMethodBodyReaderOptions #554

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 12 additions & 19 deletions src/DotNet/Emit/DynamicMethodBodyReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public enum DynamicMethodBodyReaderOptions {
None = 0,

/// <summary>
/// Some fields/methods have an unknown declaring type and don't have a context with
/// that information. If this is enabled, the reader will try to guess it but it doesn't
/// always work. If you get an <see cref="ArgumentException"/>, try enabling this option.
/// Fields in generic type have an unknown declaring type when built by DynamicILInfo.GetTokenFor(RuntimeFieldHandle field)
/// rather than DynamicILInfo.GetTokenFor(RuntimeFieldHandle field, RuntimeTypeHandle contextType).
/// If you get an <see cref="ArgumentException"/>, try enabling this option.
/// </summary>
UnknownDeclaringType = 0x00000001,
}
Expand Down Expand Up @@ -454,26 +454,19 @@ IMethod ImportMethod(uint rid) {
if (obj is null)
return null;

if (obj is RuntimeMethodHandle) {
if ((options & DynamicMethodBodyReaderOptions.UnknownDeclaringType) != 0) {
// Sometimes it's a generic type but obj != `GenericMethodInfo`, so pass in 'default' and the
// runtime will try to figure out the declaring type. https://github.com/0xd4d/dnlib/issues/298
return importer.Import(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj, default));
}
else
return importer.Import(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj));
}
if (obj is RuntimeMethodHandle)
return importer.ImportAsOperand(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj));

if (obj.GetType().ToString() == "System.Reflection.Emit.GenericMethodInfo") {
var context = (RuntimeTypeHandle)gmiContextFieldInfo.Read(obj);
var method = SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)gmiMethodHandleFieldInfo.Read(obj), context);
return importer.Import(method);
return importer.ImportAsOperand(method);
}

if (obj.GetType().ToString() == "System.Reflection.Emit.VarArgMethod") {
var method = GetVarArgMethod(obj);
if (!(method is DynamicMethod))
return importer.Import(method);
return importer.ImportAsOperand(method);
obj = method;
}

Expand Down Expand Up @@ -505,17 +498,17 @@ IField ImportField(uint rid) {
if (obj is RuntimeFieldHandle) {
if ((options & DynamicMethodBodyReaderOptions.UnknownDeclaringType) != 0) {
// Sometimes it's a generic type but obj != `GenericFieldInfo`, so pass in 'default' and the
// runtime will try to figure out the declaring type. https://github.com/0xd4d/dnlib/issues/298
return importer.Import(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj, default));
// runtime will try to figure out the declaring type. https://github.com/0xd4d/dnlib/issues/552
return importer.ImportAsOperand(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj, default));
}
else
return importer.Import(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj));
return importer.ImportAsOperand(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj));
}

if (obj.GetType().ToString() == "System.Reflection.Emit.GenericFieldInfo") {
var context = (RuntimeTypeHandle)gfiContextFieldInfo.Read(obj);
var field = SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)gfiFieldHandleFieldInfo.Read(obj), context);
return importer.Import(field);
return importer.ImportAsOperand(field);
}

return null;
Expand All @@ -524,7 +517,7 @@ IField ImportField(uint rid) {
ITypeDefOrRef ImportType(uint rid) {
var obj = Resolve(rid);
if (obj is RuntimeTypeHandle)
return importer.Import(Type.GetTypeFromHandle((RuntimeTypeHandle)obj));
return importer.ImportAsOperand(Type.GetTypeFromHandle((RuntimeTypeHandle)obj));

return null;
}
Expand Down
64 changes: 43 additions & 21 deletions src/DotNet/Importer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using dnlib.DotNet.Emit;

namespace dnlib.DotNet {
/// <summary>
Expand Down Expand Up @@ -167,22 +168,22 @@ public Importer(ModuleDef module, ImporterOptions options, GenericParamContext g
}

/// <summary>
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>.
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/>.
/// </summary>
/// <param name="type">The type</param>
/// <returns>The imported type or <c>null</c> if <paramref name="type"/> is invalid</returns>
public ITypeDefOrRef Import(Type type) => module.UpdateRowId(ImportAsTypeSig(type).ToTypeDefOrRef());

/// <summary>
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>. See also <see cref="Import(Type)"/>
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/>. See also <see cref="Import(Type)"/>
/// </summary>
/// <param name="type">The type</param>
/// <returns></returns>
[Obsolete("Use 'Import(Type)' instead.")]
public ITypeDefOrRef ImportDeclaringType(Type type) => Import(type);

/// <summary>
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/>
/// </summary>
/// <param name="type">The type</param>
/// <param name="requiredModifiers">A list of all required modifiers or <c>null</c></param>
Expand Down Expand Up @@ -399,7 +400,7 @@ IResolutionScope CreateScopeReference(Type type) {
}

/// <summary>
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/>
/// </summary>
/// <param name="type">The type</param>
/// <param name="requiredModifiers">A list of all required modifiers or <c>null</c></param>
Expand Down Expand Up @@ -437,17 +438,15 @@ TypeSig ImportAsTypeSig(Type type, IList<Type> requiredModifiers, IList<Type> op
static bool IsEmpty<T>(IList<T> list) => list is null || list.Count == 0;

/// <summary>
/// Imports a <see cref="MethodBase"/> as a <see cref="IMethod"/>. This will be either
/// a <see cref="MemberRef"/> or a <see cref="MethodSpec"/>.
/// Imports a <see cref="MethodBase"/> as an <see cref="IMethod"/>.
/// </summary>
/// <param name="methodBase">The method</param>
/// <returns>The imported method or <c>null</c> if <paramref name="methodBase"/> is invalid
/// or if we failed to import the method</returns>
public IMethod Import(MethodBase methodBase) => Import(methodBase, false);

/// <summary>
/// Imports a <see cref="MethodBase"/> as a <see cref="IMethod"/>. This will be either
/// a <see cref="MemberRef"/> or a <see cref="MethodSpec"/>.
/// Imports a <see cref="MethodBase"/> as an <see cref="IMethod"/>.
/// </summary>
/// <param name="methodBase">The method</param>
/// <param name="forceFixSignature">Always verify method signature to make sure the
Expand All @@ -459,9 +458,7 @@ public IMethod Import(MethodBase methodBase, bool forceFixSignature) {
return ImportInternal(methodBase, forceFixSignature);
}

IMethod ImportInternal(MethodBase methodBase) => ImportInternal(methodBase, false);

IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature) {
IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature, bool asOperand = false) {
if (methodBase is null)
return null;

Expand All @@ -484,13 +481,13 @@ IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature) {
if (methodBase.DeclaringType.GetElementType2() == ElementType.GenericInst)
method = module.UpdateRowId(new MemberRefUser(module, methodBase.Name, CreateMethodSig(origMethod), Import(methodBase.DeclaringType)));
else
method = ImportInternal(origMethod) as IMethodDefOrRef;
method = ImportInternal(origMethod, forceFixSignature, asOperand) as IMethodDefOrRef;

method = TryResolveMethod(method);
if (methodBase.ContainsGenericParameters)
if (!asOperand && methodBase.ContainsGenericParameters)
return method; // Declaring type is instantiated but method itself is not

var gim = CreateGenericInstMethodSig(methodBase);
var gim = CreateGenericInstMethodSig(methodBase, asOperand);
var methodSpec = module.UpdateRowId(new MethodSpecUser(method, gim));
if (FixSignature && !forceFixSignature) {
//TODO:
Expand All @@ -504,7 +501,7 @@ IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature) {
parent = GetModuleParent(methodBase.Module);
}
else
parent = Import(methodBase.DeclaringType);
parent = asOperand ? ImportAsOperand(methodBase.DeclaringType) : Import(methodBase.DeclaringType);
if (parent is null)
return null;

Expand Down Expand Up @@ -583,11 +580,11 @@ CallingConvention GetCallingConvention(MethodBase mb) {
return cc;
}

GenericInstMethodSig CreateGenericInstMethodSig(MethodBase mb) {
GenericInstMethodSig CreateGenericInstMethodSig(MethodBase mb, bool asOperand) {
var genMethodArgs = mb.GetGenericArguments();
var gim = new GenericInstMethodSig(CallingConvention.GenericInst, (uint)genMethodArgs.Length);
foreach (var gma in genMethodArgs)
gim.GenericArguments.Add(ImportAsTypeSig(gma));
gim.GenericArguments.Add(asOperand ? ImportAsTypeSig(gma, null, gma.IsGenericType) : ImportAsTypeSig(gma));
return gim;
}

Expand All @@ -604,22 +601,24 @@ bool IsThisAssembly(Module module2) {
}

/// <summary>
/// Imports a <see cref="FieldInfo"/> as a <see cref="MemberRef"/>
/// Imports a <see cref="FieldInfo"/> as an <see cref="IField"/>
/// </summary>
/// <param name="fieldInfo">The field</param>
/// <returns>The imported field or <c>null</c> if <paramref name="fieldInfo"/> is invalid
/// or if we failed to import the field</returns>
public IField Import(FieldInfo fieldInfo) => Import(fieldInfo, false);

/// <summary>
/// Imports a <see cref="FieldInfo"/> as a <see cref="MemberRef"/>
/// Imports a <see cref="FieldInfo"/> as an <see cref="IField"/>
/// </summary>
/// <param name="fieldInfo">The field</param>
/// <param name="forceFixSignature">Always verify field signature to make sure the
/// returned reference matches the metadata in the source assembly</param>
/// <returns>The imported field or <c>null</c> if <paramref name="fieldInfo"/> is invalid
/// or if we failed to import the field</returns>
public IField Import(FieldInfo fieldInfo, bool forceFixSignature) {
public IField Import(FieldInfo fieldInfo, bool forceFixSignature) => ImportInternal(fieldInfo, forceFixSignature, false);

IField ImportInternal(FieldInfo fieldInfo, bool forceFixSignature, bool asOperand = false) {
FixSignature = false;
if (fieldInfo is null)
return null;
Expand All @@ -642,7 +641,7 @@ public IField Import(FieldInfo fieldInfo, bool forceFixSignature) {
parent = GetModuleParent(fieldInfo.Module);
}
else
parent = Import(fieldInfo.DeclaringType);
parent = asOperand ? ImportAsOperand(fieldInfo.DeclaringType) : Import(fieldInfo.DeclaringType);
if (parent is null)
return null;

Expand Down Expand Up @@ -1190,5 +1189,28 @@ IMemberRefParent Import(IMemberRefParent parent) {

return null;
}

/// <summary>
/// Imports a <see cref="Type"/> as an <see cref="ITypeDefOrRef"/> used for <see cref="Instruction.Operand"/>.
/// </summary>
/// <param name="type">The type</param>
/// <returns>The imported type or <c>null</c> if <paramref name="type"/> is invalid</returns>
public ITypeDefOrRef ImportAsOperand(Type type) => module.UpdateRowId(ImportAsTypeSig(type, null, type.IsGenericType).ToTypeDefOrRef());

/// <summary>
/// Imports a <see cref="MethodBase"/> as an <see cref="IMethod"/> used for <see cref="Instruction.Operand"/>.
/// </summary>
/// <param name="methodBase">The method</param>
/// <returns>The imported method or <c>null</c> if <paramref name="methodBase"/> is invalid
/// or if we failed to import the method</returns>
public IMethod ImportAsOperand(MethodBase methodBase) => ImportInternal(methodBase, false, true);

/// <summary>
/// Imports a <see cref="FieldInfo"/> as an <see cref="IField"/> used for <see cref="Instruction.Operand"/>.
/// </summary>
/// <param name="fieldInfo">The field</param>
/// <returns>The imported field or <c>null</c> if <paramref name="fieldInfo"/> is invalid
/// or if we failed to import the field</returns>
public IField ImportAsOperand(FieldInfo fieldInfo) => ImportInternal(fieldInfo, false, true);
}
}
Loading