Optimize CSharp scripting runtime to use arena allocator per-assembly

This commit is contained in:
Wojtek Figat
2025-05-25 02:04:16 +02:00
parent f9cb4ddae2
commit 410ec0465c
15 changed files with 126 additions and 78 deletions

View File

@@ -78,7 +78,7 @@ namespace ScriptsBuilderImpl
void onScriptsReloadEnd(); void onScriptsReloadEnd();
void onScriptsLoaded(); void onScriptsLoaded();
void GetClassName(const StringAnsi& fullname, StringAnsi& className); void GetClassName(const StringAnsiView fullname, StringAnsi& className);
void onCodeEditorAsyncOpenBegin() void onCodeEditorAsyncOpenBegin()
{ {
@@ -273,7 +273,7 @@ bool ScriptsBuilder::GenerateProject(const StringView& customArgs)
return RunBuildTool(args); return RunBuildTool(args);
} }
void ScriptsBuilderImpl::GetClassName(const StringAnsi& fullname, StringAnsi& className) void ScriptsBuilderImpl::GetClassName(const StringAnsiView fullname, StringAnsi& className)
{ {
const auto lastDotIndex = fullname.FindLast('.'); const auto lastDotIndex = fullname.FindLast('.');
if (lastDotIndex != -1) if (lastDotIndex != -1)

View File

@@ -44,9 +44,19 @@ public:
return ptr; return ptr;
} }
// Invokes destructor on values in an array and clears it.
template<typename Value, typename Allocator>
static void ClearDelete(Array<Value, Allocator>& collection)
{
Value* ptr = collection.Get();
for (int32 i = 0; i < collection.Count(); i++)
Memory::DestructItem(ptr[i]);
collection.Clear();
}
// Invokes destructor on values in a dictionary and clears it. // Invokes destructor on values in a dictionary and clears it.
template<typename Key, typename Value, typename Allocator> template<typename Key, typename Value, typename Allocator>
void ClearDelete(Dictionary<Key, Value, Allocator>& collection) static void ClearDelete(Dictionary<Key, Value, Allocator>& collection)
{ {
for (auto it = collection.Begin(); it.IsNotEnd(); ++it) for (auto it = collection.Begin(); it.IsNotEnd(); ++it)
Memory::DestructItem(it->Value); Memory::DestructItem(it->Value);

View File

@@ -118,7 +118,7 @@ VariantType::VariantType(Types type, const MClass* klass)
#if USE_CSHARP #if USE_CSHARP
if (klass) if (klass)
{ {
const StringAnsi& typeName = klass->GetFullName(); const StringAnsiView typeName = klass->GetFullName();
const int32 length = typeName.Length(); const int32 length = typeName.Length();
TypeName = static_cast<char*>(Allocator::Allocate(length + 1)); TypeName = static_cast<char*>(Allocator::Allocate(length + 1));
Platform::MemoryCopy(TypeName, typeName.Get(), length); Platform::MemoryCopy(TypeName, typeName.Get(), length);

View File

@@ -215,7 +215,7 @@ namespace
{ {
if (!method->IsStatic()) if (!method->IsStatic())
continue; continue;
const StringAnsi& name = method->GetName(); const StringAnsiView name = method->GetName();
if (name.Contains("Internal_") || if (name.Contains("Internal_") ||
mclass->GetFullName().Contains(".Interop.")) mclass->GetFullName().Contains(".Interop."))
continue; continue;

View File

@@ -1029,7 +1029,7 @@ void ManagedBinaryModule::InitType(MClass* mclass)
{ {
#if !COMPILE_WITHOUT_CSHARP #if !COMPILE_WITHOUT_CSHARP
// Skip if already initialized // Skip if already initialized
const StringAnsi& typeName = mclass->GetFullName(); const StringAnsiView typeName = mclass->GetFullName();
if (TypeNameToTypeIndex.ContainsKey(typeName)) if (TypeNameToTypeIndex.ContainsKey(typeName))
return; return;
PROFILE_MEM(Scripting); PROFILE_MEM(Scripting);

View File

@@ -7,6 +7,7 @@
#include "Engine/Core/Types/String.h" #include "Engine/Core/Types/String.h"
#include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/Dictionary.h" #include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Core/Memory/ArenaAllocation.h"
#include "Engine/Platform/CriticalSection.h" #include "Engine/Platform/CriticalSection.h"
/// <summary> /// <summary>
@@ -19,7 +20,7 @@ class FLAXENGINE_API MAssembly
friend Scripting; friend Scripting;
public: public:
typedef Dictionary<StringAnsi, MClass*> ClassesDictionary; typedef Dictionary<StringAnsiView, MClass*> ClassesDictionary;
private: private:
#if USE_MONO #if USE_MONO
@@ -67,6 +68,15 @@ public:
/// </summary> /// </summary>
~MAssembly(); ~MAssembly();
public:
/// <summary>
/// Memory storage with all assembly-related data that shares its lifetime (eg. metadata).
/// </summary>
ArenaAllocator Memory;
// Allocates the given string within a memory that has lifetime of assembly.
StringAnsiView AllocString(const char* str);
public: public:
/// <summary> /// <summary>
/// Managed assembly actions delegate type. /// Managed assembly actions delegate type.

View File

@@ -17,14 +17,13 @@ private:
mutable void* _attrInfo = nullptr; mutable void* _attrInfo = nullptr;
#elif USE_NETCORE #elif USE_NETCORE
void* _handle; void* _handle;
StringAnsi _name; StringAnsiView _name;
StringAnsi _namespace; StringAnsiView _namespace;
StringAnsiView _fullname;
uint32 _types = 0; uint32 _types = 0;
mutable uint32 _size = 0; mutable uint32 _size = 0;
#endif #endif
const MAssembly* _assembly; MAssembly* _assembly;
StringAnsi _fullname;
mutable Array<MMethod*> _methods; mutable Array<MMethod*> _methods;
mutable Array<MField*> _fields; mutable Array<MField*> _fields;
@@ -47,12 +46,13 @@ private:
int32 _isInterface : 1; int32 _isInterface : 1;
int32 _isValueType : 1; int32 _isValueType : 1;
int32 _isEnum : 1; int32 _isEnum : 1;
int32 _isGeneric : 1;
public: public:
#if USE_MONO #if USE_MONO
MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const StringAnsi& fullname); MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const StringAnsi& fullname);
#elif USE_NETCORE #elif USE_NETCORE
MClass(const MAssembly* parentAssembly, void* handle, const char* name, const char* fullname, const char* namespace_, MTypeAttributes typeAttributes); MClass(MAssembly* parentAssembly, void* handle, const char* name, const char* fullname, const char* namespace_, MTypeAttributes typeAttributes);
#endif #endif
/// <summary> /// <summary>
@@ -64,7 +64,7 @@ public:
/// <summary> /// <summary>
/// Gets the parent assembly. /// Gets the parent assembly.
/// </summary> /// </summary>
const MAssembly* GetAssembly() const FORCE_INLINE MAssembly* GetAssembly() const
{ {
return _assembly; return _assembly;
} }
@@ -72,7 +72,7 @@ public:
/// <summary> /// <summary>
/// Gets the full name of the class (namespace and typename). /// Gets the full name of the class (namespace and typename).
/// </summary> /// </summary>
FORCE_INLINE const StringAnsi& GetFullName() const FORCE_INLINE StringAnsiView GetFullName() const
{ {
return _fullname; return _fullname;
} }
@@ -80,12 +80,18 @@ public:
/// <summary> /// <summary>
/// Gets the name of the class. /// Gets the name of the class.
/// </summary> /// </summary>
StringAnsiView GetName() const; FORCE_INLINE StringAnsiView GetName() const
{
return _name;
}
/// <summary> /// <summary>
/// Gets the namespace of the class. /// Gets the namespace of the class.
/// </summary> /// </summary>
StringAnsiView GetNamespace() const; FORCE_INLINE StringAnsiView GetNamespace() const
{
return _name;
}
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
@@ -161,9 +167,9 @@ public:
/// <summary> /// <summary>
/// Gets if class is generic /// Gets if class is generic
/// </summary> /// </summary>
bool IsGeneric() const FORCE_INLINE bool IsGeneric() const
{ {
return _fullname.FindLast('`') != -1; return _isGeneric != 0;
} }
/// <summary> /// <summary>

View File

@@ -71,6 +71,17 @@ MAssembly::~MAssembly()
Unload(); Unload();
} }
StringAnsiView MAssembly::AllocString(const char* str)
{
if (!str)
return StringAnsiView::Empty;
int32 len = StringUtils::Length(str);
char* mem = (char*)Memory.Allocate(len + 1);
Platform::MemoryCopy(mem, str, len);
mem[len] = 0;
return StringAnsiView(mem, len);
}
String MAssembly::ToString() const String MAssembly::ToString() const
{ {
return _name.ToString(); return _name.ToString();
@@ -127,7 +138,11 @@ void MAssembly::Unload(bool isReloading)
_isLoading = false; _isLoading = false;
_isLoaded = false; _isLoaded = false;
_hasCachedClasses = false; _hasCachedClasses = false;
#if USE_NETCORE
ArenaAllocator::ClearDelete(_classes);
#else
_classes.ClearDelete(); _classes.ClearDelete();
#endif
Unloaded(this); Unloaded(this);
} }

View File

@@ -15,16 +15,16 @@ class FLAXENGINE_API MEvent
protected: protected:
#if USE_MONO #if USE_MONO
MonoEvent* _monoEvent; MonoEvent* _monoEvent;
StringAnsi _name;
#elif USE_NETCORE #elif USE_NETCORE
void* _handle; void* _handle;
StringAnsiView _name;
#endif #endif
mutable MMethod* _addMethod; mutable MMethod* _addMethod;
mutable MMethod* _removeMethod; mutable MMethod* _removeMethod;
MClass* _parentClass; MClass* _parentClass;
StringAnsi _name;
mutable int32 _hasCachedAttributes : 1; mutable int32 _hasCachedAttributes : 1;
mutable int32 _hasAddMonoMethod : 1; mutable int32 _hasAddMonoMethod : 1;
mutable int32 _hasRemoveMonoMethod : 1; mutable int32 _hasRemoveMonoMethod : 1;
@@ -42,7 +42,7 @@ public:
/// <summary> /// <summary>
/// Gets the event name. /// Gets the event name.
/// </summary> /// </summary>
FORCE_INLINE const StringAnsi& GetName() const FORCE_INLINE StringAnsiView GetName() const
{ {
return _name; return _name;
} }

View File

@@ -17,14 +17,15 @@ protected:
#if USE_MONO #if USE_MONO
MonoClassField* _monoField; MonoClassField* _monoField;
MonoType* _monoType; MonoType* _monoType;
StringAnsi _name;
#elif USE_NETCORE #elif USE_NETCORE
void* _handle; void* _handle;
void* _type; void* _type;
int32 _fieldOffset; int32 _fieldOffset;
StringAnsiView _name;
#endif #endif
MClass* _parentClass; MClass* _parentClass;
StringAnsi _name;
MVisibility _visibility; MVisibility _visibility;
@@ -44,7 +45,7 @@ public:
/// <summary> /// <summary>
/// Gets field name. /// Gets field name.
/// </summary> /// </summary>
FORCE_INLINE const StringAnsi& GetName() const FORCE_INLINE StringAnsiView GetName() const
{ {
return _name; return _name;
} }

View File

@@ -21,15 +21,16 @@ class FLAXENGINE_API MMethod
protected: protected:
#if USE_MONO #if USE_MONO
MonoMethod* _monoMethod; MonoMethod* _monoMethod;
StringAnsi _name;
#elif USE_NETCORE #elif USE_NETCORE
void* _handle; void* _handle;
StringAnsiView _name;
int32 _paramsCount; int32 _paramsCount;
mutable void* _returnType; mutable void* _returnType;
mutable Array<void*, InlinedAllocation<8>> _parameterTypes; mutable Array<void*, InlinedAllocation<8>> _parameterTypes;
void CacheSignature() const; void CacheSignature() const;
#endif #endif
MClass* _parentClass; MClass* _parentClass;
StringAnsi _name;
MVisibility _visibility; MVisibility _visibility;
#if !USE_MONO_AOT #if !USE_MONO_AOT
void* _cachedThunk = nullptr; void* _cachedThunk = nullptr;
@@ -48,12 +49,11 @@ public:
explicit MMethod(MonoMethod* monoMethod, MClass* parentClass); explicit MMethod(MonoMethod* monoMethod, MClass* parentClass);
explicit MMethod(MonoMethod* monoMethod, const char* name, MClass* parentClass); explicit MMethod(MonoMethod* monoMethod, const char* name, MClass* parentClass);
#elif USE_NETCORE #elif USE_NETCORE
MMethod(MClass* parentClass, StringAnsi&& name, void* handle, int32 paramsCount, MMethodAttributes attributes); MMethod(MClass* parentClass, StringAnsiView name, void* handle, int32 paramsCount, MMethodAttributes attributes);
#endif #endif
public: public:
#if COMPILE_WITH_PROFILER #if COMPILE_WITH_PROFILER
StringAnsi ProfilerName;
SourceLocationData ProfilerData; SourceLocationData ProfilerData;
#endif #endif
@@ -109,7 +109,7 @@ public:
/// <summary> /// <summary>
/// Gets the method name. /// Gets the method name.
/// </summary> /// </summary>
FORCE_INLINE const StringAnsi& GetName() const FORCE_INLINE StringAnsiView GetName() const
{ {
return _name; return _name;
} }

View File

@@ -17,16 +17,16 @@ class FLAXENGINE_API MProperty
protected: protected:
#if USE_MONO #if USE_MONO
MonoProperty* _monoProperty; MonoProperty* _monoProperty;
StringAnsi _name;
#elif USE_NETCORE #elif USE_NETCORE
void* _handle; void* _handle;
StringAnsiView _name;
#endif #endif
mutable MMethod* _getMethod; mutable MMethod* _getMethod;
mutable MMethod* _setMethod; mutable MMethod* _setMethod;
MClass* _parentClass; MClass* _parentClass;
StringAnsi _name;
mutable int32 _hasCachedAttributes : 1; mutable int32 _hasCachedAttributes : 1;
mutable int32 _hasSetMethod : 1; mutable int32 _hasSetMethod : 1;
mutable int32 _hasGetMethod : 1; mutable int32 _hasGetMethod : 1;
@@ -49,7 +49,7 @@ public:
/// <summary> /// <summary>
/// Gets the property name. /// Gets the property name.
/// </summary> /// </summary>
FORCE_INLINE const StringAnsi& GetName() const FORCE_INLINE StringAnsiView GetName() const
{ {
return _name; return _name;
} }

View File

@@ -150,7 +150,7 @@ ScriptingTypeHandle MUtils::UnboxScriptingTypeHandle(MTypeObject* value)
MClass* klass = GetClass(value); MClass* klass = GetClass(value);
if (!klass) if (!klass)
return ScriptingTypeHandle(); return ScriptingTypeHandle();
const StringAnsi& typeName = klass->GetFullName(); const StringAnsiView typeName = klass->GetFullName();
const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeName); const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeName);
if (!typeHandle) if (!typeHandle)
LOG(Warning, "Unknown scripting type {}", String(typeName)); LOG(Warning, "Unknown scripting type {}", String(typeName));
@@ -821,14 +821,14 @@ MObject* MUtils::BoxVariant(const Variant& value)
} }
} }
const StringAnsi& MUtils::GetClassFullname(MObject* obj) StringAnsiView MUtils::GetClassFullname(MObject* obj)
{ {
if (obj) if (obj)
{ {
MClass* mClass = MCore::Object::GetClass(obj); MClass* mClass = MCore::Object::GetClass(obj);
return mClass->GetFullName(); return mClass->GetFullName();
} }
return StringAnsi::Empty; return StringAnsiView::Empty;
} }
MClass* MUtils::GetClass(MTypeObject* type) MClass* MUtils::GetClass(MTypeObject* type)

