Add attributes support for dotnet interop for methods, fields and properties

This commit is contained in:
Wojtek Figat
2024-10-04 15:57:41 +02:00
parent 1414eb9852
commit e860f969be
4 changed files with 107 additions and 57 deletions

View File

@@ -49,6 +49,7 @@ namespace FlaxEngine.Interop
internal struct NativePropertyDefinitions
{
internal IntPtr name;
internal ManagedHandle propertyHandle;
internal ManagedHandle getterHandle;
internal ManagedHandle setterHandle;
internal uint getterAttributes;
@@ -379,6 +380,17 @@ namespace FlaxEngine.Interop
for (int i = 0; i < properties.Length; i++)
{
var property = properties[i];
ManagedHandle propertyHandle = ManagedHandle.Alloc(property);
#if FLAX_EDITOR
if (type.IsCollectible)
propertyHandleCacheCollectible.Add(propertyHandle);
else
#endif
{
propertyHandleCache.Add(propertyHandle);
}
IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf<NativePropertyDefinitions>() * i);
var getterMethod = property.GetGetMethod(true);
@@ -387,6 +399,7 @@ namespace FlaxEngine.Interop
var classProperty = new NativePropertyDefinitions
{
name = NativeAllocStringAnsi(property.Name),
propertyHandle = propertyHandle,
};
if (getterMethod != null)
{
@@ -404,12 +417,8 @@ namespace FlaxEngine.Interop
*classPropertiesCount = properties.Length;
}
[UnmanagedCallersOnly]
internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount)
internal static void GetAttributes(object[] attributeValues, ManagedHandle** classAttributes, int* classAttributesCount)
{
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
object[] attributeValues = type.GetCustomAttributes(false);
ManagedHandle* arr = (ManagedHandle*)NativeAlloc(attributeValues.Length, Unsafe.SizeOf<ManagedHandle>());
for (int i = 0; i < attributeValues.Length; i++)
{
@@ -424,6 +433,38 @@ namespace FlaxEngine.Interop
*classAttributesCount = attributeValues.Length;
}
[UnmanagedCallersOnly]
internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount)
{
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
object[] attributeValues = type.GetCustomAttributes(false);
GetAttributes(attributeValues, classAttributes, classAttributesCount);
}
[UnmanagedCallersOnly]
internal static void GetMethodAttributes(ManagedHandle methodHandle, ManagedHandle** classAttributes, int* classAttributesCount)
{
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
object[] attributeValues = methodHolder.method.GetCustomAttributes(false);
GetAttributes(attributeValues, classAttributes, classAttributesCount);
}
[UnmanagedCallersOnly]
internal static void GetFieldAttributes(ManagedHandle fieldHandle, ManagedHandle** classAttributes, int* classAttributesCount)
{
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
object[] attributeValues = field.field.GetCustomAttributes(false);
GetAttributes(attributeValues, classAttributes, classAttributesCount);
}
[UnmanagedCallersOnly]
internal static void GetPropertyAttributes(ManagedHandle propertyHandle, ManagedHandle** classAttributes, int* classAttributesCount)
{
PropertyInfo property = Unsafe.As<PropertyInfo>(propertyHandle.Target);
object[] attributeValues = property.GetCustomAttributes(false);
GetAttributes(attributeValues, classAttributes, classAttributesCount);
}
[UnmanagedCallersOnly]
internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attributeHandle)
{
@@ -1027,6 +1068,9 @@ namespace FlaxEngine.Interop
foreach (var handle in fieldHandleCacheCollectible)
handle.Free();
fieldHandleCacheCollectible.Clear();
foreach (var handle in propertyHandleCacheCollectible)
handle.Free();
propertyHandleCacheCollectible.Clear();
_typeSizeCache.Clear();

View File

@@ -38,11 +38,13 @@ namespace FlaxEngine.Interop
private static ConcurrentDictionary<IntPtr, Delegate> cachedDelegates = new();
private static Dictionary<Type, (TypeHolder typeHolder, ManagedHandle handle)> managedTypes = new(new TypeComparer());
private static List<ManagedHandle> fieldHandleCache = new();
private static List<ManagedHandle> propertyHandleCache = new();
#if FLAX_EDITOR
private static List<ManagedHandle> methodHandlesCollectible = new();
private static ConcurrentDictionary<IntPtr, Delegate> cachedDelegatesCollectible = new();
private static Dictionary<Type, (TypeHolder typeHolder, ManagedHandle handle)> managedTypesCollectible = new(new TypeComparer());
private static List<ManagedHandle> fieldHandleCacheCollectible = new();
private static List<ManagedHandle> propertyHandleCacheCollectible = new();
#endif
private static Dictionary<object, ManagedHandle> classAttributesCacheCollectible = new();
private static Dictionary<Assembly, ManagedHandle> assemblyHandles = new();

View File

@@ -16,6 +16,8 @@ class FLAXENGINE_API MProperty
protected:
#if USE_MONO
MonoProperty* _monoProperty;
#elif USE_NETCORE
void* _handle;
#endif
mutable MMethod* _getMethod;
@@ -34,7 +36,7 @@ public:
#if USE_MONO
explicit MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass);
#elif USE_NETCORE
MProperty(MClass* parentClass, const char* name, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes);
MProperty(MClass* parentClass, const char* name, void* handle, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes);
#endif
/// <summary>

