Skip to content

Commit

Permalink
Update builder
Browse files Browse the repository at this point in the history
  • Loading branch information
usausa committed May 9, 2019
1 parent bce0698 commit 98c35be
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 118 deletions.
224 changes: 110 additions & 114 deletions Smart.Resolver/Resolver/Builders/EmitFactoryBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,77 +1,27 @@
namespace Smart.Resolver.Builders
{
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

using Smart.Reflection.Emit;

public sealed class EmitFactoryBuilder : IFactoryBuilder
{
private AssemblyBuilder assemblyBuilder;
private static readonly Action<IResolver, object>[] EmptyActions = new Action<IResolver, object>[0];

private ModuleBuilder moduleBuilder;

private int nextId = 1;

private ModuleBuilder ModuleBuilder
{
get
{
if (moduleBuilder == null)
{
assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName("EmitBuilderAssembly"),
AssemblyBuilderAccess.Run);
moduleBuilder = assemblyBuilder.DefineDynamicModule(
"EmitBuilderModule");
}

return moduleBuilder;
}
}

private int GenerateId()
{
lock (assemblyBuilder)
{
return nextId++;
}
}
private readonly HolderBuilder holderBuilder = new HolderBuilder();

public Func<IResolver, object> CreateFactory(ConstructorInfo ci, Func<IResolver, object>[] factories, Action<IResolver, object>[] actions)
{
var holder = holderBuilder.CreateHolder(factories, actions);
var holderType = holder?.GetType() ?? typeof(object);

var returnType = ci.DeclaringType.IsValueType ? typeof(object) : ci.DeclaringType;

// Define type
var typeBuilder = ModuleBuilder.DefineType(
$"{ci.DeclaringType.FullName}_Factory_{GenerateId()}",
TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);

// Define field
var factoryFields = factories
.Select((t, i) => typeBuilder.DefineField(
$"factory{i}",
t.GetType(),
FieldAttributes.Public | FieldAttributes.InitOnly))
.ToList();

var actionFields = actions
.Select((t, i) => typeBuilder.DefineField(
$"actions{i}",
t.GetType(),
FieldAttributes.Public | FieldAttributes.InitOnly))
.ToList();

// Define method
var method = typeBuilder.DefineMethod(
"Create",
MethodAttributes.Public | MethodAttributes.HideBySig,
returnType,
new[] { typeof(IResolver) });

var ilGenerator = method.GetILGenerator();
var dynamicMethod = new DynamicMethod(string.Empty, returnType, new[] { holderType, typeof(IResolver) }, true);
var ilGenerator = dynamicMethod.GetILGenerator();

for (var i = 0; i < factories.Length; i++)
{
Expand All @@ -83,8 +33,10 @@ public Func<IResolver, object> CreateFactory(ConstructorInfo ci, Func<IResolver,
throw new ArgumentException($"Invalid factory[{i}]");
}

var field = holderType.GetField($"factory{i}");

ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, factoryFields[i]);
ilGenerator.Emit(OpCodes.Ldfld, field);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Call, invokeMethod);
if (ci.GetParameters()[i].ParameterType.IsValueType)
Expand All @@ -111,8 +63,10 @@ public Func<IResolver, object> CreateFactory(ConstructorInfo ci, Func<IResolver,
throw new ArgumentException($"Invalid actions[{i}]");
}

var field = holderType.GetField($"action{i}");

ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, actionFields[i]);
ilGenerator.Emit(OpCodes.Ldfld, field);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Ldloc_0);
ilGenerator.Emit(OpCodes.Callvirt, invokeMethod);
Expand All @@ -128,66 +82,32 @@ public Func<IResolver, object> CreateFactory(ConstructorInfo ci, Func<IResolver,

ilGenerator.Emit(OpCodes.Ret);

var typeInfo = typeBuilder.CreateTypeInfo();
var factoryType = typeInfo.AsType();

// Prepare instance
var instance = Activator.CreateInstance(factoryType);

for (var i = 0; i < factories.Length; i++)
{
var fi = factoryType.GetField($"factory{i}");
fi.SetValue(instance, factories[i]);
}

for (var i = 0; i < actions.Length; i++)
{
var fi = factoryType.GetField($"actions{i}");
fi.SetValue(instance, actions[i]);
}

// Make delegate
var funcType = typeof(Func<,>).MakeGenericType(typeof(IResolver), returnType);
// ReSharper disable once AssignNullToNotNullAttribute
return (Func<IResolver, object>)Delegate.CreateDelegate(funcType, instance, factoryType.GetMethod("Create"));
return (Func<IResolver, object>)dynamicMethod.CreateDelegate(funcType, holder);
}

