From 08da959737d1ba079d32b6233b5789bb0fee84be Mon Sep 17 00:00:00 2001
From: NextTurn <45985406+NextTurn@users.noreply.github.com>
Date: Tue, 4 Dec 2018 00:00:00 +0800
Subject: [PATCH] Optimize DynamicProxy
---
src/Core/WinSWCore/DynamicProxy.cs | 247 +++++------------------------
src/Core/WinSWCore/Wmi.cs | 6 +-
2 files changed, 46 insertions(+), 207 deletions(-)
diff --git a/src/Core/WinSWCore/DynamicProxy.cs b/src/Core/WinSWCore/DynamicProxy.cs
index 740e44e..0589e27 100644
--- a/src/Core/WinSWCore/DynamicProxy.cs
+++ b/src/Core/WinSWCore/DynamicProxy.cs
@@ -19,196 +19,63 @@ namespace DynamicProxy
}
///
- /// Factory class used to cache Types instances
///
- public class MetaDataFactory
+ public static class ProxyFactory
{
- private static readonly Dictionary typeMap = new Dictionary();
-
- ///
- /// Class constructor. Private because this is a static class.
- ///
- private MetaDataFactory()
- {
- }
-
- ///
- /// Method to add a new Type to the cache, using the type's fully qualified
- /// name as the key
- ///
- ///Type to cache
- public static void Add(Type interfaceType)
- {
- if (interfaceType != null)
- {
- lock (typeMap)
- {
-#if NETCOREAPP
- _ = typeMap.TryAdd(interfaceType.FullName!, interfaceType);
-#else
- if (!typeMap.ContainsKey(interfaceType.FullName!))
- {
- typeMap.Add(interfaceType.FullName!, interfaceType);
- }
-#endif
- }
- }
- }
-
- ///
- /// Method to return the method of a given type at a specified index.
- ///
- ///Fully qualified name of the method to return
- ///Index to use to return MethodInfo
- ///MethodInfo
- public static MethodInfo GetMethod(string name, int i)
- {
- Type? type = null;
- lock (typeMap)
- {
- type = typeMap[name];
- }
-
- return type.GetMethods()[i];
- }
-
- public static PropertyInfo GetProperty(string name, int i)
- {
- Type? type = null;
- lock (typeMap)
- {
- type = typeMap[name];
- }
-
- return type.GetProperties()[i];
- }
- }
-
- ///
- ///
- public class ProxyFactory
- {
- private static ProxyFactory? _instance;
- private static readonly object LockObj = new object();
-
- private readonly Dictionary _typeMap = new Dictionary();
-
- private static readonly Dictionary OpCodeTypeMapper = new Dictionary
- {
- { typeof(bool), OpCodes.Ldind_I1 },
- { typeof(short), OpCodes.Ldind_I2 },
- { typeof(int), OpCodes.Ldind_I4 },
- { typeof(long), OpCodes.Ldind_I8 },
- { typeof(double), OpCodes.Ldind_R8 },
- { typeof(float), OpCodes.Ldind_R4 },
- { typeof(ushort), OpCodes.Ldind_U2 },
- { typeof(uint), OpCodes.Ldind_U4 },
- };
-
private const string ProxySuffix = "Proxy";
private const string AssemblyName = "ProxyAssembly";
private const string ModuleName = "ProxyModule";
private const string HandlerName = "handler";
- private ProxyFactory()
- {
- }
+ private static readonly Dictionary TypeCache = new Dictionary();
- public static ProxyFactory GetInstance()
- {
- if (_instance == null)
- {
- CreateInstance();
- }
+ private static readonly AssemblyBuilder AssemblyBuilder =
+#if VNEXT
+ AssemblyBuilder.DefineDynamicAssembly(
+#else
+ AppDomain.CurrentDomain.DefineDynamicAssembly(
+#endif
+ new AssemblyName(AssemblyName), AssemblyBuilderAccess.Run);
- return _instance!;
- }
+ private static readonly ModuleBuilder ModuleBuilder = AssemblyBuilder.DefineDynamicModule(ModuleName);
- private static void CreateInstance()
- {
- lock (LockObj)
- {
- _instance ??= new ProxyFactory();
- }
- }
-
- public object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface)
+ public static object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface = false)
{
string typeName = objType.FullName + ProxySuffix;
Type? type = null;
- lock (_typeMap)
+ lock (TypeCache)
{
- _ = _typeMap.TryGetValue(typeName, out type);
- }
-
- // check to see if the type was in the cache. If the type was not cached, then
- // create a new instance of the dynamic type and add it to the cache.
- if (type == null)
- {
- if (isObjInterface)
+ if (!TypeCache.TryGetValue(typeName, out type))
{
- type = CreateType(handler, new Type[] { objType }, typeName);
- }
- else
- {
- type = CreateType(handler, objType.GetInterfaces(), typeName);
- }
-
- lock (_typeMap)
- {
- _typeMap.Add(typeName, type);
+ type = CreateType(typeName, isObjInterface ? new Type[] { objType } : objType.GetInterfaces());
+ TypeCache.Add(typeName, type);
}
}
- // return a new instance of the type.
return Activator.CreateInstance(type, new object[] { handler })!;
}
- public object Create(IProxyInvocationHandler handler, Type objType)
- {
- return Create(handler, objType, false);
- }
-
- private Type CreateType(IProxyInvocationHandler handler, Type[] interfaces, string dynamicTypeName)
+ private static Type CreateType(string dynamicTypeName, Type[] interfaces)
{
Type objType = typeof(object);
Type handlerType = typeof(IProxyInvocationHandler);
- AssemblyName assemblyName = new AssemblyName();
- assemblyName.Name = AssemblyName;
- assemblyName.Version = new Version(1, 0, 0, 0);
-
- // create a new assembly for this proxy, one that isn't presisted on the file system
- AssemblyBuilder assemblyBuilder =
-#if VNEXT
- AssemblyBuilder.DefineDynamicAssembly(
-#else
- AppDomain.CurrentDomain.DefineDynamicAssembly(
-#endif
- assemblyName, AssemblyBuilderAccess.Run);
-
- // create a new module for this proxy
- ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(ModuleName);
-
- // Set the class to be public and sealed
- TypeAttributes typeAttributes =
- TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
+ TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
// Gather up the proxy information and create a new type builder. One that
// inherits from Object and implements the interface passed in
- TypeBuilder typeBuilder = moduleBuilder.DefineType(
+ TypeBuilder typeBuilder = ModuleBuilder.DefineType(
dynamicTypeName, typeAttributes, objType, interfaces);
// Define a member variable to hold the delegate
FieldBuilder handlerField = typeBuilder.DefineField(
- HandlerName, handlerType, FieldAttributes.Private);
+ HandlerName, handlerType, FieldAttributes.Private | FieldAttributes.InitOnly);
// build a constructor that takes the delegate object as the only argument
ConstructorInfo baseConstructor = objType.GetConstructor(Type.EmptyTypes)!;
ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
- #region( "Constructor IL Code" )
ILGenerator constructorIL = delegateConstructor.GetILGenerator();
// Load "this"
@@ -223,7 +90,6 @@ namespace DynamicProxy
constructorIL.Emit(OpCodes.Call, baseConstructor);
// Constructor return
constructorIL.Emit(OpCodes.Ret);
- #endregion
// for every method that the interfaces define, build a corresponding
// method in the dynamic type that calls the handlers invoke method.
@@ -235,14 +101,19 @@ namespace DynamicProxy
return typeBuilder.CreateType()!;
}
- private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod(nameof(IProxyInvocationHandler.Invoke))!;
- private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod(nameof(MetaDataFactory.GetMethod))!;
+ ///
+ /// .
+ ///
+ private static readonly MethodInfo InvokeMethod = typeof(IProxyInvocationHandler).GetMethod(nameof(IProxyInvocationHandler.Invoke))!;
- private void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
+ ///
+ /// .
+ ///
+ private static readonly MethodInfo GetMethodFromHandleMethod = typeof(MethodBase).GetMethod(nameof(MethodBase.GetMethodFromHandle), new[] { typeof(RuntimeMethodHandle) })!;
+
+ private static void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
{
- MetaDataFactory.Add(interfaceType);
MethodInfo[] interfaceMethods = interfaceType.GetMethods();
- // PropertyInfo[] props = interfaceType.GetProperties();
for (int i = 0; i < interfaceMethods.Length; i++)
{
@@ -267,36 +138,31 @@ namespace DynamicProxy
CallingConventions.Standard,
methodInfo.ReturnType, methodParameters);
- #region( "Handler Method IL Code" )
ILGenerator methodIL = methodBuilder.GetILGenerator();
- // load "this"
+ // invoke target: IProxyInvocationHandler
methodIL.Emit(OpCodes.Ldarg_0);
- // load the handler
methodIL.Emit(OpCodes.Ldfld, handlerField);
- // load "this" since its needed for the call to invoke
- methodIL.Emit(OpCodes.Ldarg_0);
- // load the name of the interface, used to get the MethodInfo object
- // from MetaDataFactory
- methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName!);
- // load the index, used to get the MethodInfo object
- // from MetaDataFactory
- methodIL.Emit(OpCodes.Ldc_I4, i);
- // invoke GetMethod in MetaDataFactory
- methodIL.Emit(OpCodes.Call, GET_METHODINFO_METHOD);
- // load the number of parameters onto the stack
+ // 1st parameter: object proxy
+ methodIL.Emit(OpCodes.Ldarg_0);
+
+ // 2nd parameter: MethodInfo method
+ methodIL.Emit(OpCodes.Ldtoken, methodInfo);
+ methodIL.Emit(OpCodes.Call, GetMethodFromHandleMethod);
+ methodIL.Emit(OpCodes.Castclass, typeof(MethodInfo));
+
+ // 3rd parameter: object[] parameters
methodIL.Emit(OpCodes.Ldc_I4, numOfParams);
- // create a new array, using the size that was just pused on the stack
methodIL.Emit(OpCodes.Newarr, typeof(object));
// if we have any parameters, then iterate through and set the values
// of each element to the corresponding arguments
for (int j = 0; j < numOfParams; j++)
{
- methodIL.Emit(OpCodes.Dup); // this copies the array
+ methodIL.Emit(OpCodes.Dup); // copy the array
methodIL.Emit(OpCodes.Ldc_I4, j);
- methodIL.Emit(OpCodes.Ldarg, j + 1);
+ methodIL.Emit(OpCodes.Ldarg, j + 1); // +1 for "this"
if (methodParameters[j].IsValueType)
{
methodIL.Emit(OpCodes.Box, methodParameters[j]);
@@ -306,28 +172,11 @@ namespace DynamicProxy
}
// call the Invoke method
- methodIL.Emit(OpCodes.Callvirt, INVOKE_METHOD);
+ methodIL.Emit(OpCodes.Callvirt, InvokeMethod);
if (methodInfo.ReturnType != typeof(void))
{
- // if the return type is a value type, then unbox the return value
- // so that we don't get junk.
- if (methodInfo.ReturnType.IsValueType)
- {
- methodIL.Emit(OpCodes.Unbox, methodInfo.ReturnType);
- if (methodInfo.ReturnType.IsEnum)
- {
- methodIL.Emit(OpCodes.Ldind_I4);
- }
- else if (!methodInfo.ReturnType.IsPrimitive)
- {
- methodIL.Emit(OpCodes.Ldobj, methodInfo.ReturnType);
- }
- else
- {
- methodIL.Emit(OpCodeTypeMapper[methodInfo.ReturnType]);
- }
- }
+ methodIL.Emit(OpCodes.Unbox_Any, methodInfo.ReturnType);
}
else
{
@@ -338,18 +187,8 @@ namespace DynamicProxy
// Return
methodIL.Emit(OpCodes.Ret);
- #endregion
}
- // for (int i = 0; i < props.Length; i++)
- // {
- // PropertyInfo p = props[i];
-
- // PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType });
- // pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]);
- // pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]);
- // }
-
// Iterate through the parent interfaces and recursively call this method
foreach (Type parentType in interfaceType.GetInterfaces())
{
diff --git a/src/Core/WinSWCore/Wmi.cs b/src/Core/WinSWCore/Wmi.cs
index 22c6b27..d6bb359 100755
--- a/src/Core/WinSWCore/Wmi.cs
+++ b/src/Core/WinSWCore/Wmi.cs
@@ -289,7 +289,7 @@ namespace WMI
// TODO: support collections
foreach (CimInstance cimInstance in this.cimSession.QueryInstances(CimNamespace, "WQL", query))
{
- return ProxyFactory.GetInstance().Create(new InstanceHandler(this.cimSession, cimInstance), method.ReturnType, true);
+ return ProxyFactory.Create(new InstanceHandler(this.cimSession, cimInstance), method.ReturnType, true);
}
#else
using ManagementObjectSearcher searcher = new ManagementObjectSearcher(this.wmiClass.Scope, new ObjectQuery(query));
@@ -297,7 +297,7 @@ namespace WMI
// TODO: support collections
foreach (ManagementObject wmiObject in results)
{
- return ProxyFactory.GetInstance().Create(new InstanceHandler(wmiObject), method.ReturnType, true);
+ return ProxyFactory.Create(new InstanceHandler(wmiObject), method.ReturnType, true);
}
#endif
@@ -327,7 +327,7 @@ namespace WMI
{
WmiClassName className = (WmiClassName)typeof(T).GetCustomAttributes(typeof(WmiClassName), false)[0];
- return (T)ProxyFactory.GetInstance().Create(
+ return (T)ProxyFactory.Create(
#if FEATURE_CIM
new ClassHandler(this.cimSession, className.Name),
#else