-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: Lightweight Code Generation using IGetSetHelper (.NET 2.0)
PostPosted: Thu Feb 09, 2006 11:09 am 
Beginner
Beginner

Joined: Tue May 17, 2005 7:25 pm
Posts: 43
Location: Somewhere, USA
I have implemented a LCG IGetSetHelper implementation. It needs to be tested (and I don't really have the time to manage it). So here it is...

Code:
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Cfg/Environment.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Cfg/Environment.cs   (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Cfg/Environment.cs   (revision 92)
@@ -94,8 +94,10 @@
      public const string PrepareSql = "hibernate.prepare_sql";
      public const string CommandTimeout = "hibernate.command_timeout";
      public const string PropertyUseReflectionOptimizer = "hibernate.use_reflection_optimizer";
+        public const string PropertyUseLightweightCodeGeneration = "hibernate.use_lightweight_code_generation";

      private static bool EnableReflectionOptimizer;
+        private static bool EnableLightweightCodeGeneration;

      private static IDictionary GlobalProperties;

@@ -191,5 +193,14 @@
         get { return EnableReflectionOptimizer; }
         set { EnableReflectionOptimizer = value; }
      }
+
+        /// <summary>
+        /// Enables the use of .NET 2.0 LCG techniques within the reflection optimizer.
+        /// </summary>
+        public static bool UseLightweightCodeGeneration
+        {
+            get { return EnableLightweightCodeGeneration; }
+            set { EnableLightweightCodeGeneration = value; }
+        }
   }
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/ISetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/ISetter.cs   (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/ISetter.cs   (revision 92)
@@ -40,5 +40,16 @@
      /// &lt;id&gt; property.
      /// </remarks>
      PropertyInfo Property { get; }
+
+        /// <summary>
+        /// Gets the member info of the underlying member that this getter wraps.
+        /// Should return null when not implemented.
+        /// </summary>
+        MemberInfo Member { get; }
+
+        /// <summary>
+        /// Gets the type of the property/field.
+        /// </summary>
+        System.Type ValueType { get; }
   }
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicGetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicGetter.cs   (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicGetter.cs   (revision 92)
@@ -75,6 +75,10 @@
         get { return property; }
      }

+        public MemberInfo Member
+        {
+            get { return property; }
+        }
      #endregion
   }
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldGetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldGetter.cs   (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldGetter.cs   (revision 92)
@@ -73,6 +73,10 @@
         get { return null; }
      }

+        public MemberInfo Member
+        {
+            get { return field; }
+        }
      #endregion
   }
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/IGetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/IGetter.cs   (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/IGetter.cs   (revision 92)
@@ -48,5 +48,11 @@
      /// &lt;id&gt; property.
      /// </remarks>
      PropertyInfo Property { get; }
+
+        /// <summary>
+        /// Gets the member info of the underlying member that this getter wraps.
+        /// Should return null when not implemented.
+        /// </summary>
+        MemberInfo Member { get; }
   }
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicSetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicSetter.cs   (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicSetter.cs   (revision 92)
@@ -81,6 +81,15 @@
         get { return property; }
      }

+        public MemberInfo Member
+        {
+            get { return property; }
+        }
+
+        public System.Type ValueType
+        {
+            get { return property.PropertyType; }
+        }
      #endregion
   }
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldSetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldSetter.cs   (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldSetter.cs   (revision 92)
@@ -81,6 +81,15 @@
         get { return null; }
      }

