UserDataPropertyDescriptor.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using System.Text;
  7. using System.Threading;
  8. using MoonSharp.Interpreter.Diagnostics;
  9. namespace MoonSharp.Interpreter.Interop
  10. {
  11. internal class UserDataPropertyDescriptor
  12. {
  13. internal PropertyInfo PropertyInfo { get; private set; }
  14. internal InteropAccessMode AccessMode { get; private set; }
  15. internal bool IsStatic { get; private set; }
  16. internal string Name { get; private set; }
  17. Func<object, object> m_OptimizedGetter = null;
  18. Action<object, object> m_OptimizedSetter = null;
  19. internal UserDataPropertyDescriptor(PropertyInfo pi, InteropAccessMode accessMode)
  20. {
  21. this.PropertyInfo = pi;
  22. this.AccessMode = accessMode;
  23. this.Name = pi.Name;
  24. this.IsStatic = (this.PropertyInfo.GetGetMethod() ?? this.PropertyInfo.GetSetMethod()).IsStatic;
  25. if (AccessMode == InteropAccessMode.Preoptimized)
  26. {
  27. this.OptimizeGetter();
  28. this.OptimizeSetter();
  29. }
  30. }
  31. internal object GetValue(object obj)
  32. {
  33. if (AccessMode == InteropAccessMode.LazyOptimized && m_OptimizedGetter == null)
  34. OptimizeGetter();
  35. if (m_OptimizedGetter != null)
  36. return m_OptimizedGetter(obj);
  37. return PropertyInfo.GetValue(IsStatic ? null : obj, null);
  38. }
  39. internal void OptimizeGetter()
  40. {
  41. using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation))
  42. {
  43. if (PropertyInfo.CanRead)
  44. {
  45. if (IsStatic)
  46. {
  47. var paramExp = Expression.Parameter(typeof(object), "dummy");
  48. var propAccess = Expression.Property(null, PropertyInfo);
  49. var castPropAccess = Expression.Convert(propAccess, typeof(object));
  50. var lambda = Expression.Lambda<Func<object, object>>(castPropAccess, paramExp);
  51. Interlocked.Exchange(ref m_OptimizedGetter, lambda.Compile());
  52. }
  53. else
  54. {
  55. var paramExp = Expression.Parameter(typeof(object), "obj");
  56. var castParamExp = Expression.Convert(paramExp, this.PropertyInfo.DeclaringType);
  57. var propAccess = Expression.Property(castParamExp, PropertyInfo);
  58. var castPropAccess = Expression.Convert(propAccess, typeof(object));
  59. var lambda = Expression.Lambda<Func<object, object>>(castPropAccess, paramExp);
  60. Interlocked.Exchange(ref m_OptimizedGetter, lambda.Compile());
  61. }
  62. }
  63. }
  64. }
  65. internal void OptimizeSetter()
  66. {
  67. using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation))
  68. {
  69. if (PropertyInfo.CanWrite)
  70. {
  71. MethodInfo setterMethod = PropertyInfo.GetSetMethod();
  72. if (IsStatic)
  73. {
  74. var paramExp = Expression.Parameter(typeof(object), "dummy");
  75. var paramValExp = Expression.Parameter(typeof(object), "val");
  76. var castParamValExp = Expression.Convert(paramValExp, this.PropertyInfo.PropertyType);
  77. var callExpression = Expression.Call(setterMethod, castParamValExp);
  78. var lambda = Expression.Lambda<Action<object, object>>(callExpression, paramExp, paramValExp);
  79. Interlocked.Exchange(ref m_OptimizedSetter, lambda.Compile());
  80. }
  81. else
  82. {
  83. var paramExp = Expression.Parameter(typeof(object), "obj");
  84. var paramValExp = Expression.Parameter(typeof(object), "val");
  85. var castParamExp = Expression.Convert(paramExp, this.PropertyInfo.DeclaringType);
  86. var castParamValExp = Expression.Convert(paramValExp, this.PropertyInfo.PropertyType);
  87. var callExpression = Expression.Call(castParamExp, setterMethod, castParamValExp);
  88. var lambda = Expression.Lambda<Action<object, object>>(callExpression, paramExp, paramValExp);
  89. Interlocked.Exchange(ref m_OptimizedSetter, lambda.Compile());
  90. }
  91. }
  92. }
  93. }
  94. internal void SetValue(object obj, object value, DataType originalType)
  95. {
  96. try
  97. {
  98. if (value is double)
  99. value = ConversionHelper.DoubleToType(PropertyInfo.PropertyType, (double)value);
  100. if (AccessMode == InteropAccessMode.LazyOptimized && m_OptimizedSetter == null)
  101. OptimizeSetter();
  102. if (m_OptimizedSetter != null)
  103. {
  104. m_OptimizedSetter(obj, value);
  105. }
  106. else
  107. {
  108. PropertyInfo.SetValue(IsStatic ? null : obj, value, null);
  109. }
  110. }
  111. catch (ArgumentException)
  112. {
  113. // non-optimized setters fall here
  114. throw ScriptRuntimeException.UserDataArgumentTypeMismatch(originalType, PropertyInfo.PropertyType);
  115. }
  116. catch (InvalidCastException)
  117. {
  118. // optimized setters fall here
  119. throw ScriptRuntimeException.UserDataArgumentTypeMismatch(originalType, PropertyInfo.PropertyType);
  120. }
  121. }
  122. }
  123. }