View File

@@ -400,7 +400,7 @@ struct MConverter<Array<T>>
namespace MUtils namespace MUtils
{ {
// Outputs the full typename for the type of the specified object. // Outputs the full typename for the type of the specified object.
extern FLAXENGINE_API const StringAnsi& GetClassFullname(MObject* obj); extern FLAXENGINE_API StringAnsiView GetClassFullname(MObject* obj);
// Returns the class of the provided object. // Returns the class of the provided object.
extern FLAXENGINE_API MClass* GetClass(MObject* object); extern FLAXENGINE_API MClass* GetClass(MObject* object);

View File

@@ -183,7 +183,7 @@ Dictionary<void*, MAssembly*> CachedAssemblyHandles;
/// <summary> /// <summary>
/// Returns the function pointer to the managed static method in NativeInterop class. /// Returns the function pointer to the managed static method in NativeInterop class.
/// </summary> /// </summary>
void* GetStaticMethodPointer(const String& methodName); void* GetStaticMethodPointer(StringView methodName);
/// <summary> /// <summary>
/// Calls the managed static method with given parameters. /// Calls the managed static method with given parameters.
@@ -753,12 +753,13 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
static void* GetManagedClassesPtr = GetStaticMethodPointer(TEXT("GetManagedClasses")); static void* GetManagedClassesPtr = GetStaticMethodPointer(TEXT("GetManagedClasses"));
CallStaticMethod<void, void*, NativeClassDefinitions**, int*>(GetManagedClassesPtr, _handle, &managedClasses, &classCount); CallStaticMethod<void, void*, NativeClassDefinitions**, int*>(GetManagedClassesPtr, _handle, &managedClasses, &classCount);
_classes.EnsureCapacity(classCount); _classes.EnsureCapacity(classCount);
MAssembly* assembly = const_cast<MAssembly*>(this);
for (int32 i = 0; i < classCount; i++) for (int32 i = 0; i < classCount; i++)
{ {
NativeClassDefinitions& managedClass = managedClasses[i]; NativeClassDefinitions& managedClass = managedClasses[i];
// Create class object // Create class object
MClass* klass = New<MClass>(this, managedClass.typeHandle, managedClass.name, managedClass.fullname, managedClass.namespace_, managedClass.typeAttributes); MClass* klass = assembly->Memory.New<MClass>(assembly, managedClass.typeHandle, managedClass.name, managedClass.fullname, managedClass.namespace_, managedClass.typeAttributes);
_classes.Add(klass->GetFullName(), klass); _classes.Add(klass->GetFullName(), klass);
managedClass.nativePointer = klass; managedClass.nativePointer = klass;
@@ -811,7 +812,7 @@ DEFINE_INTERNAL_CALL(void) NativeInterop_CreateClass(NativeClassDefinitions* man
CachedAssemblyHandles.Add(assemblyHandle, assembly); CachedAssemblyHandles.Add(assemblyHandle, assembly);
} }
MClass* klass = New<MClass>(assembly, managedClass->typeHandle, managedClass->name, managedClass->fullname, managedClass->namespace_, managedClass->typeAttributes); MClass* klass = assembly->Memory.New<MClass>(assembly, managedClass->typeHandle, managedClass->name, managedClass->fullname, managedClass->namespace_, managedClass->typeAttributes);
if (assembly != nullptr) if (assembly != nullptr)
{ {
auto& classes = const_cast<MAssembly::ClassesDictionary&>(assembly->GetClasses()); auto& classes = const_cast<MAssembly::ClassesDictionary&>(assembly->GetClasses());
@@ -819,7 +820,7 @@ DEFINE_INTERNAL_CALL(void) NativeInterop_CreateClass(NativeClassDefinitions* man
if (classes.TryGet(klass->GetFullName(), oldKlass)) if (classes.TryGet(klass->GetFullName(), oldKlass))
{ {
LOG(Warning, "Class '{0}' was already added to assembly '{1}'", String(klass->GetFullName()), String(assembly->GetName())); LOG(Warning, "Class '{0}' was already added to assembly '{1}'", String(klass->GetFullName()), String(assembly->GetName()));
Delete(klass); Memory::DestructItem(klass);
klass = oldKlass; klass = oldKlass;
} }
else else
@@ -915,12 +916,12 @@ bool MAssembly::UnloadImage(bool isReloading)
return false; return false;
} }
MClass::MClass(const MAssembly* parentAssembly, void* handle, const char* name, const char* fullname, const char* namespace_, MTypeAttributes attributes) MClass::MClass(MAssembly* parentAssembly, void* handle, const char* name, const char* fullname, const char* namespace_, MTypeAttributes attributes)
: _handle(handle) : _handle(handle)
, _name(name) , _name(parentAssembly->AllocString(name))
, _namespace(namespace_) , _namespace(parentAssembly->AllocString(namespace_))
, _fullname(parentAssembly->AllocString(fullname))
, _assembly(parentAssembly) , _assembly(parentAssembly)
, _fullname(fullname)
, _hasCachedProperties(false) , _hasCachedProperties(false)
, _hasCachedFields(false) , _hasCachedFields(false)
, _hasCachedMethods(false) , _hasCachedMethods(false)
@@ -967,6 +968,8 @@ MClass::MClass(const MAssembly* parentAssembly, void* handle, const char* name,
static void* TypeIsEnumPtr = GetStaticMethodPointer(TEXT("TypeIsEnum")); static void* TypeIsEnumPtr = GetStaticMethodPointer(TEXT("TypeIsEnum"));
_isEnum = CallStaticMethod<bool, void*>(TypeIsEnumPtr, handle); _isEnum = CallStaticMethod<bool, void*>(TypeIsEnumPtr, handle);
_isGeneric = _fullname.FindLast('`') != -1;
CachedClassHandles[handle] = this; CachedClassHandles[handle] = this;
} }
@@ -982,24 +985,14 @@ bool MAssembly::ResolveMissingFile(String& assemblyPath) const
MClass::~MClass() MClass::~MClass()
{ {
_methods.ClearDelete(); ArenaAllocator::ClearDelete(_methods);
_fields.ClearDelete(); ArenaAllocator::ClearDelete(_fields);
_properties.ClearDelete(); ArenaAllocator::ClearDelete(_properties);
_events.ClearDelete(); ArenaAllocator::ClearDelete(_events);
CachedClassHandles.Remove(_handle); CachedClassHandles.Remove(_handle);
} }
StringAnsiView MClass::GetName() const
{
return _name;
}
StringAnsiView MClass::GetNamespace() const
{
return _namespace;
}
MType* MClass::GetType() const MType* MClass::GetType() const
{ {
return (MType*)_handle; return (MType*)_handle;
@@ -1071,10 +1064,11 @@ const Array<MMethod*>& MClass::GetMethods() const
static void* GetClassMethodsPtr = GetStaticMethodPointer(TEXT("GetClassMethods")); static void* GetClassMethodsPtr = GetStaticMethodPointer(TEXT("GetClassMethods"));
CallStaticMethod<void, void*, NativeMethodDefinitions**, int*>(GetClassMethodsPtr, _handle, &methods, &methodsCount); CallStaticMethod<void, void*, NativeMethodDefinitions**, int*>(GetClassMethodsPtr, _handle, &methods, &methodsCount);
_methods.Resize(methodsCount); _methods.Resize(methodsCount);
MAssembly* assembly = const_cast<MAssembly*>(_assembly);
for (int32 i = 0; i < methodsCount; i++) for (int32 i = 0; i < methodsCount; i++)
{ {
NativeMethodDefinitions& definition = methods[i]; NativeMethodDefinitions& definition = methods[i];
MMethod* method = New<MMethod>(const_cast<MClass*>(this), StringAnsi(definition.name), definition.handle, definition.numParameters, definition.methodAttributes); MMethod* method = assembly->Memory.New<MMethod>(const_cast<MClass*>(this), assembly->AllocString(definition.name), definition.handle, definition.numParameters, definition.methodAttributes);
_methods[i] = method; _methods[i] = method;
MCore::GC::FreeMemory((void*)definition.name); MCore::GC::FreeMemory((void*)definition.name);
} }
@@ -1112,7 +1106,7 @@ const Array<MField*>& MClass::GetFields() const
for (int32 i = 0; i < numFields; i++) for (int32 i = 0; i < numFields; i++)
{ {
NativeFieldDefinitions& definition = fields[i]; NativeFieldDefinitions& definition = fields[i];
MField* field = New<MField>(const_cast<MClass*>(this), definition.fieldHandle, definition.name, definition.fieldType, definition.fieldOffset, definition.fieldAttributes); MField* field = _assembly->Memory.New<MField>(const_cast<MClass*>(this), definition.fieldHandle, definition.name, definition.fieldType, definition.fieldOffset, definition.fieldAttributes);
_fields[i] = field; _fields[i] = field;
MCore::GC::FreeMemory((void*)definition.name); MCore::GC::FreeMemory((void*)definition.name);
} }
@@ -1162,7 +1156,7 @@ const Array<MProperty*>& MClass::GetProperties() const
for (int i = 0; i < numProperties; i++) for (int i = 0; i < numProperties; i++)
{ {
const NativePropertyDefinitions& definition = foundProperties[i]; const NativePropertyDefinitions& definition = foundProperties[i];
MProperty* property = New<MProperty>(const_cast<MClass*>(this), definition.name, definition.propertyHandle, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes); MProperty* property = _assembly->Memory.New<MProperty>(const_cast<MClass*>(this), definition.name, definition.propertyHandle, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes);
_properties[i] = property; _properties[i] = property;
MCore::GC::FreeMemory((void*)definition.name); MCore::GC::FreeMemory((void*)definition.name);
} }
@@ -1241,7 +1235,7 @@ MEvent::MEvent(MClass* parentClass, void* handle, const char* name)
, _addMethod(nullptr) , _addMethod(nullptr)
, _removeMethod(nullptr) , _removeMethod(nullptr)
, _parentClass(parentClass) , _parentClass(parentClass)
, _name(name) , _name(parentClass->GetAssembly()->AllocString(name))
, _hasCachedAttributes(false) , _hasCachedAttributes(false)
, _hasAddMonoMethod(true) , _hasAddMonoMethod(true)
, _hasRemoveMonoMethod(true) , _hasRemoveMonoMethod(true)
@@ -1317,7 +1311,7 @@ MField::MField(MClass* parentClass, void* handle, const char* name, void* type,
, _type(type) , _type(type)
, _fieldOffset(fieldOffset) , _fieldOffset(fieldOffset)
, _parentClass(parentClass) , _parentClass(parentClass)
, _name(name) , _name(parentClass->GetAssembly()->AllocString(name))
, _hasCachedAttributes(false) , _hasCachedAttributes(false)
{ {
switch (attributes & MFieldAttributes::FieldAccessMask) switch (attributes & MFieldAttributes::FieldAccessMask)
@@ -1409,11 +1403,11 @@ const Array<MObject*>& MField::GetAttributes() const
return _attributes; return _attributes;
} }
MMethod::MMethod(MClass* parentClass, StringAnsi&& name, void* handle, int32 paramsCount, MMethodAttributes attributes) MMethod::MMethod(MClass* parentClass, StringAnsiView name, void* handle, int32 paramsCount, MMethodAttributes attributes)
: _handle(handle) : _handle(handle)
, _paramsCount(paramsCount) , _paramsCount(paramsCount)
, _parentClass(parentClass) , _parentClass(parentClass)
, _name(MoveTemp(name)) , _name(name)
, _hasCachedAttributes(false) , _hasCachedAttributes(false)
, _hasCachedSignature(false) , _hasCachedSignature(false)
{ {
@@ -1443,13 +1437,15 @@ MMethod::MMethod(MClass* parentClass, StringAnsi&& name, void* handle, int32 par
_isStatic = (attributes & MMethodAttributes::Static) == MMethodAttributes::Static; _isStatic = (attributes & MMethodAttributes::Static) == MMethodAttributes::Static;
#if COMPILE_WITH_PROFILER #if COMPILE_WITH_PROFILER
const StringAnsi& className = parentClass->GetFullName(); // Setup Tracy profiler entry (use assembly memory)
ProfilerName.Resize(className.Length() + 2 + _name.Length()); const StringAnsiView className = parentClass->GetFullName();
Platform::MemoryCopy(ProfilerName.Get(), className.Get(), className.Length()); char* profilerName = (char*)parentClass->GetAssembly()->Memory.Allocate(className.Length() + _name.Length() + 3);
ProfilerName.Get()[className.Length()] = ':'; Platform::MemoryCopy(profilerName, className.Get(), className.Length());
ProfilerName.Get()[className.Length() + 1] = ':'; profilerName[className.Length()] = ':';
Platform::MemoryCopy(ProfilerName.Get() + className.Length() + 2, _name.Get(), _name.Length()); profilerName[className.Length() + 1] = ':';
ProfilerData.name = ProfilerName.Get(); Platform::MemoryCopy(profilerName + className.Length() + 2, _name.Get(), _name.Length());
profilerName[className.Length() + 2 + _name.Length()] = 0;
ProfilerData.name = profilerName;
ProfilerData.function = _name.Get(); ProfilerData.function = _name.Get();
ProfilerData.file = nullptr; ProfilerData.file = nullptr;
ProfilerData.line = 0; ProfilerData.line = 0;
@@ -1573,20 +1569,30 @@ const Array<MObject*>& MMethod::GetAttributes() const
return _attributes; return _attributes;
} }
FORCE_INLINE StringAnsiView GetPropertyMethodName(MProperty* property, StringAnsiView prefix)
{
StringAnsiView name = property->GetName();
char* mem = (char*)property->GetParentClass()->GetAssembly()->Memory.Allocate(name.Length() + prefix.Length() + 1);
Platform::MemoryCopy(mem, prefix.Get(), prefix.Length());
Platform::MemoryCopy(mem + prefix.Length(), name.Get(), name.Length());
mem[name.Length() + prefix.Length()] = 0;
return StringAnsiView(mem, name.Length() + prefix.Length() + 1);
}
MProperty::MProperty(MClass* parentClass, const char* name, void* handle, 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) : _parentClass(parentClass)
, _name(name) , _name(parentClass->GetAssembly()->AllocString(name))
, _handle(handle) , _handle(handle)
, _hasCachedAttributes(false) , _hasCachedAttributes(false)
{ {
_hasGetMethod = getterHandle != nullptr; _hasGetMethod = getterHandle != nullptr;
if (_hasGetMethod) if (_hasGetMethod)
_getMethod = New<MMethod>(parentClass, StringAnsi("get_" + _name), getterHandle, 0, getterAttributes); _getMethod = parentClass->GetAssembly()->Memory.New<MMethod>(parentClass, GetPropertyMethodName(this, StringAnsiView("get_", 4)), getterHandle, 0, getterAttributes);
else else
_getMethod = nullptr; _getMethod = nullptr;
_hasSetMethod = setterHandle != nullptr; _hasSetMethod = setterHandle != nullptr;
if (_hasSetMethod) if (_hasSetMethod)
_setMethod = New<MMethod>(parentClass, StringAnsi("set_" + _name), setterHandle, 1, setterAttributes); _setMethod = parentClass->GetAssembly()->Memory.New<MMethod>(parentClass, GetPropertyMethodName(this, StringAnsiView("set_", 4)), setterHandle, 1, setterAttributes);
else else
_setMethod = nullptr; _setMethod = nullptr;
} }
@@ -1594,9 +1600,9 @@ MProperty::MProperty(MClass* parentClass, const char* name, void* handle, void*
MProperty::~MProperty() MProperty::~MProperty()
{ {
if (_getMethod) if (_getMethod)
Delete(_getMethod); Memory::DestructItem(_getMethod);
if (_setMethod) if (_setMethod)
Delete(_setMethod); Memory::DestructItem(_setMethod);
} }
MMethod* MProperty::GetGetMethod() const MMethod* MProperty::GetGetMethod() const
@@ -1683,7 +1689,7 @@ MClass* GetOrCreateClass(MType* typeHandle)
static void* GetManagedClassFromTypePtr = GetStaticMethodPointer(TEXT("GetManagedClassFromType")); static void* GetManagedClassFromTypePtr = GetStaticMethodPointer(TEXT("GetManagedClassFromType"));
CallStaticMethod<void, void*, void*>(GetManagedClassFromTypePtr, typeHandle, &classInfo, &assemblyHandle); CallStaticMethod<void, void*, void*>(GetManagedClassFromTypePtr, typeHandle, &classInfo, &assemblyHandle);
MAssembly* assembly = GetAssembly(assemblyHandle); MAssembly* assembly = GetAssembly(assemblyHandle);
klass = New<MClass>(assembly, classInfo.typeHandle, classInfo.name, classInfo.fullname, classInfo.namespace_, classInfo.typeAttributes); klass = assembly->Memory.New<MClass>(assembly, classInfo.typeHandle, classInfo.name, classInfo.fullname, classInfo.namespace_, classInfo.typeAttributes);
if (assembly != nullptr) if (assembly != nullptr)
{ {
auto& classes = const_cast<MAssembly::ClassesDictionary&>(assembly->GetClasses()); auto& classes = const_cast<MAssembly::ClassesDictionary&>(assembly->GetClasses());
@@ -1889,7 +1895,7 @@ void ShutdownHostfxr()
{ {
} }
void* GetStaticMethodPointer(const String& methodName) void* GetStaticMethodPointer(StringView methodName)
{ {
void* fun; void* fun;
if (CachedFunctions.TryGet(methodName, fun)) if (CachedFunctions.TryGet(methodName, fun))