|
7 | 7 | using System.Linq.Expressions; |
8 | 8 | using System.Reflection; |
9 | 9 | using System.Reflection.Emit; |
| 10 | +using System.Runtime.CompilerServices; |
10 | 11 | using System.Runtime.InteropServices; |
11 | 12 | using System.Text; |
12 | 13 | using System.Threading.Tasks; |
@@ -60,6 +61,7 @@ private struct PropertyGetReflectionCache { |
60 | 61 | [FormerlySerializedAs("pi")] public PropertyInfo propertyInfo; |
61 | 62 | public Delegate GetProperty; |
62 | 63 | public bool HasGetPropertyFunc; |
| 64 | + public bool IsNativeClass; |
63 | 65 | } |
64 | 66 |
|
65 | 67 | // Hopefully faster dictionary comparison / hash time |
@@ -627,41 +629,37 @@ private static int SetProperty(LuauContext context, IntPtr thread, int instanceI |
627 | 629 |
|
628 | 630 | private static Delegate CreateSetter<T>(PropertyInfo propertyInfo, bool isStatic) { |
629 | 631 | var setMethod = propertyInfo.GetSetMethod(); |
| 632 | + |
630 | 633 | var declaringType = propertyInfo.DeclaringType; |
631 | | - |
632 | 634 | unsafe { |
| 635 | + var setPointer = setMethod |
| 636 | + .MethodHandle |
| 637 | + .GetFunctionPointer(); |
| 638 | + |
| 639 | + if (setPointer == IntPtr.Zero || declaringType.IsValueType) { |
| 640 | + // Just direct reflection for this case (like ParticleEmitter modules -- weird Unity niche) |
| 641 | + return new Action<object, T>((object target, T value) => { propertyInfo.SetValue(target, value); }); |
| 642 | + } |
| 643 | + |
| 644 | + |
633 | 645 | if (!isStatic) { |
634 | | - if (declaringType.IsValueType) { |
635 | | - // Just direct reflection for this case (like ParticleEmitter modules -- weird Unity niche) |
636 | | - return new Action<object, T>((object target, T value) => { |
637 | | - propertyInfo.SetValue(target, value); |
638 | | - }); |
639 | | - } else { |
640 | | - // Original class handling |
641 | | - delegate*<object, T, void> funcPtr = (delegate*<object, T, void>)setMethod |
642 | | - .MethodHandle |
643 | | - .GetFunctionPointer() |
644 | | - .ToPointer(); |
| 646 | + // Original class handling |
| 647 | + delegate*<object, T, void> funcPtr = (delegate*<object, T, void>)setPointer.ToPointer();; |
645 | 648 |
|
646 | | - var setter = new Setter<T>((obj, val) => { funcPtr(obj, val); }); |
647 | | - return setter; |
648 | | - } |
| 649 | + var setter = new Setter<T>((obj, val) => { funcPtr(obj, val); }); |
| 650 | + return setter; |
649 | 651 | } else { |
650 | | - delegate*<T, void> funcPtr = (delegate*<T, void>)setMethod |
651 | | - .MethodHandle |
652 | | - .GetFunctionPointer() |
653 | | - .ToPointer(); |
654 | | - |
| 652 | + delegate*<T, void> funcPtr = (delegate*<T, void>)setPointer.ToPointer();; |
655 | 653 | var setter = new StaticSetter<T>((val) => { funcPtr(val); }); |
656 | 654 | return setter; |
657 | 655 | } |
658 | 656 | } |
659 | 657 | } |
660 | 658 |
|
661 | 659 | private static T GetValue<T>(object instance, PropertyGetReflectionCache cacheData) { |
662 | | - // if (typeof(T) == typeof(object)) { |
| 660 | + if (typeof(T) == typeof(object) || cacheData.IsNativeClass) { |
663 | 661 | return (T) cacheData.propertyInfo.GetMethod.Invoke(instance, null); |
664 | | - // } |
| 662 | + } |
665 | 663 |
|
666 | 664 | if (!cacheData.HasGetPropertyFunc) { |
667 | 665 | var getMethod = cacheData.propertyInfo.GetGetMethod(); |
@@ -689,24 +687,21 @@ private static T GetValue<T>(object instance, PropertyGetReflectionCache cacheDa |
689 | 687 | } |
690 | 688 |
|
691 | 689 | private static void SetValue<T>(object instance, T value, PropertyInfo pi) { |
692 | | - pi.SetValue(instance, value); |
693 | | - return; |
694 | | - |
695 | 690 | var staticSet = instance == null; |
696 | 691 | if (!_propertySetterCache.TryGetValue((staticSet, pi.DeclaringType, pi.Name), out var setter)) { |
697 | 692 | setter = CreateSetter<T>(pi, staticSet); |
698 | 693 | _propertySetterCache[(staticSet, pi.DeclaringType, pi.Name)] = setter; |
699 | 694 | } |
700 | 695 |
|
| 696 | + if (pi.GetSetMethod().MethodHandle.GetFunctionPointer() == IntPtr.Zero || pi.DeclaringType.IsValueType) { |
| 697 | + ((Action<object, T>)setter)(instance, value); |
| 698 | + return; |
| 699 | + } |
| 700 | + |
701 | 701 | if (staticSet) { |
702 | 702 | ((StaticSetter<T>) setter)(value); |
703 | 703 | } else { |
704 | | - if (pi.DeclaringType.IsValueType) { |
705 | | - ((Action<object, T>)setter)(instance, value); |
706 | | - } |
707 | | - else { |
708 | | - ((Setter<T>)setter)(instance, value); |
709 | | - } |
| 704 | + ((Setter<T>)setter)(instance, value); |
710 | 705 | } |
711 | 706 | } |
712 | 707 |
|
@@ -1682,6 +1677,8 @@ private static PropertyGetReflectionCache SetPropertyCacheValue(Type objectType, |
1682 | 1677 | var cacheData = new PropertyGetReflectionCache { |
1683 | 1678 | t = propertyInfo.PropertyType, |
1684 | 1679 | propertyInfo = propertyInfo, |
| 1680 | + IsNativeClass = propertyInfo.DeclaringType.GetCustomAttributes(false) |
| 1681 | + .Any(attr => attr.GetType().Name == "NativeClassAttribute") |
1685 | 1682 | }; |
1686 | 1683 | LuauCore.propertyGetCache[new PropertyCacheKey(objectType, propName)] = cacheData; |
1687 | 1684 | return cacheData; |
|
0 commit comments