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