Refactor CoreCLR runtime into explicit dotnet api instead of mocking mono api

Required by platforms that will use mono under the hood for .Net 7
New `USE_CSHARP` define for C# ability
Engine doesn't use `mono_*` apis directly but via MCore/MClass/MMethod/ apis
This commit is contained in:
Wojtek Figat
2023-03-27 17:29:42 +02:00
parent eed2cdfe04
commit 510fc443e8
111 changed files with 17048 additions and 8765 deletions

View File

@@ -2,7 +2,6 @@
#include "BinaryModule.h"
#include "Scripting.h"
#include "StdTypesContainer.h"
#include "ScriptingType.h"
#include "FlaxEngine.Gen.h"
#include "Engine/Threading/Threading.h"
@@ -20,7 +19,8 @@
#include "ManagedCLR/MMethod.h"
#include "ManagedCLR/MDomain.h"
#include "ManagedCLR/MCore.h"
#include "MException.h"
#include "ManagedCLR/MException.h"
#include "Internal/StdTypesContainer.h"
#include "Engine/Core/ObjectsRemovalService.h"
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Profiler/ProfilerCPU.h"
@@ -29,14 +29,8 @@
#include "Engine/Engine/EngineService.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Platform/MemoryStats.h"
#include "Engine/Serialization/JsonTools.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/object.h>
#endif
#if USE_NETCORE
#include "DotNet/CoreCLR.h"
#endif
extern void registerFlaxEngineInternalCalls();
@@ -392,7 +386,7 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
else
{
// Create module if native library is not used
module = New<ManagedBinaryModule>(nameAnsi, MAssemblyOptions());
module = New<ManagedBinaryModule>(nameAnsi);
_nonNativeModules.Add(module);
}
}
@@ -401,18 +395,11 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
// C#
if (managedPath.HasChars() && !((ManagedBinaryModule*)module)->Assembly->IsLoaded())
{
if (((ManagedBinaryModule*)module)->Assembly->Load(managedPath))
if (((ManagedBinaryModule*)module)->Assembly->Load(managedPath, nativePath))
{
LOG(Error, "Failed to load C# assembly '{0}' for binary module {1}.", managedPath, name);
return true;
}
#if USE_NETCORE
// Provide new path of hot-reloaded native library path for managed DllImport
if (nativePath.HasChars())
{
CoreCLR::RegisterNativeLibrary(nameAnsi.Get(), StringAnsi(nativePath).Get());
}
#endif
}
#endif
@@ -429,13 +416,46 @@ bool Scripting::Load()
// Note: this action can be called from main thread (due to Mono problems with assemblies actions from other threads)
ASSERT(IsInMainThread());
#if !COMPILE_WITHOUT_CSHARP
#if USE_CSHARP
// Load C# core assembly
if (GetBinaryModuleCorlib()->Assembly->Load(mono_get_corlib()))
ManagedBinaryModule* corlib = GetBinaryModuleCorlib();
if (corlib->Assembly->LoadCorlib())
{
LOG(Error, "Failed to load corlib C# assembly.");
return true;
}
// Initialize C# corelib types
{
const auto& corlibClasses = corlib->Assembly->GetClasses();
bool gotAll = true;
#define CACHE_CORLIB_CLASS(var, name) gotAll &= corlibClasses.TryGet(StringAnsiView(name), MCore::TypeCache::var)
CACHE_CORLIB_CLASS(Void, "System.Void");
CACHE_CORLIB_CLASS(Object, "System.Object");
CACHE_CORLIB_CLASS(Byte, "System.Byte");
CACHE_CORLIB_CLASS(Boolean, "System.Boolean");
CACHE_CORLIB_CLASS(SByte, "System.SByte");
CACHE_CORLIB_CLASS(Char, "System.Char");
CACHE_CORLIB_CLASS(Int16, "System.Int16");
CACHE_CORLIB_CLASS(UInt16, "System.UInt16");
CACHE_CORLIB_CLASS(Int32, "System.Int32");
CACHE_CORLIB_CLASS(UInt32, "System.UInt32");
CACHE_CORLIB_CLASS(Int64, "System.Int64");
CACHE_CORLIB_CLASS(UInt64, "System.UInt64");
CACHE_CORLIB_CLASS(IntPtr, "System.IntPtr");
CACHE_CORLIB_CLASS(UIntPtr, "System.UIntPtr");
CACHE_CORLIB_CLASS(Single, "System.Single");
CACHE_CORLIB_CLASS(Double, "System.Double");
CACHE_CORLIB_CLASS(String, "System.String");
#undef CACHE_CORLIB_CLASS
if (!gotAll)
{
LOG(Error, "Failed to load corlib C# assembly.");
for (const auto& e : corlibClasses)
LOG(Info, "Class: {0}", String(e.Value->GetFullName()));
return true;
}
}
#endif
// Load FlaxEngine
@@ -671,48 +691,6 @@ MClass* Scripting::FindClass(const StringAnsiView& fullname)
return nullptr;
}
#if USE_MONO
MClass* Scripting::FindClass(MonoClass* monoClass)
{
if (monoClass == nullptr)
return nullptr;
PROFILE_CPU();
auto& modules = BinaryModule::GetModules();
for (auto module : modules)
{
auto managedModule = dynamic_cast<ManagedBinaryModule*>(module);
if (managedModule && managedModule->Assembly->IsLoaded())
{
MClass* result = managedModule->Assembly->GetClass(monoClass);
if (result != nullptr)
return result;
}
}
return nullptr;
}
MonoClass* Scripting::FindClassNative(const StringAnsiView& fullname)
{
if (fullname.IsEmpty())
return nullptr;
PROFILE_CPU();
auto& modules = BinaryModule::GetModules();
for (auto module : modules)
{
auto managedModule = dynamic_cast<ManagedBinaryModule*>(module);
if (managedModule && managedModule->Assembly->IsLoaded())
{
MClass* result = managedModule->Assembly->GetClass(fullname);
if (result != nullptr)
return result->GetNative();
}
}
return nullptr;
}
#endif
ScriptingTypeHandle Scripting::FindScriptingType(const StringAnsiView& fullname)
{
if (fullname.IsEmpty())
@@ -754,21 +732,20 @@ ScriptingObject* Scripting::NewObject(const MClass* type)
LOG(Error, "Invalid type.");
return nullptr;
}
#if USE_MONO
#if USE_CSHARP
// Get the assembly with that class
MonoClass* typeClass = type->GetNative();
auto module = ManagedBinaryModule::FindModule(typeClass);
auto module = ManagedBinaryModule::FindModule(type);
if (module == nullptr)
{
LOG(Error, "Cannot find scripting assembly for type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot find scripting assembly for type \'{0}\'.", String(type->GetFullName()));
return nullptr;
}
// Try to find the scripting type for this class
int32 typeIndex;
if (!module->ClassToTypeIndex.TryGet(typeClass, typeIndex))
if (!module->ClassToTypeIndex.TryGet(type, typeIndex))
{
LOG(Error, "Cannot spawn objects of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot spawn objects of type \'{0}\'.", String(type->GetFullName()));
return nullptr;
}
const ScriptingType& scriptingType = module->Types[typeIndex];