View File

@@ -211,7 +211,25 @@ MClass* GetClass(MType* typeHandle);
MClass* GetOrCreateClass(MType* typeHandle);
MType* GetObjectType(MObject* obj);
void* GetCustomAttribute(const MClass* klass, const MClass* attributeClass);
void* GetCustomAttribute(const Array<MObject*>& attributes, const MClass* attributeClass)
{
for (MObject* attr : attributes)
{
MClass* attrClass = MCore::Object::GetClass(attr);
if (attrClass == attributeClass)
return attr;
}
return nullptr;
}
void GetCustomAttributes(Array<MObject*>& result, void* handle, void* getAttributesFunc)
{
MObject** attributes;
int numAttributes;
CallStaticMethod<void, void*, MObject***, int*>(getAttributesFunc, handle, &attributes, &numAttributes);
result.Set(attributes, numAttributes);
MCore::GC::FreeMemory(attributes);
}
// Structures used to pass information from runtime, must match with the structures in managed side
struct NativeClassDefinitions
@@ -244,6 +262,7 @@ struct NativeFieldDefinitions
struct NativePropertyDefinitions
{
const char* name;
void* propertyHandle;
void* getterHandle;
void* setterHandle;
MMethodAttributes getterAttributes;
@@ -1089,7 +1108,7 @@ const Array<MProperty*>& MClass::GetProperties() const
for (int i = 0; i < numProperties; i++)
{
const NativePropertyDefinitions& definition = foundProperties[i];
MProperty* property = New<MProperty>(const_cast<MClass*>(this), definition.name, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes);
MProperty* property = New<MProperty>(const_cast<MClass*>(this), definition.name, definition.propertyHandle, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes);
_properties[i] = property;
MCore::GC::FreeMemory((void*)definition.name);
}
@@ -1125,7 +1144,7 @@ const Array<MClass*>& MClass::GetInterfaces() const
bool MClass::HasAttribute(const MClass* klass) const
{
return GetCustomAttribute(this, klass) != nullptr;
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
}
bool MClass::HasAttribute() const
@@ -1135,7 +1154,7 @@ bool MClass::HasAttribute() const
MObject* MClass::GetAttribute(const MClass* klass) const
{
return (MObject*)GetCustomAttribute(this, klass);
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
}
const Array<MObject*>& MClass::GetAttributes() const
@@ -1145,14 +1164,8 @@ const Array<MObject*>& MClass::GetAttributes() const
ScopeLock lock(BinaryModule::Locker);
if (_hasCachedAttributes)
return _attributes;
MObject** attributes;
int numAttributes;
static void* GetClassAttributesPtr = GetStaticMethodPointer(TEXT("GetClassAttributes"));
CallStaticMethod<void, void*, MObject***, int*>(GetClassAttributesPtr, _handle, &attributes, &numAttributes);
_attributes.Set(attributes, numAttributes);
MCore::GC::FreeMemory(attributes);
GetCustomAttributes(_attributes, _handle, GetClassAttributesPtr);
_hasCachedAttributes = true;
return _attributes;
}
@@ -1191,17 +1204,17 @@ MMethod* MEvent::GetRemoveMethod() const
bool MEvent::HasAttribute(const MClass* klass) const
{
return false; // TODO: implement MEvent in .NET
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
}
bool MEvent::HasAttribute() const
{
return false; // TODO: implement MEvent in .NET
return !GetAttributes().IsEmpty();
}
MObject* MEvent::GetAttribute(const MClass* klass) const
{
return nullptr; // TODO: implement MEvent in .NET
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
}
const Array<MObject*>& MEvent::GetAttributes() const
@@ -1313,29 +1326,29 @@ void MField::SetValue(MObject* instance, void* value) const
bool MField::HasAttribute(const MClass* klass) const
{
// TODO: implement MField attributes in .NET
return false;
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
}
bool MField::HasAttribute() const
{
// TODO: implement MField attributes in .NET
return false;
return !GetAttributes().IsEmpty();
}
MObject* MField::GetAttribute(const MClass* klass) const
{
// TODO: implement MField attributes in .NET
return nullptr;
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
}
const Array<MObject*>& MField::GetAttributes() const
{
if (_hasCachedAttributes)
return _attributes;
ScopeLock lock(BinaryModule::Locker);
if (_hasCachedAttributes)
return _attributes;
static void* GetFieldAttributesPtr = GetStaticMethodPointer(TEXT("GetFieldAttributes"));
GetCustomAttributes(_attributes, _handle, GetFieldAttributesPtr);
_hasCachedAttributes = true;
// TODO: implement MField attributes in .NET
return _attributes;
}
@@ -1475,35 +1488,36 @@ bool MMethod::GetParameterIsOut(int32 paramIdx) const
bool MMethod::HasAttribute(const MClass* klass) const
{
// TODO: implement MMethod attributes in .NET
return false;
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
}
bool MMethod::HasAttribute() const
{
// TODO: implement MMethod attributes in .NET
return false;
return !GetAttributes().IsEmpty();
}
MObject* MMethod::GetAttribute(const MClass* klass) const
{
// TODO: implement MMethod attributes in .NET
return nullptr;
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
}
const Array<MObject*>& MMethod::GetAttributes() const
{
if (_hasCachedAttributes)
return _attributes;
ScopeLock lock(BinaryModule::Locker);
if (_hasCachedAttributes)
return _attributes;
static void* GetMethodAttributesPtr = GetStaticMethodPointer(TEXT("GetMethodAttributes"));
GetCustomAttributes(_attributes, _handle, GetMethodAttributesPtr);
_hasCachedAttributes = true;
// TODO: implement MMethod attributes in .NET
return _attributes;
}
MProperty::MProperty(MClass* parentClass, const char* name, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes)
MProperty::MProperty(MClass* parentClass, const char* name, void* handle, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes)
: _parentClass(parentClass)
, _name(name)
, _handle(handle)
, _hasCachedAttributes(false)
{
_hasGetMethod = getterHandle != nullptr;
@@ -1552,29 +1566,29 @@ void MProperty::SetValue(MObject* instance, void* value, MObject** exception) co
bool MProperty::HasAttribute(const MClass* klass) const
{
// TODO: implement MProperty attributes in .NET
return false;
return GetCustomAttribute(GetAttributes(), klass) != nullptr;
}
bool MProperty::HasAttribute() const
{
// TODO: implement MProperty attributes in .NET
return false;
return !GetAttributes().IsEmpty();
}
MObject* MProperty::GetAttribute(const MClass* klass) const
{
// TODO: implement MProperty attributes in .NET
return nullptr;
return (MObject*)GetCustomAttribute(GetAttributes(), klass);
}
const Array<MObject*>& MProperty::GetAttributes() const
{
if (_hasCachedAttributes)
return _attributes;
ScopeLock lock(BinaryModule::Locker);
if (_hasCachedAttributes)
return _attributes;
static void* GetPropertyAttributesPtr = GetStaticMethodPointer(TEXT("GetPropertyAttributes"));
GetCustomAttributes(_attributes, _handle, GetPropertyAttributesPtr);
_hasCachedAttributes = true;
// TODO: implement MProperty attributes in .NET
return _attributes;
}
@@ -1637,18 +1651,6 @@ MType* GetObjectType(MObject* obj)
return (MType*)typeHandle;
}
void* GetCustomAttribute(const MClass* klass, const MClass* attributeClass)
{
const Array<MObject*>& attributes = klass->GetAttributes();
for (MObject* attr : attributes)
{
MClass* attrClass = MCore::Object::GetClass(attr);
if (attrClass == attributeClass)
return attr;
}
return nullptr;
}
#if DOTNET_HOST_CORECLR
const char_t* NativeInteropTypeName = FLAX_CORECLR_TEXT("FlaxEngine.Interop.NativeInterop, FlaxEngine.CSharp");