Start CoreClr from Beef and basic interaction

This commit is contained in:
Simon Lübeß
2023-07-21 22:23:31 +02:00
parent 8296f1c5cd
commit 62c85e9e1f
14 changed files with 393 additions and 178 deletions
@@ -0,0 +1,133 @@
using NetHostBeef;
using System;
using System.Interop;
namespace GlitchyEngine.Scripting;
static class CoreClrHelper
{
static HostFxr.InitializeForDotnetCommandLineFn HostFxr_Init;
static HostFxr.GetRuntimeDelegateFn HostFxr_GetDelegate;
static HostFxr.CloseFn HostFxr_Close;
static CoreClr.LoadAssemblyAndGetFunctionPointerFn LoadAssemblyAndGetFunctionPointerFn;
static CoreClr.GetFunctionPointerFn GetFunctionPointerFn;
private function void LoadScriptAssemblyFunc(uint8* appData, int64 appLength, uint8* pdbData, int64 pdbLength);
//static function void(char8* path) LoadScriptAssembly;
static LoadScriptAssemblyFunc _loadScriptAssembly;
static function void() _unloadAssemblies;
public static void Init(StringView coreAssemblyPath)
{
LoadHostFxr();
InitAndStartRuntime(coreAssemblyPath);
PrepareFunction();
}
static void LoadHostFxr()
{
char_t[256] buffer = ?;
c_size bufferSize = buffer.Count;
int rc = NetHost.get_hostfxr_path(&buffer, &bufferSize, null);
Log.EngineLogger.AssertDebug(rc == 0, "Failed to get HostFxr path.");
// Load hostfxr and get desired exports
void* lib = NetHostHelper.LoadLibrary(&buffer);
HostFxr_Init = NetHostHelper.GetExport<HostFxr.InitializeForDotnetCommandLineFn>(lib, "hostfxr_initialize_for_dotnet_command_line");
HostFxr_GetDelegate = NetHostHelper.GetExport<HostFxr.GetRuntimeDelegateFn>(lib, "hostfxr_get_runtime_delegate");
HostFxr_Close = NetHostHelper.GetExport<HostFxr.CloseFn>(lib, "hostfxr_close");
Log.EngineLogger.AssertDebug(HostFxr_Init != null && HostFxr_GetDelegate != null && HostFxr_Close != null, "Retrieving at least one HostFxr function failed.");
}
static void InitAndStartRuntime(StringView coreAssembly)
{
char_t* ptr = NetHostHelper.GetScopedRawPtr!(coreAssembly);
char_t*[2] args = char_t*[](
ptr,
null
);
HostFxr.Handle cxt = null;
int rc = HostFxr_Init(1, &args, null, &cxt);
if (rc != 0 || cxt == null)
{
Log.EngineLogger.Error($"Failed to initialize HostFxr: {rc}");
HostFxr_Close(cxt);
}
Log.EngineLogger.Assert(rc == 0, "Failed to initialize HostFxr.");
rc = HostFxr_GetDelegate(cxt, .LoadAssemblyAndGetFunctionPointer, (void**)&LoadAssemblyAndGetFunctionPointerFn);
Log.EngineLogger.Assert(rc == 0, scope $"Get delegate failed: {rc}. (LoadAssemblyAndGetFunctionPointer)");
rc = HostFxr_GetDelegate(cxt, .GetFunctionPointer, (void**)&GetFunctionPointerFn);
Log.EngineLogger.Assert(rc == 0, scope $"Get delegate failed: {rc}. (GetFunctionPointer)");
HostFxr_Close(cxt);
}
static void PrepareFunction()
{
GetFunctionPointerUnmanagedCallersOnly<LoadScriptAssemblyFunc>("GlitchyEngine.ScriptGlue, ScriptCore", "LoadScriptAssembly",
out _loadScriptAssembly);
GetFunctionPointerUnmanagedCallersOnly<function void()>("GlitchyEngine.ScriptGlue, ScriptCore", "UnloadAssemblies",
out _unloadAssemblies);
}
public static void LoadAppAssembly(Span<uint8> appAssemblyData, Span<uint8> pdbData)
{
_loadScriptAssembly(appAssemblyData.Ptr, appAssemblyData.Length, pdbData.Ptr, pdbData.Length);
}
public static void UnloadAssemblies()
{
_unloadAssemblies();
}
public static int GetFunctionPointer<T>(StringView typeName, StringView methodName, StringView delegateName, out T outDelegate) where T: operator explicit void*
{
void* funPtr = null;
int rc = GetFunctionPointerFn(NetHostHelper.GetScopedRawPtr!(typeName),
NetHostHelper.GetScopedRawPtr!(methodName), NetHostHelper.GetScopedRawPtr!(delegateName),
null, null, out funPtr);
outDelegate = (T)funPtr;
return rc;
}
public static int GetFunctionPointerDefaultDelegate(StringView typeName, StringView methodName, out CoreClr.DefaultEntryPoint outDelegate)
{
void* funPtr = null;
int rc = GetFunctionPointerFn(NetHostHelper.GetScopedRawPtr!(typeName),
NetHostHelper.GetScopedRawPtr!(methodName), null, null, null, out funPtr);
outDelegate = (CoreClr.DefaultEntryPoint)funPtr;
return rc;
}
public static int GetFunctionPointerUnmanagedCallersOnly<T>(StringView typeName, StringView methodName, out T outDelegate) where T: operator explicit void*
{
void* funPtr = null;
int rc = GetFunctionPointerFn(NetHostHelper.GetScopedRawPtr!(typeName),
NetHostHelper.GetScopedRawPtr!(methodName), CoreClr.UNMANAGEDCALLERSONLY_METHOD, null, null, out funPtr);
outDelegate = (T)funPtr;
return rc;
}
}
+46 -36
View File
@@ -5,6 +5,8 @@ using System.Collections;
using GlitchyEngine.Core;
using GlitchyEngine.Math;
using GlitchyEngine.World;
using NetHostBeef;
using System.Interop;
namespace GlitchyEngine.Scripting;
@@ -96,49 +98,32 @@ static class ScriptEngine
{
internal static MonoClass* s_ShowInEditorAttribute;
}
private static String _coreAssemblyPath = "resources/scripts/ScriptCore.dll";
private static String _appAssemblyPath = "SandboxProject/Assets/Scripts/bin/Sandbox.dll";
public static void Init()
{
InitMono();
ScriptGlue.Init();
CoreClrHelper.Init(_coreAssemblyPath);
//ScriptGlue.Init();
LoadScriptAssemblies();
LoadScriptAssembly();
InitAssemblyWatcher();
}
static void InitMono()
{
Mono.mono_set_assemblies_path("mono/lib");
if (_debuggingEnabled)
{
char8*[2] options = .(
"--debugger-agent=transport=dt_socket,address=127.0.0.1:2550,server=y,suspend=n,loglevel=3,logfile=MonoDebugger.log",
"--soft-breakpoints"
);
Mono.mono_jit_parse_options(options.Count, &options);
Mono.mono_debug_init(.Mono);
}
s_RootDomain = Mono.mono_jit_init("GlitchyEngineJITRuntime");
Log.EngineLogger.Assert(s_RootDomain != null, "Failed to initialize mono root domain");
if (_debuggingEnabled)
{
Mono.mono_debug_domain_create(s_RootDomain);
}
Mono.mono_thread_set_main(Mono.mono_thread_current());
}
static void InitAssemblyWatcher()
{
if (_userAssemblyWatcher == null)
{
String directoryPath = scope String();
Path.GetDirectoryPath(_appAssemblyPath, directoryPath);
String fileName = scope String();
Path.GetFileName(_appAssemblyPath, fileName);
// TODO: Obviously don't hardcode path
_userAssemblyWatcher = new FileSystemWatcher("SandboxProject/Assets/Scripts/bin/", "*/Sandbox.dll");
_userAssemblyWatcher = new FileSystemWatcher(directoryPath, fileName);
_userAssemblyWatcher.OnChanged.Add(new (fileName) =>
{
// TODO: Temporary, we want to be able to reload while in play-mode. (+ Editor Scripts will be a thing some day)
@@ -165,7 +150,7 @@ static class ScriptEngine
_userAssemblyWatcher.StartRaisingEvents();
}
static void LoadScriptAssemblies()
/*static void LoadScriptAssemblies()
{
CreateAppDomain("GlitchyEngineScriptRuntime");
(s_CoreAssembly, s_CoreAssemblyImage) = LoadAssembly("resources/scripts/ScriptCore.dll", _debuggingEnabled);
@@ -174,6 +159,28 @@ static class ScriptEngine
GetEntitiesFromAssemblies();
ScriptGlue.RegisterManagedComponents();
}*/
static void LoadScriptAssembly()
{
List<uint8> data = new List<uint8>(1024);
File.ReadAll(_appAssemblyPath, data);
List<uint8> pdbData = new List<uint8>(1024);
String pdbPath = scope .();
Path.ChangeExtension(_appAssemblyPath, ".pdb", pdbPath);
File.ReadAll(pdbPath, pdbData);
CoreClrHelper.LoadAppAssembly(data, pdbData);
delete data;
delete pdbData;
//GetEntitiesFromAssemblies();
//ScriptGlue.RegisterManagedComponents();
}
public static void SetContext(Scene scene)
@@ -351,11 +358,14 @@ static class ScriptEngine
{
Debug.Profiler.ProfileFunction!();
Mono.mono_domain_set(s_RootDomain, false);
CoreClrHelper.UnloadAssemblies();
LoadScriptAssembly();
Mono.mono_domain_unload(s_AppDomain);
//Mono.mono_domain_set(s_RootDomain, false);
LoadScriptAssemblies();
//Mono.mono_domain_unload(s_AppDomain);
//LoadScriptAssemblies();
// TODO: ScriptFields might get added
// TODO: ScriptField Types may change after reload!
@@ -367,13 +377,13 @@ static class ScriptEngine
public static void Shutdown()
{
Mono.mono_domain_set(s_RootDomain, false);
/*Mono.mono_domain_set(s_RootDomain, false);
Mono.mono_domain_unload(s_AppDomain);
s_AppDomain = null;
Mono.mono_jit_cleanup(s_RootDomain);
s_RootDomain = null;
s_RootDomain = null;*/
}
internal static void RegisterSharpType(SharpType sharpType)
+9 -12
View File
@@ -29,7 +29,7 @@ static class ScriptGlue
}
}
/* Adding this attribute to a method will log method entry and returned Result<T> errors */
/*/* Adding this attribute to a method will log method entry and returned Result<T> errors */
[AttributeUsage(.Method)]
struct RegisterMethodAttribute : Attribute, IOnMethodInit
{
@@ -48,13 +48,13 @@ static class ScriptGlue
}
}
}
}
}*/
public static void Init()
{
RegisterCalls();
//RegisterCalls();
RegisterMathFunctions();
//RegisterMathFunctions();
}
public static void RegisterManagedComponents()
@@ -67,11 +67,11 @@ static class ScriptGlue
RegisterComponent<Rigidbody2DComponent>("GlitchyEngine.RigidBody2D");
}
[RegisterMethod]
/*[RegisterMethod]
private static void RegisterCalls()
{
// Generated at CompTime
}
}*/
private static void RegisterComponent<T>(StringView cSharpClassName = "") where T : struct, new
{
@@ -104,13 +104,10 @@ static class ScriptGlue
}
[RegisterCall("Log::LogMessage_Impl")]
static void Log(int32 logLevel, MonoString* message)
[Export, LinkName("Log::LogMessage_Impl"), CallingConvention(.Cdecl)]
static void Log(int32 logLevel, char8* message)
{
char8* utfMessage = Mono.mono_string_to_utf8(message);
Log.ClientLogger.Log((LogLevel)logLevel, StringView(utfMessage));
Mono.mono_free(utfMessage);
Log.ClientLogger.Log((LogLevel)logLevel, StringView(message));
}
#region Input