Skip to content

Commit

Permalink
Fix.
Browse files Browse the repository at this point in the history
  • Loading branch information
wasabii committed Oct 18, 2024
1 parent b7b2716 commit b743767
Show file tree
Hide file tree
Showing 13 changed files with 613 additions and 38 deletions.
19 changes: 19 additions & 0 deletions src/IKVM.CoreLib.Tests/Symbols/Reflection/ReflectionSymbolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,25 @@ public void CanGetMethodsFromTypeBuilder()
incompleteMethod.Should().BeSameAs(method);
}

/// <summary>
/// Generics closed over a type builder need to be handled specially.
/// </summary>
[TestMethod]
public void CanCreateRuntimeGenericTypeOfTypeBuilder()
{
var c = new ReflectionSymbolContext();
var a = c.DefineAssembly(new AssemblyIdentity("DynamicAssembly"), false, false);
var m = a.DefineModule("DynamicModule");
var type = m.DefineType("DynamicType");
var funcType = c.GetOrCreateTypeSymbol(typeof(Func<,>));
var realFuncType = funcType.MakeGenericType(type, type);
var invokeMethod = realFuncType.GetMethod("Invoke");
invokeMethod.Should().NotBeNull();
invokeMethod.GetParameters().Should().HaveCount(1);
invokeMethod.GetParameters()[0].ParameterType.Should().BeSameAs(type);
invokeMethod.ReturnType.Should().BeSameAs(type);
}

}

}
118 changes: 115 additions & 3 deletions src/IKVM.CoreLib/Reflection/ReflectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@ namespace IKVM.CoreLib.Reflection
static class ReflectionExtensions
{

static readonly ParameterExpression _constructorInfoParameter = Expression.Parameter(typeof(ConstructorInfo), "p");
static readonly ParameterExpression _methodInfoParameter = Expression.Parameter(typeof(MethodInfo), "p");
static readonly ParameterExpression _fieldInfoParameter = Expression.Parameter(typeof(FieldInfo), "p");

static readonly ParameterExpression _assemblyBuilderRuntimeAssemblyParameter = Expression.Parameter(typeof(AssemblyBuilder), "p");
static readonly ParameterExpression _propertyBuilderParameter = Expression.Parameter(typeof(PropertyBuilder), "p");
static readonly ParameterExpression _eventBuilderParameter = Expression.Parameter(typeof(EventBuilder), "p");
static readonly ParameterExpression _parameterBuilderParameter = Expression.Parameter(typeof(ParameterBuilder), "p");

static readonly Type _constructorOnTypeBuilderInstantiationType = typeof(TypeBuilder).Assembly.GetType("System.Reflection.Emit.ConstructorOnTypeBuilderInstantiation", true)!;
static readonly Type _methodOnTypeBuilderInstantiationType = typeof(TypeBuilder).Assembly.GetType("System.Reflection.Emit.MethodOnTypeBuilderInstantiation", true)!;
static readonly Type _fieldOnTypeBuilderInstantiationType = typeof(TypeBuilder).Assembly.GetType("System.Reflection.Emit.FieldOnTypeBuilderInstantiation", true)!;

#if NET

#if NET8_0_OR_GREATER
Expand All @@ -25,13 +33,55 @@ static class ReflectionExtensions
static readonly Type _eventBuilderType = typeof(EventBuilder).Assembly.GetType("System.Reflection.Emit.RuntimeEventBuilder", true)!;
static readonly Type _parameterBuilderType = typeof(ParameterBuilder).Assembly.GetType("System.Reflection.Emit.RuntimeParameterBuilder", true)!;

static readonly Func<ConstructorInfo, ConstructorInfo> _getConstructorOnTypeBuilderInstantiationConstructorFunc = Expression.Lambda<Func<ConstructorInfo, ConstructorInfo>>(
Expression.Field(
Expression.ConvertChecked(_constructorInfoParameter, _constructorOnTypeBuilderInstantiationType),
_constructorOnTypeBuilderInstantiationType.GetField("_ctor", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_constructorInfoParameter)
.Compile();

static readonly Func<MethodInfo, MethodInfo> _getMethodOnTypeBuilderInstantiationMethodFunc = Expression.Lambda<Func<MethodInfo, MethodInfo>>(
Expression.Field(
Expression.ConvertChecked(_methodInfoParameter, _methodOnTypeBuilderInstantiationType),
_methodOnTypeBuilderInstantiationType.GetField("_method", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_methodInfoParameter)
.Compile();

static readonly Func<FieldInfo, FieldInfo> _getFieldOnTypeBuilderInstantiationFieldFunc = Expression.Lambda<Func<FieldInfo, FieldInfo>>(
Expression.Field(
Expression.ConvertChecked(_fieldInfoParameter, _fieldOnTypeBuilderInstantiationType),
_fieldOnTypeBuilderInstantiationType.GetField("_field", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_fieldInfoParameter)
.Compile();

#else

static readonly Type _assemblyBuilderType = typeof(AssemblyBuilder).Assembly.GetType("System.Reflection.Emit.AssemblyBuilder", true)!;
static readonly Type _propertyBuilderType = typeof(PropertyBuilder).Assembly.GetType("System.Reflection.Emit.PropertyBuilder", true)!;
static readonly Type _eventBuilderType = typeof(EventBuilder).Assembly.GetType("System.Reflection.Emit.EventBuilder", true)!;
static readonly Type _parameterBuilderType = typeof(ParameterBuilder).Assembly.GetType("System.Reflection.Emit.ParameterBuilder", true)!;

static readonly Func<ConstructorInfo, ConstructorInfo> _getConstructorOnTypeBuilderInstantiationConstructorFunc = Expression.Lambda<Func<ConstructorInfo, ConstructorInfo>>(
Expression.Field(
Expression.ConvertChecked(_constructorInfoParameter, _constructorOnTypeBuilderInstantiationType),
_constructorOnTypeBuilderInstantiationType.GetField("m_ctor", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_constructorInfoParameter)
.Compile();

static readonly Func<MethodInfo, MethodInfo> _getMethodOnTypeBuilderInstantiationMethodFunc = Expression.Lambda<Func<MethodInfo, MethodInfo>>(
Expression.Field(
Expression.ConvertChecked(_methodInfoParameter, _methodOnTypeBuilderInstantiationType),
_methodOnTypeBuilderInstantiationType.GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_methodInfoParameter)
.Compile();

static readonly Func<FieldInfo, FieldInfo> _getFieldOnTypeBuilderInstantiationFieldFunc = Expression.Lambda<Func<FieldInfo, FieldInfo>>(
Expression.Field(
Expression.ConvertChecked(_fieldInfoParameter, _fieldOnTypeBuilderInstantiationType),
_fieldOnTypeBuilderInstantiationType.GetField("m_field", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_fieldInfoParameter)
.Compile();

#endif

static readonly Func<AssemblyBuilder, Assembly> _getAssemblyBuilderRuntimeAssemblyFunc = Expression.Lambda<Func<AssemblyBuilder, Assembly>>(
Expand Down Expand Up @@ -75,6 +125,27 @@ static class ReflectionExtensions
static readonly Type _eventBuilderType = typeof(EventBuilder).Assembly.GetType("System.Reflection.Emit.EventBuilder", true)!;
static readonly Type _parameterBuilderType = typeof(ParameterBuilder).Assembly.GetType("System.Reflection.Emit.ParameterBuilder", true)!;

static readonly Func<ConstructorInfo, ConstructorInfo> _getConstructorOnTypeBuilderInstantiationConstructorFunc = Expression.Lambda<Func<ConstructorInfo, ConstructorInfo>>(
Expression.Field(
Expression.ConvertChecked(_constructorInfoParameter, _constructorOnTypeBuilderInstantiationType),
_constructorOnTypeBuilderInstantiationType.GetField("m_ctor", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_constructorInfoParameter)
.Compile();

static readonly Func<MethodInfo, MethodInfo> _getMethodOnTypeBuilderInstantiationMethodFunc = Expression.Lambda<Func<MethodInfo, MethodInfo>>(
Expression.Field(
Expression.ConvertChecked(_methodInfoParameter, _methodOnTypeBuilderInstantiationType),
_methodOnTypeBuilderInstantiationType.GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_methodInfoParameter)
.Compile();

static readonly Func<FieldInfo, FieldInfo> _getFieldOnTypeBuilderInstantiationFieldFunc = Expression.Lambda<Func<FieldInfo, FieldInfo>>(
Expression.Field(
Expression.ConvertChecked(_fieldInfoParameter, _fieldOnTypeBuilderInstantiationType),
_fieldOnTypeBuilderInstantiationType.GetField("m_field", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException()),
_fieldInfoParameter)
.Compile();

static readonly Func<AssemblyBuilder, Assembly> _getAssemblyBuilderRuntimeAssemblyFunc = Expression.Lambda<Func<AssemblyBuilder, Assembly>>(
Expression.Call(
Expression.ConvertChecked(_assemblyBuilderRuntimeAssemblyParameter, _assemblyBuilderType),
Expand Down Expand Up @@ -121,6 +192,11 @@ static class ReflectionExtensions
_eventBuilderParameter)
.Compile();

/// <summary>
/// Gets the <see cref="MethodOnTypeBuilderInstantiation"/> type.
/// </summary>
public static Type MethodOnTypeBuilderInstantiationType => _methodOnTypeBuilderInstantiationType;

/// <summary>
/// Gets the metadata token for the specified <see cref="Type"/>.
/// </summary>
Expand Down Expand Up @@ -212,6 +288,15 @@ public static int GetMetadataTokenSafe(this FieldInfo field)
}
#endif

#if NET8_0_OR_GREATER || NETFRAMEWORK
// field is instance of FieldOnTypeBuilderInstantiation
if (_fieldOnTypeBuilderInstantiationType.IsInstanceOfType(field))
{
var f = _getFieldOnTypeBuilderInstantiationFieldFunc(field);
return f.GetMetadataTokenSafe();
}
#endif

return field.GetMetadataToken();
}

Expand Down Expand Up @@ -275,6 +360,15 @@ public static int GetMetadataTokenSafe(this ConstructorInfo ctor)
}
#endif

#if NET8_0_OR_GREATER || NETFRAMEWORK
// ctor is instance of ConstructorOnTypeBuilderInstantiation
if (_constructorOnTypeBuilderInstantiationType.IsInstanceOfType(ctor))
{
var c = _getConstructorOnTypeBuilderInstantiationConstructorFunc(ctor);
return c.GetMetadataTokenSafe();
}
#endif

return ctor.GetMetadataToken();
}

Expand Down Expand Up @@ -306,17 +400,35 @@ public static int GetMetadataTokenSafe(this MethodInfo method)
}
#endif

#if NET8_0_OR_GREATER || NETFRAMEWORK
// method is instance of MethodOnTypeBuilderInstantiation
if (_methodOnTypeBuilderInstantiationType.IsInstanceOfType(method))
{
var m = _getMethodOnTypeBuilderInstantiationMethodFunc(method);
return m.GetMetadataTokenSafe();
}
#endif

#if NET6_0
// method is instance of MethodOnTypeBuilderInstantiation
if (_methodOnTypeBuilderInstantiationType.IsInstanceOfType(method))
{
var m = _getMethodOnTypeBuilderInstantiationMethodFunc(method);
return m.GetMetadataTokenSafe();
}
#endif

return method.GetMetadataToken();
}

/// <summary>
/// Gets the metadata row number for the specified <see cref="MethodInfo"/>.
/// </summary>
/// <param name="ctor"></param>
/// <param name="method"></param>
/// <returns></returns>
public static int GetMetadataTokenRowNumberSafe(this MethodInfo ctor)
public static int GetMetadataTokenRowNumberSafe(this MethodInfo method)
{
return MetadataTokens.GetRowNumber(MetadataTokens.MethodDefinitionHandle(ctor.GetMetadataTokenSafe()));
return MetadataTokens.GetRowNumber(MetadataTokens.MethodDefinitionHandle(method.GetMetadataTokenSafe()));
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ReflectionMethodSymbolBuilder : ReflectionMethodSymbol, IReflectionMethodS
public ReflectionMethodSymbolBuilder(ReflectionSymbolContext context, IReflectionModuleSymbolBuilder resolvingModule, IReflectionTypeSymbolBuilder? resolvingType, MethodBuilder builder) :
base(context, resolvingModule, resolvingType, builder)
{
_builder = builder;
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
}

/// <inheritdoc />
Expand Down
Loading

0 comments on commit b743767

Please sign in to comment.