Progress on dotnet7 runtime hosting with mono

This commit is contained in:
Wojtek Figat
2023-03-22 17:59:46 +01:00
parent 4c4a559125
commit eed2cdfe04
44 changed files with 462 additions and 111 deletions

View File

@@ -15,7 +15,12 @@
#include <coreclr_delegates.h>
#include <hostfxr.h>
#elif DOTNET_HOST_MONO
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include "Engine/Debug/Exceptions/CLRInnerException.h"
#include <mono/jit/jit.h>
#include <mono/jit/mono-private-unstable.h>
#include <mono/utils/mono-logger.h>
typedef char char_t;
#else
#error "Unknown .NET runtime host."
@@ -30,6 +35,7 @@ static Dictionary<String, void*> CachedFunctions;
static const char_t* NativeInteropTypeName = FLAX_CORECLR_TEXT("FlaxEngine.NativeInterop, FlaxEngine.CSharp");
#if DOTNET_HOST_CORECRL
hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config;
hostfxr_initialize_for_dotnet_command_line_fn hostfxr_initialize_for_dotnet_command_line;
hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate;
@@ -39,11 +45,9 @@ get_function_pointer_fn get_function_pointer;
hostfxr_set_error_writer_fn hostfxr_set_error_writer;
hostfxr_get_dotnet_environment_info_result_fn hostfxr_get_dotnet_environment_info_result;
hostfxr_run_app_fn hostfxr_run_app;
#endif
bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath)
{
#if DOTNET_HOST_CORECRL
const FLAX_CORECLR_STRING& library_path = FLAX_CORECLR_STRING(libraryPath);
// Get path to hostfxr library
@@ -138,31 +142,227 @@ bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath)
hostfxr_close(handle);
get_function_pointer = (get_function_pointer_fn)pget_function_pointer;
#elif DOTNET_HOST_MONO
LOG(Fatal, "TODO: init mono hosting runtime");
#endif
return false;
}
void CoreCLR::ShutdownHostfxr()
{
}
void* CoreCLR::GetStaticMethodPointer(const String& methodName)
{
void* fun;
if (CachedFunctions.TryGet(methodName, fun))
return fun;
#if DOTNET_HOST_CORECRL
int rc = get_function_pointer(NativeInteropTypeName, FLAX_CORECLR_STRING(methodName).Get(), UNMANAGEDCALLERSONLY_METHOD, nullptr, nullptr, &fun);
if (rc != 0)
#else
int rc = -1;
#endif
LOG(Fatal, "Failed to get unmanaged function pointer for method {0}: 0x{1:x}", methodName.Get(), (unsigned int)rc);
CachedFunctions.Add(methodName, fun);
return fun;
}
#elif DOTNET_HOST_MONO
#ifdef USE_MONO_AOT_MODULE
void* MonoAotModuleHandle = nullptr;
#endif
MonoDomain* MonoDomainHandle = nullptr;
void OnLogCallback(const char* logDomain, const char* logLevel, const char* message, mono_bool fatal, void* userData)
{
String currentDomain(logDomain);
String msg(message);
msg.Replace('\n', ' ');
static const char* monoErrorLevels[] =
{
nullptr,
"error",
"critical",
"warning",
"message",
"info",
"debug"
};
uint32 errorLevel = 0;
if (logLevel != nullptr)
{
for (uint32 i = 1; i < 7; i++)
{
if (strcmp(monoErrorLevels[i], logLevel) == 0)
{
errorLevel = i;
break;
}
}
}
if (currentDomain.IsEmpty())
{
auto domain = MCore::GetActiveDomain();
if (domain != nullptr)
{
currentDomain = domain->GetName().Get();
}
else
{
currentDomain = "null";
}
}
#if 0
// Print C# stack trace (crash may be caused by the managed code)
if (mono_domain_get() && Assemblies::FlaxEngine.Assembly->IsLoaded())
{
const auto managedStackTrace = DebugLog::GetStackTrace();
if (managedStackTrace.HasChars())
{
LOG(Warning, "Managed stack trace:");
LOG_STR(Warning, managedStackTrace);
}
}
#endif
if (errorLevel == 0)
{
Log::CLRInnerException(String::Format(TEXT("Message: {0} | Domain: {1}"), msg, currentDomain)).SetLevel(LogType::Error);
}
else if (errorLevel <= 2)
{
Log::CLRInnerException(String::Format(TEXT("Message: {0} | Domain: {1}"), msg, currentDomain)).SetLevel(LogType::Error);
}
else if (errorLevel <= 3)
{
LOG(Warning, "Message: {0} | Domain: {1}", msg, currentDomain);
}
else
{
LOG(Info, "Message: {0} | Domain: {1}", msg, currentDomain);
}
}
void OnPrintCallback(const char* string, mono_bool isStdout)
{
LOG_STR(Warning, String(string));
}
void OnPrintErrorCallback(const char* string, mono_bool isStdout)
{
// HACK: ignore this message
if (string && Platform::MemoryCompare(string, "debugger-agent: Unable to listen on ", 36) == 0)
return;
LOG_STR(Error, String(string));
}
bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath)
{
#if 1
// Enable detailed Mono logging
Platform::SetEnvironmentVariable(TEXT("MONO_LOG_LEVEL"), TEXT("debug"));
Platform::SetEnvironmentVariable(TEXT("MONO_LOG_MASK"), TEXT("all"));
//Platform::SetEnvironmentVariable(TEXT("MONO_GC_DEBUG"), TEXT("6:gc-log.txt,check-remset-consistency,nursery-canaries"));
#endif
#if defined(USE_MONO_AOT_MODE)
// Enable AOT mode (per-platform)
mono_jit_set_aot_mode(USE_MONO_AOT_MODE);
#endif
#ifdef USE_MONO_AOT_MODULE
// Load AOT module
const DateTime aotModuleLoadStartTime = DateTime::Now();
LOG(Info, "Loading Mono AOT module...");
void* libAotModule = Platform::LoadLibrary(TEXT(USE_MONO_AOT_MODULE));
if (libAotModule == nullptr)
{
LOG(Error, "Failed to laod Mono AOT module (" TEXT(USE_MONO_AOT_MODULE) ")");
return true;
}
MonoAotModuleHandle = libAotModule;
void* getModulesPtr = Platform::GetProcAddress(libAotModule, "GetMonoModules");
if (getModulesPtr == nullptr)
{
LOG(Error, "Failed to get Mono AOT modules getter.");
return true;
}
typedef int (*GetMonoModulesFunc)(void** buffer, int bufferSize);
const auto getModules = (GetMonoModulesFunc)getModulesPtr;
const int32 moduelsCount = getModules(nullptr, 0);
void** modules = (void**)Allocator::Allocate(moduelsCount * sizeof(void*));
getModules(modules, moduelsCount);
for (int32 i = 0; i < moduelsCount; i++)
{
mono_aot_register_module((void**)modules[i]);
}
Allocator::Free(modules);
LOG(Info, "Mono AOT module loaded in {0}ms", (int32)(DateTime::Now() - aotModuleLoadStartTime).GetTotalMilliseconds());
#endif
// TODO: setup C# debugger
// Connect to mono engine callback system
mono_trace_set_log_handler(OnLogCallback, nullptr);
mono_trace_set_print_handler(OnPrintCallback);
mono_trace_set_printerr_handler(OnPrintErrorCallback);
// Initialize Mono VM
StringAnsi baseDirectory(Globals::ProjectFolder);
const char* appctxKeys[] =
{
"RUNTIME_IDENTIFIER",
"APP_CONTEXT_BASE_DIRECTORY",
};
const char* appctxValues[] =
{
MACRO_TO_STR(DOTNET_HOST_RUNTIME_IDENTIFIER),
baseDirectory.Get(),
};
static_assert(ARRAY_COUNT(appctxKeys) == ARRAY_COUNT(appctxValues), "Invalid appctx setup");
monovm_initialize(ARRAY_COUNT(appctxKeys), appctxKeys, appctxValues);
// Init managed runtime
#if PLATFORM_ANDROID || PLATFORM_IOS
const char* monoVersion = "mobile";
#else
const char* monoVersion = ""; // ignored
#endif
MonoDomainHandle = mono_jit_init_version("Flax", monoVersion);
if (!MonoDomainHandle)
{
LOG(Fatal, "Failed to initialize Mono.");
return true;
}
// Log info
char* buildInfo = mono_get_runtime_build_info();
LOG(Info, "Mono runtime version: {0}", String(buildInfo));
mono_free(buildInfo);
return false;
}
void CoreCLR::ShutdownHostfxr()
{
mono_jit_cleanup(MonoDomainHandle);
MonoDomainHandle = nullptr;
#ifdef USE_MONO_AOT_MODULE
Platform::FreeLibrary(MonoAotModuleHandle);
#endif
}
void* CoreCLR::GetStaticMethodPointer(const String& methodName)
{
MISSING_CODE("TODO: CoreCLR::GetStaticMethodPointer for Mono host runtime");
return nullptr;
}
#endif
void CoreCLR::RegisterNativeLibrary(const char* moduleName, const char* modulePath)
{
static void* RegisterNativeLibraryPtr = CoreCLR::GetStaticMethodPointer(TEXT("RegisterNativeLibrary"));

View File

@@ -25,6 +25,7 @@ class CoreCLR
{
public:
static bool InitHostfxr(const String& configPath, const String& libraryPath);
static void ShutdownHostfxr();
/// <summary>
/// Returns the function pointer to the managed static method in NativeInterop class.

View File

@@ -6,8 +6,8 @@
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Core/Types/StringBuilder.h"
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#include <mono/metadata/object.h>
#include <mono/metadata/appdomain.h>
#pragma warning(disable : 4297)

View File

@@ -9,9 +9,9 @@
#include "Engine/Scripting/ManagedCLR/MField.h"
#include "Engine/Scripting/BinaryModule.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/debug-helpers.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/object.h>
struct ManagedBitArray
{

View File

@@ -12,7 +12,7 @@
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/MException.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#include <mono/metadata/appdomain.h>
/// <summary>
/// Utility interop between C++ and C# for Dictionary collection.

View File

@@ -3,7 +3,7 @@
#include "MException.h"
#include "ManagedCLR/MUtils.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <mono/metadata/object.h>
#endif
MException::MException(MObject* exception)

View File

@@ -17,9 +17,9 @@
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Threading/Threading.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/assembly.h>
#include <ThirdParty/mono-2.0/mono/metadata/tokentype.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/tokentype.h>
#endif
MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const MAssemblyOptions& options)

View File

@@ -10,8 +10,8 @@
#include "Engine/Scripting/Scripting.h"
#include "Engine/Core/Log.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/attrdefs.h>
#define GET_CUSTOM_ATTR() (MonoCustomAttrInfo*)(_attrInfo ? _attrInfo : _attrInfo = mono_custom_attrs_from_class(_monoClass))
#endif
#if USE_NETCORE

View File

@@ -20,19 +20,19 @@
#ifdef USE_MONO_AOT_MODULE
#include "Engine/Core/Types/TimeSpan.h"
#endif
#include <ThirdParty/mono-2.0/mono/jit/jit.h>
#include <ThirdParty/mono-2.0/mono/utils/mono-counters.h>
#include <ThirdParty/mono-2.0/mono/utils/mono-logger.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <ThirdParty/mono-2.0/mono/metadata/assembly.h>
#include <ThirdParty/mono-2.0/mono/metadata/threads.h>
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/mono-config.h>
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
#include <ThirdParty/mono-2.0/mono/metadata/profiler.h>
#include <mono/jit/jit.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-logger.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/object.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/profiler.h>
#if !USE_MONO_DYNAMIC_LIB
#include <ThirdParty/mono-2.0/mono/utils/mono-dl-fallback.h>
#include <mono/utils/mono-dl-fallback.h>
#endif
#endif
@@ -159,6 +159,7 @@ void MCore::UnloadEngine()
CoreCLR::CallStaticMethodByName<void>(TEXT("Exit"));
MDomains.ClearDelete();
MRootDomain = nullptr;
CoreCLR::ShutdownHostfxr();
}
#elif USE_MONO

View File

@@ -8,7 +8,7 @@
#include "Engine/Debug/Exceptions/ArgumentException.h"
#include "Engine/Debug/Exceptions/Exceptions.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/threads.h>
#include <mono/metadata/threads.h>
#endif
extern MDomain* MActiveDomain;

View File

@@ -4,7 +4,7 @@
#include "MType.h"
#include "MClass.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug.h>
MEvent::MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass)
: _monoEvent(monoEvent)
@@ -137,7 +137,7 @@ const Array<MObject*>& MEvent::GetAttributes()
const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length);
for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
mono_custom_attrs_free(attrInfo);
#endif
return _attributes;

