From d41daee94c724dbbc0ddad00b598ef4116c2b8ab Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 25 Feb 2021 11:14:42 +0100 Subject: [PATCH 1/5] Fix warning --- Source/Engine/Platform/Windows/WindowsWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Platform/Windows/WindowsWindow.cpp b/Source/Engine/Platform/Windows/WindowsWindow.cpp index 61c8737b8..299c31df8 100644 --- a/Source/Engine/Platform/Windows/WindowsWindow.cpp +++ b/Source/Engine/Platform/Windows/WindowsWindow.cpp @@ -481,7 +481,7 @@ void WindowsWindow::StartTrackingMouse(bool useMouseScreenOffset) int32 x = 0 , y = 0, width = 0, height = 0; GetScreenInfo(x, y, width, height); - _mouseOffsetScreenSize = Rectangle(x, y, width, height); + _mouseOffsetScreenSize = Rectangle((float)x, (float)y, (float)width, (float)height); SetCapture(_handle); } From 86c1823d4a3e0696e1e792a9c1557b1e393cef72 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 27 Feb 2021 00:00:02 +0100 Subject: [PATCH 2/5] Fix typo --- .../Flax.Build/Bindings/BindingsGenerator.Cpp.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 3f088ffdf..9fdcbd56a 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -12,8 +12,8 @@ namespace Flax.Build.Bindings partial class BindingsGenerator { private static readonly bool[] CppParamsThatNeedLocalVariable = new bool[64]; - private static readonly bool[] CppParamsThatNeedConvertion = new bool[64]; - private static readonly string[] CppParamsThatNeedConvertionWrappers = new string[64]; + private static readonly bool[] CppParamsThatNeedConversion = new bool[64]; + private static readonly string[] CppParamsThatNeedConversionWrappers = new string[64]; private static readonly string[] CppParamsWrappersCache = new string[64]; public static readonly List CppUsedNonPodTypes = new List(); private static readonly List CppUsedNonPodTypesList = new List(); @@ -619,7 +619,7 @@ namespace Flax.Build.Bindings contents.Append(", "); separator = true; - CppParamsThatNeedConvertion[i] = false; + CppParamsThatNeedConversion[i] = false; CppParamsWrappersCache[i] = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, out var managedType, functionInfo, out CppParamsThatNeedLocalVariable[i]); contents.Append(managedType); if (parameterInfo.IsRef || parameterInfo.IsOut || UsePassByReference(buildData, parameterInfo.Type, caller)) @@ -653,8 +653,8 @@ namespace Flax.Build.Bindings if (convertOutputParameter) { useInlinedReturn = false; - CppParamsThatNeedConvertion[i] = true; - CppParamsThatNeedConvertionWrappers[i] = GenerateCppWrapperNativeToManaged(buildData, parameterInfo.Type, caller, out _, functionInfo); + CppParamsThatNeedConversion[i] = true; + CppParamsThatNeedConversionWrappers[i] = GenerateCppWrapperNativeToManaged(buildData, parameterInfo.Type, caller, out _, functionInfo); } } } @@ -716,7 +716,7 @@ namespace Flax.Build.Bindings callParams += ", "; separator = true; var name = parameterInfo.Name; - if (CppParamsThatNeedConvertion[i] && (!FindApiTypeInfo(buildData, parameterInfo.Type, caller)?.IsStruct ?? false)) + if (CppParamsThatNeedConversion[i] && (!FindApiTypeInfo(buildData, parameterInfo.Type, caller)?.IsStruct ?? false)) name = '*' + name; string param = string.Empty; @@ -734,7 +734,7 @@ namespace Flax.Build.Bindings } // Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter) - if (CppParamsThatNeedConvertion[i]) + if (CppParamsThatNeedConversion[i]) { var apiType = FindApiTypeInfo(buildData, parameterInfo.Type, caller); if (apiType != null) @@ -791,7 +791,7 @@ namespace Flax.Build.Bindings var parameterInfo = functionInfo.Parameters[i]; // Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter) - if (CppParamsThatNeedConvertion[i]) + if (CppParamsThatNeedConversion[i]) { contents.AppendFormat(" *{0} = {1};", parameterInfo.Name, string.Format(CppParamsThatNeedConvertionWrappers[i], parameterInfo.Name + "Temp")).AppendLine(); } From bcf86d9d9fae9e7532748682ebca3cf827a54de8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 27 Feb 2021 00:00:28 +0100 Subject: [PATCH 3/5] Add `StringBuilder::ToStringView()` --- Source/Engine/Core/Types/StringBuilder.h | 2 ++ Source/Engine/Core/Types/StringView.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/Source/Engine/Core/Types/StringBuilder.h b/Source/Engine/Core/Types/StringBuilder.h index f38d5279e..fd0400fba 100644 --- a/Source/Engine/Core/Types/StringBuilder.h +++ b/Source/Engine/Core/Types/StringBuilder.h @@ -269,6 +269,8 @@ public: { return String(_data.Get(), _data.Count()); } + + StringView ToStringView() const; }; inline uint32 GetHash(const StringBuilder& key) diff --git a/Source/Engine/Core/Types/StringView.cpp b/Source/Engine/Core/Types/StringView.cpp index 43776605a..d6cbb3a6a 100644 --- a/Source/Engine/Core/Types/StringView.cpp +++ b/Source/Engine/Core/Types/StringView.cpp @@ -2,6 +2,12 @@ #include "StringView.h" #include "String.h" +#include "StringBuilder.h" + +StringView StringBuilder::ToStringView() const +{ + return StringView(_data.Get(), _data.Count()); +} StringView StringView::Empty; From cdf66372e6c6169ca97349bd284bf2aa856f3aa3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 27 Feb 2021 00:38:42 +0100 Subject: [PATCH 4/5] Add write barriers for Mono GC in bindings glue code --- .../Bindings/BindingsGenerator.Cpp.cs | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 9fdcbd56a..1a120eb80 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -14,6 +14,7 @@ namespace Flax.Build.Bindings private static readonly bool[] CppParamsThatNeedLocalVariable = new bool[64]; private static readonly bool[] CppParamsThatNeedConversion = new bool[64]; private static readonly string[] CppParamsThatNeedConversionWrappers = new string[64]; + private static readonly string[] CppParamsThatNeedConversionTypes = new string[64]; private static readonly string[] CppParamsWrappersCache = new string[64]; public static readonly List CppUsedNonPodTypes = new List(); private static readonly List CppUsedNonPodTypesList = new List(); @@ -654,7 +655,7 @@ namespace Flax.Build.Bindings { useInlinedReturn = false; CppParamsThatNeedConversion[i] = true; - CppParamsThatNeedConversionWrappers[i] = GenerateCppWrapperNativeToManaged(buildData, parameterInfo.Type, caller, out _, functionInfo); + CppParamsThatNeedConversionWrappers[i] = GenerateCppWrapperNativeToManaged(buildData, parameterInfo.Type, caller, out CppParamsThatNeedConversionTypes[i], functionInfo); } } } @@ -793,7 +794,39 @@ namespace Flax.Build.Bindings // Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter) if (CppParamsThatNeedConversion[i]) { - contents.AppendFormat(" *{0} = {1};", parameterInfo.Name, string.Format(CppParamsThatNeedConvertionWrappers[i], parameterInfo.Name + "Temp")).AppendLine(); + var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp"); + + // MonoObject* parameters returned by reference need write barrier for GC + if (parameterInfo.IsOut) + { + var apiType = FindApiTypeInfo(buildData, parameterInfo.Type, caller); + if (apiType != null) + { + if (apiType.IsClass) + { + contents.AppendFormat(" mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine(); + continue; + } + if (apiType.IsStruct && !apiType.IsPod) + { + CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h"); + contents.AppendFormat(" {{ auto _temp = {1}; mono_gc_wbarrier_value_copy({0}, &_temp, 1, {2}::TypeInitializer.GetType().ManagedClass->GetNative()); }}", parameterInfo.Name, value, apiType.FullNameNative).AppendLine(); + continue; + } + } + else + { + // BytesContainer + if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null) + { + contents.AppendFormat(" mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine(); + continue; + } + + throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'"); + } + } + contents.AppendFormat(" *{0} = {1};", parameterInfo.Name, value).AppendLine(); } } } From c3e3e70f96413598e407a899a7c8c327cb6ab8b0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 27 Feb 2021 00:39:12 +0100 Subject: [PATCH 5/5] Add minor tweaks for debug code and add mono dev docs --- Development/Documentation/mono.md | 13 +++++++++++ .../Scripting/ManagedCLR/MCore.Mono.cpp | 22 ++++++++++--------- 2 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 Development/Documentation/mono.md diff --git a/Development/Documentation/mono.md b/Development/Documentation/mono.md new file mode 100644 index 000000000..3f3267860 --- /dev/null +++ b/Development/Documentation/mono.md @@ -0,0 +1,13 @@ +## Mono + +Custom fork: [https://github.com/FlaxEngine/mono](https://github.com/FlaxEngine/mono) with custom features for C# assemblies hot-reloading at runtime without domain unload (more: [https://flaxengine.com/blog/flax-facts-16-scripts-hot-reload/](https://flaxengine.com/blog/flax-facts-16-scripts-hot-reload/)). + +### Notes + +Some useful notes and tips for devs: +* When working with mono fork set `localRepoPath` to local repo location in `Source\Tools\Flax.Build\Deps\Dependencies\mono.cs` +* To update mono deps when developing/updating use `.\Development\Scripts\Windows\CallBuildTool.bat -log -ReBuildDeps -verbose -depsToBuild=mono -platform=Windows`, then build engine and run it +* `MONO_GC_DEBUG=check-remset-consistency` - it will do additional checks at each collection to see if there are any missing write barriers +* `MONO_GC_DEBUG=nursery-canaries` - it might catch some buffer overflows in case of problems in code. +* Methods `mono_custom_attrs_from_property` and `mono_custom_attrs_get_attr` are internally cached +* If C++ mono call a method in c# that will throw an error, error will be handled but, not completly. Calling relase domain will return random `Access memory violation`. First search for error in c# code. No workaround yet. diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.Mono.cpp b/Source/Engine/Scripting/ManagedCLR/MCore.Mono.cpp index c69a2870b..7ab51d85b 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.Mono.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MCore.Mono.cpp @@ -115,6 +115,8 @@ void* MonoCalloc(size_t count, size_t size) #if USE_MONO_PROFILER +#include "Engine/Core/Types/StringBuilder.h" + struct FlaxMonoProfiler { }; @@ -123,7 +125,7 @@ FlaxMonoProfiler Profiler; struct StackWalkDataResult { - StringAnsi Buffer; + StringBuilder Buffer; }; mono_bool OnStackWalk(MonoMethod* method, int32_t native_offset, int32_t il_offset, mono_bool managed, void* data) @@ -135,16 +137,16 @@ mono_bool OnStackWalk(MonoMethod* method, int32_t native_offset, int32_t il_offs auto mName = mono_method_get_name(method); auto mKlassNameSpace = mono_class_get_namespace(mono_method_get_class(method)); auto mKlassName = mono_class_get_name(mono_method_get_class(method)); - result->Buffer += mKlassNameSpace; - result->Buffer += "."; - result->Buffer += mKlassName; - result->Buffer += "::"; - result->Buffer += mName; - result->Buffer += "\n"; + result->Buffer.Append(mKlassNameSpace); + result->Buffer.Append(TEXT(".")); + result->Buffer.Append(mKlassName); + result->Buffer.Append(TEXT("::")); + result->Buffer.Append(mName); + result->Buffer.Append(TEXT("\n")); } else if (!managed) { - result->Buffer += "\n"; + result->Buffer.Append(TEXT("\n")); } return 0; @@ -167,10 +169,10 @@ void OnGCAllocation(MonoProfiler* profiler, MonoObject* obj) if (details) { StackWalkDataResult stackTrace; - stackTrace.Buffer.reserve(1024); + stackTrace.Buffer.SetCapacity(1024); mono_stack_walk(&OnStackWalk, &stackTrace); - LOG(Info, "GC new: {0}.{1} ({2} bytes). Stack Trace:\n{3}", name_space, name, size, stackTrace.Buffer.c_str()); + LOG(Info, "GC new: {0}.{1} ({2} bytes). Stack Trace:\n{3}", String(name_space), String(name), size, stackTrace.Buffer.ToStringView()); } } #endif