public Func<IResolver, object> CreateArrayFactory(Type type, Func<IResolver, object>[] factories)
{
var arrayType = type.MakeArrayType();
var holder = holderBuilder.CreateHolder(factories, EmptyActions);
var holderType = holder?.GetType() ?? typeof(object);

// Define type
var typeBuilder = ModuleBuilder.DefineType(
$"{arrayType.FullName}_Factory_{GenerateId()}",
TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);

// Define field
var fields = factories
.Select((t, i) => typeBuilder.DefineField(
$"factory{i}",
t.GetType(),
FieldAttributes.Public | FieldAttributes.InitOnly))
.ToList();

// Define method
var method = typeBuilder.DefineMethod(
"Create",
MethodAttributes.Public | MethodAttributes.HideBySig,
arrayType,
new[] { typeof(IResolver) });
var arrayType = type.MakeArrayType();

var ilGenerator = method.GetILGenerator();
var dynamicMethod = new DynamicMethod(string.Empty, arrayType, new[] { holderType, typeof(IResolver) }, true);
var ilGenerator = dynamicMethod.GetILGenerator();

ilGenerator.EmitLdcI4(factories.Length);
ilGenerator.Emit(OpCodes.Newarr, type);

for (var i = 0; i < factories.Length; i++)
{
var field = holderType.GetField($"factory{i}");

ilGenerator.Emit(OpCodes.Dup);
ilGenerator.EmitLdcI4(i);

ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, fields[i]);
ilGenerator.Emit(OpCodes.Ldfld, field);
ilGenerator.Emit(OpCodes.Ldarg_1);
var invokeMethod = factories[i].GetType().GetMethod("Invoke", new[] { typeof(IResolver) });
ilGenerator.Emit(OpCodes.Call, invokeMethod);
Expand All @@ -197,22 +117,98 @@ public Func<IResolver, object> CreateArrayFactory(Type type, Func<IResolver, obj

ilGenerator.Emit(OpCodes.Ret);

var typeInfo = typeBuilder.CreateTypeInfo();
var factoryType = typeInfo.AsType();
var funcType = typeof(Func<,>).MakeGenericType(typeof(IResolver), arrayType);
return (Func<IResolver, object>)dynamicMethod.CreateDelegate(funcType, holder);
}

private sealed class HolderBuilder
{
private readonly Dictionary<Tuple<int, int>, Type> cache = new Dictionary<Tuple<int, int>, Type>();

// Prepare instance
var instance = Activator.CreateInstance(factoryType);
private AssemblyBuilder assemblyBuilder;

for (var i = 0; i < factories.Length; i++)
private ModuleBuilder moduleBuilder;

private ModuleBuilder ModuleBuilder
{
var fi = factoryType.GetField($"factory{i}");
fi.SetValue(instance, factories[i]);
get
{
if (moduleBuilder == null)
{
assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName("EmitBuilderAssembly"),
AssemblyBuilderAccess.Run);
moduleBuilder = assemblyBuilder.DefineDynamicModule(
"EmitBuilderModule");
}

return moduleBuilder;
}
}

// Make delegate
var funcType = typeof(Func<,>).MakeGenericType(typeof(IResolver), arrayType);
// ReSharper disable once AssignNullToNotNullAttribute
return (Func<IResolver, object>)Delegate.CreateDelegate(funcType, instance, factoryType.GetMethod("Create"));
public object CreateHolder(Func<IResolver, object>[] factories, Action<IResolver, object>[] actions)
{
if ((factories.Length == 0) && (actions.Length == 0))
{
return null;
}

var key = Tuple.Create(factories.Length, actions.Length);
Type type;
lock (cache)
{
if (!cache.TryGetValue(key, out type))
{
type = CreateType(factories.Length, actions.Length);
cache[key] = type;
}
}

var holder = Activator.CreateInstance(type);

for (var i = 0; i < factories.Length; i++)
{
var field = type.GetField($"factory{i}");
field.SetValue(holder, factories[i]);
}

for (var i = 0; i < actions.Length; i++)
{
var field = type.GetField($"action{i}");
field.SetValue(holder, actions[i]);
}

return holder;
}

private Type CreateType(int factoryCount, int actionCount)
{
// Define type
var typeBuilder = ModuleBuilder.DefineType(
$"Holder_{factoryCount}_{actionCount}",
TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);

// Define factory fields
for (var i = 0; i < factoryCount; i++)
{
typeBuilder.DefineField(
$"factory{i}",
typeof(Func<IResolver, object>),
FieldAttributes.Public);
}

// Define action fields
for (var i = 0; i < actionCount; i++)
{
typeBuilder.DefineField(
$"action{i}",
typeof(Action<IResolver, object>),
FieldAttributes.Public);
}

var typeInfo = typeBuilder.CreateTypeInfo();
return typeInfo.AsType();
}
}
}
}
4 changes: 0 additions & 4 deletions Smart.Resolver/Smart.Resolver.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,4 @@
<PackageReference Include="Usa.Smart.Core" Version="1.7.3" />
</ItemGroup>

<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>

</Project>

0 comments on commit 98c35be

Please sign in to comment.