View File

@@ -4,8 +4,8 @@
#include "MType.h"
#include "MClass.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/attrdefs.h>
MField::MField(MonoClassField* monoField, const char* name, MClass* parentClass)
: _monoField(monoField)

View File

@@ -5,8 +5,8 @@
#include "MClass.h"
#include "Engine/Profiler/ProfilerCPU.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/attrdefs.h>
MMethod::MMethod(MonoMethod* monoMethod, MClass* parentClass)
: MMethod(monoMethod, mono_method_get_name(monoMethod), parentClass)

View File

@@ -6,7 +6,7 @@
#include "MClass.h"
#include "MType.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug.h>
MProperty::MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass)
: _monoProperty(monoProperty)

View File

@@ -4,7 +4,7 @@
#include "Engine/Core/Types/String.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug.h>
#endif
/// <summary>

View File

@@ -3,7 +3,7 @@
#include "MType.h"
#include "MUtils.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug.h>
String MType::ToString() const
{

View File

@@ -11,8 +11,8 @@
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#include <mono/metadata/object.h>
#include <mono/metadata/appdomain.h>
#if USE_NETCORE
#include "Engine/Scripting/DotNet/CoreCLR.h"

View File

@@ -8,7 +8,7 @@
#include "StdTypesContainer.h"
#include "MException.h"
#include "ManagedCLR/MMethod.h"
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug.h>
void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, MObject* object)
{

View File

@@ -15,7 +15,7 @@
#include "Engine/Core/Types/Pair.h"
#include "Engine/Threading/Threading.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
#include <mono/metadata/mono-gc.h>
#endif
#if USE_MONO

View File

@@ -31,8 +31,8 @@
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Serialization/JsonTools.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/object.h>
#endif
#if USE_NETCORE
#include "DotNet/CoreCLR.h"

View File

@@ -17,8 +17,8 @@
#include "ManagedCLR/MCore.h"
#include "FlaxEngine.Gen.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#include <mono/metadata/object.h>
#include <mono/metadata/appdomain.h>
#endif
#define ScriptingObject_unmanagedPtr "__unmanagedPtr"