+        public MemberInfo Member
+        {
+            get { return field; }
+        }
+
+        public System.Type ValueType
+        {
+            get { return field.FieldType; }
+        }
      #endregion
   }

Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/LCGGetSetHelper.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/LCGGetSetHelper.cs   (revision 0)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/LCGGetSetHelper.cs   (revision 92)
@@ -0,0 +1,243 @@
+using System;
+using System.CodeDom.Compiler;
+using System.Globalization;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+using log4net;
+using NHibernate.Property;
+
+namespace NHibernate.Persister
+{
+    class LCGGetSetHelper : IGetSetHelper
+    {
+        private delegate void SetPropertyValuesInvoker(object o,object[] values);
+        private delegate object[] GetPropertyValuesInvoker(object o);
+
+        private SetPropertyValuesInvoker m_Setter;
+        private GetPropertyValuesInvoker m_Getter;
+
+        private static readonly ILog m_Log = LogManager.GetLogger(typeof(LCGGetSetHelper));
+
+        /// <summary>
+        /// Class constructor.
+        /// </summary>
+        /// <param name="mappedClass"></param>
+        /// <param name="setters"></param>
+        /// <param name="getters"></param>
+        public LCGGetSetHelper(System.Type mappedClass, ISetter[] setters, IGetter[] getters)
+        {
+            //Generate the set and get dynamic methods
+            m_Setter = GenerateSetPropertyValuesMethod(mappedClass, setters);
+            m_Getter = GenerateGetPropertyValuesMethod(mappedClass, getters);
+        }
+
+        /// <summary>
+        /// Generates a dynamic method on the given type.
+        /// </summary>
+        /// <param name="mappedClass"></param>
+        /// <param name="getters"></param>
+        /// <returns></returns>
+        private static GetPropertyValuesInvoker GenerateGetPropertyValuesMethod(System.Type mappedClass, IGetter[] getters)
+        {
+            DynamicMethod method = new DynamicMethod(
+                String.Empty,
+                typeof(object[]),
+                new System.Type[] { typeof(object) },
+                mappedClass,
+                true);
+
+            ILGenerator il = method.GetILGenerator();
+
+            // Declare the locals
+            LocalBuilder dataLocal = il.DeclareLocal(typeof(Object[]));
+            LocalBuilder thisLocal = il.DeclareLocal(mappedClass);
+
+            // Set the this local
+            il.Emit(OpCodes.Ldarg_0);
+            il.Emit(OpCodes.Stloc, thisLocal.LocalIndex);
+
+            // Allocate the data array
+            il.Emit(OpCodes.Ldc_I4, getters.Length);
+            il.Emit(OpCodes.Newarr, typeof(Object));
+            il.Emit(OpCodes.Stloc, dataLocal.LocalIndex);
+
+            //get all the data from the object into the data array to be returned
+            for (int i = 0; i < getters.Length; i++)
+            {
+                // get the member accessors
+                IGetter getter = getters[i];
+                if (getter.Member != null)
+                {
+                    // get the data element location
+                    il.Emit(OpCodes.Ldloc, dataLocal.LocalIndex);
+                    il.Emit(OpCodes.Ldc_I4, i);
+
+                    // get the value
+                    il.Emit((mappedClass.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc), thisLocal.LocalIndex);
+                    switch (getter.Member.MemberType)
+                    {
+                        // fields...
+                        case MemberTypes.Field:
+                            FieldInfo fieldInfo = ((FieldInfo)getter.Member);
+                            il.Emit(OpCodes.Ldfld, fieldInfo);
+                            break;
+
+                        // properties...
+                        case MemberTypes.Property:
+                            MethodInfo methodInfo = ((PropertyInfo)getter.Member).GetGetMethod(true);
+                            if (methodInfo != null)
+                            {
+                                if (methodInfo.IsVirtual)
+                                {
+                                    il.Emit(OpCodes.Callvirt, methodInfo);
+                                }
+                                else
+                                {
+                                    il.Emit(OpCodes.Call, methodInfo);
+                                }
+                            }
+                            else
+                            {
+                                m_Log.InfoFormat("Property {0} is marked write-only. Retrieving null value.", getter.PropertyName);
+                                il.Emit(OpCodes.Pop);
+                                il.Emit(OpCodes.Ldnull);
+                            }
+                            break;
+
+                        // uh-oh!
+                        default:
+                            throw new NHibernate.HibernateException("Unhandled member type!");
+                    }
+
+                    // box the value?
+                    if (getter.ReturnType.IsValueType)
+                    {
+                        il.Emit(OpCodes.Box, getter.ReturnType);
+                    }
+                }
+                else
+                {
+                    throw new NHibernate.HibernateException("IGetter implementation does not implement the required Member property!");
+                }
+
+                //store the value
+                il.Emit(OpCodes.Stelem_Ref);
+            }
+
+            // Return the data array
+            il.Emit(OpCodes.Ldloc, dataLocal.LocalIndex);
+            il.Emit(OpCodes.Ret);
+
+            return (GetPropertyValuesInvoker)method.CreateDelegate(typeof(GetPropertyValuesInvoker));
+        }
+
+        /// <summary>
+        /// Generates a dynamic method on the given type.
+        /// </summary>
+        /// <param name="mappedClass"></param>
+        /// <param name="setters"></param>
+        /// <returns></returns>
+        private static SetPropertyValuesInvoker GenerateSetPropertyValuesMethod(System.Type mappedClass, ISetter[] setters)
+        {
+            DynamicMethod method = new DynamicMethod(
+                String.Empty,
+                typeof(void),
+                new System.Type[] { typeof(object), typeof(object[]) },
+                mappedClass,
+                true);
+           
+            ILGenerator il = method.GetILGenerator();
+
+            // Declare a local variable used to store the object reference (typed)
+            LocalBuilder thisLocal = il.DeclareLocal(mappedClass);
+            il.Emit(OpCodes.Ldarg_0);
+            il.Emit(OpCodes.Stloc, thisLocal.LocalIndex);
+
+            for (int i = 0; i < setters.Length; i++)
+            {
+                // get the member accessor
+                ISetter setter = setters[i];
+                if (setter.Member != null)
+                {
+                    // load the this pointer
+                    il.Emit((mappedClass.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc), thisLocal.LocalIndex);
+
+                    // load the value
+                    il.Emit(OpCodes.Ldarg_1);
+                    il.Emit(OpCodes.Ldc_I4, i);
+                    il.Emit(OpCodes.Ldelem_Ref);
+
+                    // cast and optionly unbox the value
+                    il.Emit(OpCodes.Unbox_Any, setter.ValueType);
+
+                    // set the value
+                    switch (setter.Member.MemberType)
+                    {
+                        // fields...
+                        case MemberTypes.Field:
+                            il.Emit(OpCodes.Stfld, (FieldInfo)setter.Member);
+                            break;
+
+                        // properties...
+                        case MemberTypes.Property:
+                            MethodInfo methodInfo = ((PropertyInfo)setter.Member).GetSetMethod(true);
+                            if (methodInfo != null)
+                            {
+                                if (methodInfo.IsVirtual)
+                                {
+                                    il.Emit(OpCodes.Callvirt, methodInfo);
+                                }
+                                else
+                                {
+                                    il.Emit(OpCodes.Call, methodInfo);
+                                }
+                            }
+                            else
+                            {
+                                m_Log.InfoFormat("Property {0} is marked read-only. Ignoring property value.", setter.PropertyName);
+                                il.Emit(OpCodes.Pop);
+                                il.Emit(OpCodes.Pop);
+                            }
+                            break;
+
+                        // uh-oh!
+                        default:
+                            throw new NHibernate.HibernateException("Unhandled member type!");
+                    }
+                }
+                else
+                {
+                    throw new NHibernate.HibernateException("ISetter implementation does not implement the required Member property!");
+                }
+            }
+
+            // Setup the return
+            il.Emit(OpCodes.Ret);
+
+            return (SetPropertyValuesInvoker)method.CreateDelegate(typeof(SetPropertyValuesInvoker));
+        }
+
+        /// <summary>
+        /// Sets the property values.
+        /// </summary>
+        /// <param name="o"></param>
+        /// <param name="values"></param>
+        public void SetPropertyValues(object o, object[] values)
+        {
+            m_Setter(o, values);
+        }
+
+        /// <summary>
+        /// Gets the property values.
+        /// </summary>
+        /// <param name="o"></param>
+        /// <returns></returns>
+        public object[] GetPropertyValues(object o)
+        {
+            return m_Getter(o);
+        }
+
+    }
+}
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/GetSetHelperFactory.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/GetSetHelperFactory.cs   (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/GetSetHelperFactory.cs   (revision 92)
@@ -53,16 +53,23 @@
      /// <param name="setters">Array of setters</param>
      /// <param name="getters">Array of getters</param>
      /// <returns>null if the generation fail</returns>
-      public static IGetSetHelper Create( System.Type mappedClass, ISetter[] setters, IGetter[] getters )
-      {
-         if (mappedClass.IsValueType)
-         {
-            // Cannot create optimizer for value types - the setter method will not work.
-            log.Info( "Disabling reflection optimizer for value type " + mappedClass.FullName );
-            return null;
-         }
-         return new GetSetHelperFactory( mappedClass, setters, getters ).CreateGetSetHelper();
-      }
+        public static IGetSetHelper Create(System.Type mappedClass, ISetter[] setters, IGetter[] getters)
+        {
+            if (!Cfg.Environment.UseLightweightCodeGeneration)
+            {
+                if (mappedClass.IsValueType)
+                {
+                    // Cannot create optimizer for value types - the setter method will not work.
+                    log.Info("Disabling reflection optimizer for value type " + mappedClass.FullName);
+                    return null;
+                }
+                return new GetSetHelperFactory(mappedClass, setters, getters).CreateGetSetHelper();
+            }
+            else
+            {
+                return new LCGGetSetHelper(mappedClass, setters, getters);
+            }
+        }

      private IGetSetHelper CreateGetSetHelper()
      {


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.