Browse Source

Mono/C#: WebAssembly support

Ignacio Etcheverry 5 years ago
parent
commit
de7c2ad21b
37 changed files with 1318 additions and 988 deletions
  1. 82 27
      modules/mono/build_scripts/mono_configure.py
  2. 0 70
      modules/mono/build_scripts/patches/fix-mono-android-tkill.diff
  3. 10 2
      modules/mono/config.py
  4. 9 9
      modules/mono/csharp_script.cpp
  5. 1 1
      modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
  6. 211 0
      modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
  7. 6 5
      modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
  8. 0 197
      modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs
  9. 1 1
      modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
  10. 1 1
      modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
  11. 3 3
      modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs
  12. 49 27
      modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
  13. 6 6
      modules/mono/editor/editor_internal_calls.cpp
  14. 1 0
      modules/mono/editor/godotsharp_export.cpp
  15. 1 0
      modules/mono/glue/base_object_glue.cpp
  16. 1 0
      modules/mono/glue/collections_glue.cpp
  17. 2 1
      modules/mono/glue/gd_glue.cpp
  18. 4 0
      modules/mono/godotsharp_dirs.cpp
  19. 65 19
      modules/mono/mono_gd/gd_mono.cpp
  20. 1 0
      modules/mono/mono_gd/gd_mono_assembly.cpp
  21. 282 0
      modules/mono/mono_gd/gd_mono_cache.cpp
  22. 174 0
      modules/mono/mono_gd/gd_mono_cache.h
  23. 1 6
      modules/mono/mono_gd/gd_mono_class.cpp
  24. 0 2
      modules/mono/mono_gd/gd_mono_class.h
  25. 4 2
      modules/mono/mono_gd/gd_mono_field.cpp
  26. 6 0
      modules/mono/mono_gd/gd_mono_header.h
  27. 45 18
      modules/mono/mono_gd/gd_mono_log.cpp
  28. 10 4
      modules/mono/mono_gd/gd_mono_log.h
  29. 5 4
      modules/mono/mono_gd/gd_mono_marshal.cpp
  30. 5 0
      modules/mono/mono_gd/gd_mono_marshal.h
  31. 2 4
      modules/mono/mono_gd/gd_mono_method.cpp
  32. 2 2
      modules/mono/mono_gd/gd_mono_method.h
  33. 302 0
      modules/mono/mono_gd/gd_mono_method_thunk.h
  34. 2 0
      modules/mono/mono_gd/gd_mono_property.cpp
  35. 21 294
      modules/mono/mono_gd/gd_mono_utils.cpp
  36. 0 281
      modules/mono/mono_gd/gd_mono_utils.h
  37. 3 2
      modules/mono/signal_awaiter_utils.cpp

+ 82 - 27
modules/mono/build_scripts/mono_configure.py

@@ -44,9 +44,33 @@ def copy_file(src_dir, dst_dir, name):
     copy(src_path, dst_dir)
     copy(src_path, dst_dir)
 
 
 
 
+def is_desktop(platform):
+    return platform in ['windows', 'osx', 'x11', 'server', 'uwp', 'haiku']
+
+
+def is_unix_like(platform):
+    return platform in ['osx', 'x11', 'server', 'android', 'haiku']
+
+
+def module_supports_tools_on(platform):
+    return platform not in ['android', 'javascript']
+
+
+def find_wasm_src_dir(mono_root):
+    hint_dirs = [
+        os.path.join(mono_root, 'src'),
+        os.path.join(mono_root, '../src'),
+    ]
+    for hint_dir in hint_dirs:
+        if os.path.isfile(os.path.join(hint_dir, 'driver.c')):
+            return hint_dir
+    return ''
+
+
 def configure(env, env_mono):
 def configure(env, env_mono):
     bits = env['bits']
     bits = env['bits']
     is_android = env['platform'] == 'android'
     is_android = env['platform'] == 'android'
+    is_javascript = env['platform'] == 'javascript'
 
 
     tools_enabled = env['tools']
     tools_enabled = env['tools']
     mono_static = env['mono_static']
     mono_static = env['mono_static']
@@ -63,17 +87,21 @@ def configure(env, env_mono):
         env_mono.Append(CPPDEFINES=['NO_PENDING_EXCEPTIONS'])
         env_mono.Append(CPPDEFINES=['NO_PENDING_EXCEPTIONS'])
 
 
     if is_android and not env['android_arch'] in android_arch_dirs:
     if is_android and not env['android_arch'] in android_arch_dirs:
-        raise RuntimeError('This module does not support for the specified \'android_arch\': ' + env['android_arch'])
+        raise RuntimeError('This module does not support the specified \'android_arch\': ' + env['android_arch'])
 
 
-    if is_android and tools_enabled:
-        # TODO: Implement this. We have to add the data directory to the apk, concretely the Api and Tools folders.
-        raise RuntimeError('This module does not currently support building for android with tools enabled')
+    if tools_enabled and not module_supports_tools_on(env['platform']):
+        # TODO:
+        # Android: We have to add the data directory to the apk, concretely the Api and Tools folders.
+        raise RuntimeError('This module does not currently support building for this platform with tools enabled')
 
 
     if is_android and mono_static:
     if is_android and mono_static:
-        # When static linking and doing something that requires libmono-native, we get a dlopen error as libmono-native seems to depend on libmonosgen-2.0
-        raise RuntimeError('Linking Mono statically is not currently supported on Android')
+        # Android: When static linking and doing something that requires libmono-native, we get a dlopen error as libmono-native seems to depend on libmonosgen-2.0
+        raise RuntimeError('Statically linking Mono is not currently supported on this platform')
 
 
-    if (os.getenv('MONO32_PREFIX') or os.getenv('MONO64_PREFIX')) and not mono_prefix:
+    if is_javascript:
+        mono_static = True
+
+    if not mono_prefix and (os.getenv('MONO32_PREFIX') or os.getenv('MONO64_PREFIX')):
         print("WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the 'mono_prefix' SCons parameter instead")
         print("WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the 'mono_prefix' SCons parameter instead")
 
 
     if env['platform'] == 'windows':
     if env['platform'] == 'windows':
@@ -143,7 +171,7 @@ def configure(env, env_mono):
         mono_lib_path = ''
         mono_lib_path = ''
         mono_so_name = ''
         mono_so_name = ''
 
 
-        if not mono_root and is_android:
+        if not mono_root and (is_android or is_javascript):
             raise RuntimeError("Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter")
             raise RuntimeError("Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter")
 
 
         if not mono_root and is_apple:
         if not mono_root and is_apple:
@@ -167,7 +195,7 @@ def configure(env, env_mono):
 
 
             mono_lib_path = os.path.join(mono_root, 'lib')
             mono_lib_path = os.path.join(mono_root, 'lib')
 
 
-            env.Append(LIBPATH=mono_lib_path)
+            env.Append(LIBPATH=[mono_lib_path])
             env_mono.Prepend(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
             env_mono.Prepend(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
 
 
             mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
             mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
@@ -183,7 +211,30 @@ def configure(env, env_mono):
                 if is_apple:
                 if is_apple:
                     env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file])
                     env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file])
                 else:
                 else:
+                    assert is_desktop(env['platform']) or is_android or is_javascript
                     env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
                     env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
+
+                if is_javascript:
+                    env.Append(LIBS=['mono-icall-table', 'mono-native', 'mono-ilgen', 'mono-ee-interp'])
+
+                    wasm_src_dir = os.path.join(mono_root, 'src')
+                    if not os.path.isdir(wasm_src_dir):
+                        raise RuntimeError('Could not find mono wasm src directory')
+
+                    # Ideally this should be defined only for 'driver.c', but I can't fight scons for another 2 hours
+                    env_mono.Append(CPPDEFINES=['CORE_BINDINGS'])
+
+                    env_mono.add_source_files(env.modules_sources, [
+                        os.path.join(wasm_src_dir, 'driver.c'),
+                        os.path.join(wasm_src_dir, 'zlib-helper.c'),
+                        os.path.join(wasm_src_dir, 'corebindings.c')
+                    ])
+
+                    env.Append(LINKFLAGS=[
+                        '--js-library', os.path.join(wasm_src_dir, 'library_mono.js'),
+                        '--js-library', os.path.join(wasm_src_dir, 'binding_support.js'),
+                        '--js-library', os.path.join(wasm_src_dir, 'dotnet_support.js')
+                    ])
             else:
             else:
                 env.Append(LIBS=[mono_lib])
                 env.Append(LIBS=[mono_lib])
 
 
@@ -191,6 +242,8 @@ def configure(env, env_mono):
                 env.Append(LIBS=['iconv', 'pthread'])
                 env.Append(LIBS=['iconv', 'pthread'])
             elif is_android:
             elif is_android:
                 pass # Nothing
                 pass # Nothing
+            elif is_javascript:
+                env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
             else:
             else:
                 env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
                 env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
 
 
@@ -230,19 +283,22 @@ def configure(env, env_mono):
 
 
         env.Append(LINKFLAGS='-rdynamic')
         env.Append(LINKFLAGS='-rdynamic')
 
 
-    if not tools_enabled and not is_android:
-        if not mono_root:
-            mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
+    if not tools_enabled:
+        if is_desktop(env['platform']):
+            if not mono_root:
+                mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
 
 
-        make_template_dir(env, mono_root)
-    elif not tools_enabled and is_android:
-        # Compress Android Mono Config
-        from . import make_android_mono_config
-        config_file_path = os.path.join(mono_root, 'etc', 'mono', 'config')
-        make_android_mono_config.generate_compressed_config(config_file_path, 'mono_gd/')
+            make_template_dir(env, mono_root)
+        elif is_android:
+            # Compress Android Mono Config
+            from . import make_android_mono_config
+            config_file_path = os.path.join(mono_root, 'etc', 'mono', 'config')
+            make_android_mono_config.generate_compressed_config(config_file_path, 'mono_gd/')
 
 
-        # Copy the required shared libraries
-        copy_mono_shared_libs(env, mono_root, None)
+            # Copy the required shared libraries
+            copy_mono_shared_libs(env, mono_root, None)
+        elif is_javascript:
+            pass # No data directory for this platform
 
 
     if copy_mono_root:
     if copy_mono_root:
         if not mono_root:
         if not mono_root:
@@ -251,7 +307,7 @@ def configure(env, env_mono):
         if tools_enabled:
         if tools_enabled:
            copy_mono_root_files(env, mono_root)
            copy_mono_root_files(env, mono_root)
         else:
         else:
-            print("Ignoring option: 'copy_mono_root'. Only available for builds with 'tools' enabled.")
+            print("Ignoring option: 'copy_mono_root'; only available for builds with 'tools' enabled.")
 
 
 
 
 def make_template_dir(env, mono_root):
 def make_template_dir(env, mono_root):
@@ -262,10 +318,9 @@ def make_template_dir(env, mono_root):
 
 
     template_dir_name = ''
     template_dir_name = ''
 
 
-    if platform in ['windows', 'osx', 'x11', 'android', 'server']:
-        template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target)
-    else:
-        assert False
+    assert is_desktop(platform)
+
+    template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target)
 
 
     output_dir = Dir('#bin').abspath
     output_dir = Dir('#bin').abspath
     template_dir = os.path.join(output_dir, template_dir_name)
     template_dir = os.path.join(output_dir, template_dir_name)
@@ -278,7 +333,7 @@ def make_template_dir(env, mono_root):
     # Copy etc/mono/
     # Copy etc/mono/
 
 
     template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono')
     template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono')
-    copy_mono_etc_dir(mono_root, template_mono_config_dir, env['platform'])
+    copy_mono_etc_dir(mono_root, template_mono_config_dir, platform)
 
 
     # Copy the required shared libraries
     # Copy the required shared libraries
 
 
@@ -386,7 +441,7 @@ def copy_mono_shared_libs(env, mono_root, target_mono_root_dir):
         if platform == 'osx':
         if platform == 'osx':
             # TODO: Make sure nothing is missing
             # TODO: Make sure nothing is missing
             copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.dylib'), target_mono_lib_dir)
             copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.dylib'), target_mono_lib_dir)
-        elif platform == 'x11' or platform == 'android' or platform == 'server':
+        elif is_unix_like(platform):
             lib_file_names = [lib_name + '.so' for lib_name in [
             lib_file_names = [lib_name + '.so' for lib_name in [
                 'libmono-btls-shared', 'libmono-ee-interp', 'libmono-native', 'libMonoPosixHelper',
                 'libmono-btls-shared', 'libmono-ee-interp', 'libmono-native', 'libMonoPosixHelper',
                 'libmono-profiler-aot', 'libmono-profiler-coverage', 'libmono-profiler-log', 'libMonoSupportW'
                 'libmono-profiler-aot', 'libmono-profiler-coverage', 'libmono-profiler-log', 'libMonoSupportW'

+ 0 - 70
modules/mono/build_scripts/patches/fix-mono-android-tkill.diff

@@ -1,70 +0,0 @@
-diff --git a/libgc/include/private/gcconfig.h b/libgc/include/private/gcconfig.h
-index e2bdf13ac3e..f962200ba4e 100644
---- a/libgc/include/private/gcconfig.h
-+++ b/libgc/include/private/gcconfig.h
-@@ -2255,6 +2255,14 @@
- #   define GETPAGESIZE() getpagesize()
- # endif
- 
-+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
-+    && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
-+        || defined(ARM32) || defined(I386) /* but not x32 */)
-+  /* tkill() exists only on arm32/mips(32)/x86. */
-+  /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
-+# define USE_TKILL_ON_ANDROID
-+#endif
-+
- # if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
- 	    /* OS has SVR4 generic features.  Probably others also qualify.	*/
- #   define SVR4
-diff --git a/libgc/pthread_stop_world.c b/libgc/pthread_stop_world.c
-index f93ce26b562..4a49a6d578c 100644
---- a/libgc/pthread_stop_world.c
-+++ b/libgc/pthread_stop_world.c
-@@ -336,7 +336,7 @@ void GC_push_all_stacks()
- pthread_t GC_stopping_thread;
- int GC_stopping_pid;
- 
--#ifdef HOST_ANDROID
-+#ifdef USE_TKILL_ON_ANDROID
- static
- int android_thread_kill(pid_t tid, int sig)
- {
-diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c
-index ad9b8823f8f..3542b32b540 100644
---- a/mono/metadata/threads.c
-+++ b/mono/metadata/threads.c
-@@ -77,8 +77,12 @@ mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle);
- #include <zircon/syscalls.h>
- #endif
- 
--#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
--#define USE_TKILL_ON_ANDROID 1
-+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
-+    && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
-+        || defined(ARM32) || defined(I386) /* but not x32 */)
-+  /* tkill() exists only on arm32/mips(32)/x86. */
-+  /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
-+# define USE_TKILL_ON_ANDROID
- #endif
- 
- #ifdef HOST_ANDROID
-diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c
-index 3e4bf93de5f..79c9f731fe7 100644
---- a/mono/utils/mono-threads-posix.c
-+++ b/mono/utils/mono-threads-posix.c
-@@ -31,8 +31,12 @@
- 
- #include <errno.h>
- 
--#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
--#define USE_TKILL_ON_ANDROID 1
-+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
-+    && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
-+        || defined(ARM32) || defined(I386) /* but not x32 */)
-+  /* tkill() exists only on arm32/mips(32)/x86. */
-+  /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
-+# define USE_TKILL_ON_ANDROID
- #endif
- 
- #ifdef USE_TKILL_ON_ANDROID

+ 10 - 2
modules/mono/config.py

@@ -1,10 +1,11 @@
 def can_build(env, platform):
 def can_build(env, platform):
-    if platform in ['javascript']:
-        return False # Not yet supported
     return True
     return True
 
 
 
 
 def configure(env):
 def configure(env):
+    if env['platform'] not in ['windows', 'osx', 'x11', 'server', 'android', 'haiku', 'javascript']:
+        raise RuntimeError('This module does not currently support building for this platform')
+
     env.use_ptrcall = True
     env.use_ptrcall = True
     env.add_module_version_string('mono')
     env.add_module_version_string('mono')
 
 
@@ -18,6 +19,13 @@ def configure(env):
     envvars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
     envvars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
     envvars.Update(env)
     envvars.Update(env)
 
 
+    if env['platform'] == 'javascript':
+        # Mono wasm already has zlib builtin, so we need this workaround to avoid symbol collisions
+        print('Compiling with Mono wasm disables \'builtin_zlib\'')
+        env['builtin_zlib'] = False
+        thirdparty_zlib_dir = "#thirdparty/zlib/"
+        env.Prepend(CPPPATH=[thirdparty_zlib_dir])
+
 
 
 def get_doc_classes():
 def get_doc_classes():
     return [
     return [

+ 9 - 9
modules/mono/csharp_script.cpp

@@ -50,8 +50,10 @@
 
 
 #include "editor/editor_internal_calls.h"
 #include "editor/editor_internal_calls.h"
 #include "godotsharp_dirs.h"
 #include "godotsharp_dirs.h"
+#include "mono_gd/gd_mono_cache.h"
 #include "mono_gd/gd_mono_class.h"
 #include "mono_gd/gd_mono_class.h"
 #include "mono_gd/gd_mono_marshal.h"
 #include "mono_gd/gd_mono_marshal.h"
+#include "mono_gd/gd_mono_utils.h"
 #include "signal_awaiter_utils.h"
 #include "signal_awaiter_utils.h"
 #include "utils/macros.h"
 #include "utils/macros.h"
 #include "utils/mutex_utils.h"
 #include "utils/mutex_utils.h"
@@ -545,7 +547,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 	_TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
 	_TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
 
 
-	if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated)
+	if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoCache::cached_data.corlib_cache_updated)
 		return Vector<StackInfo>();
 		return Vector<StackInfo>();
 
 
 	MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr());
 	MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr());
@@ -571,7 +573,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
 
 
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
 
 
-	MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, &exc);
+	MonoArray *frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames).invoke(p_stack_trace, &exc);
 
 
 	if (exc) {
 	if (exc) {
 		GDMonoUtils::debug_print_unhandled_exception(exc);
 		GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -583,8 +585,6 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
 	if (frame_count <= 0)
 	if (frame_count <= 0)
 		return Vector<StackInfo>();
 		return Vector<StackInfo>();
 
 
-	GDMonoUtils::DebugUtils_StackFrameInfo get_sf_info = CACHED_METHOD_THUNK(DebuggingUtils, GetStackFrameInfo);
-
 	Vector<StackInfo> si;
 	Vector<StackInfo> si;
 	si.resize(frame_count);
 	si.resize(frame_count);
 
 
@@ -595,7 +595,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
 		MonoString *file_name;
 		MonoString *file_name;
 		int file_line_num;
 		int file_line_num;
 		MonoString *method_decl;
 		MonoString *method_decl;
-		invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, &exc);
+		CACHED_METHOD_THUNK(DebuggingUtils, GetStackFrameInfo).invoke(frame, &file_name, &file_line_num, &method_decl, &exc);
 
 
 		if (exc) {
 		if (exc) {
 			GDMonoUtils::debug_print_unhandled_exception(exc);
 			GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -618,14 +618,14 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
 void CSharpLanguage::frame() {
 void CSharpLanguage::frame() {
 
 
 	if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != NULL) {
 	if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != NULL) {
-		const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle;
+		const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoCache::cached_data.task_scheduler_handle;
 
 
 		if (task_scheduler_handle.is_valid()) {
 		if (task_scheduler_handle.is_valid()) {
 			MonoObject *task_scheduler = task_scheduler_handle->get_target();
 			MonoObject *task_scheduler = task_scheduler_handle->get_target();
 
 
 			if (task_scheduler) {
 			if (task_scheduler) {
 				MonoException *exc = NULL;
 				MonoException *exc = NULL;
-				invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, &exc);
+				CACHED_METHOD_THUNK(GodotTaskScheduler, Activate).invoke(task_scheduler, &exc);
 
 
 				if (exc) {
 				if (exc) {
 					GDMonoUtils::debug_unhandled_exception(exc);
 					GDMonoUtils::debug_unhandled_exception(exc);
@@ -1079,7 +1079,7 @@ bool CSharpLanguage::overrides_external_editor() {
 void CSharpLanguage::thread_enter() {
 void CSharpLanguage::thread_enter() {
 
 
 #if 0
 #if 0
-	if (mono->is_runtime_initialized()) {
+	if (gdmono->is_runtime_initialized()) {
 		GDMonoUtils::attach_current_thread();
 		GDMonoUtils::attach_current_thread();
 	}
 	}
 #endif
 #endif
@@ -1088,7 +1088,7 @@ void CSharpLanguage::thread_enter() {
 void CSharpLanguage::thread_exit() {
 void CSharpLanguage::thread_exit() {
 
 
 #if 0
 #if 0
-	if (mono->is_runtime_initialized()) {
+	if (gdmono->is_runtime_initialized()) {
 		GDMonoUtils::detach_current_thread();
 		GDMonoUtils::detach_current_thread();
 	}
 	}
 #endif
 #endif

+ 1 - 1
modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs

@@ -91,7 +91,7 @@ namespace GodotTools.Build
             {
             {
                 var result = new List<string>();
                 var result = new List<string>();
 
 
-                if (OS.IsOSX())
+                if (OS.IsOSX)
                 {
                 {
                     result.Add("/Library/Frameworks/Mono.framework/Versions/Current/bin/");
                     result.Add("/Library/Frameworks/Mono.framework/Versions/Current/bin/");
                     result.Add("/usr/local/var/homebrew/linked/mono/bin/");
                     result.Add("/usr/local/var/homebrew/linked/mono/bin/");

+ 211 - 0
modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs

@@ -0,0 +1,211 @@
+using Godot;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using GodotTools.Core;
+using GodotTools.Internals;
+using Directory = GodotTools.Utils.Directory;
+using File = GodotTools.Utils.File;
+using OS = GodotTools.Utils.OS;
+using Path = System.IO.Path;
+
+namespace GodotTools.Export
+{
+    public class ExportPlugin : EditorExportPlugin
+    {
+        private void AddFile(string srcPath, string dstPath, bool remap = false)
+        {
+            AddFile(dstPath, File.ReadAllBytes(srcPath), remap);
+        }
+
+        public override void _ExportFile(string path, string type, string[] features)
+        {
+            base._ExportFile(path, type, features);
+
+            if (type != Internal.CSharpLanguageType)
+                return;
+
+            if (Path.GetExtension(path) != $".{Internal.CSharpLanguageExtension}")
+                throw new ArgumentException($"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}", nameof(path));
+
+            // TODO What if the source file is not part of the game's C# project
+
+            bool includeScriptsContent = (bool) ProjectSettings.GetSetting("mono/export/include_scripts_content");
+
+            if (!includeScriptsContent)
+            {
+                // We don't want to include the source code on exported games
+                AddFile(path, new byte[] { }, remap: false);
+                Skip();
+            }
+        }
+
+        public override void _ExportBegin(string[] features, bool isDebug, string path, int flags)
+        {
+            base._ExportBegin(features, isDebug, path, flags);
+
+            try
+            {
+                _ExportBeginImpl(features, isDebug, path, flags);
+                // TODO: Handle _ExportBeginImpl return value. Do something on error once _ExportBegin supports failing.
+            }
+            catch (Exception e)
+            {
+                GD.PushError($"Failed to export project: {e.Message}");
+                Console.Error.WriteLine(e);
+                // TODO: Do something on error once _ExportBegin supports failing.
+            }
+        }
+
+        private bool _ExportBeginImpl(string[] features, bool isDebug, string path, int flags)
+        {
+            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+                return true;
+
+            string platform = DeterminePlatformFromFeatures(features);
+
+            if (platform == null)
+                throw new NotSupportedException("Target platform not supported");
+
+            // TODO Right now there is no way to stop the export process with an error
+
+            string buildConfig = isDebug ? "Debug" : "Release";
+
+            string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}");
+            CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath);
+
+            AddFile(scriptsMetadataPath, scriptsMetadataPath);
+
+            // Turn export features into defines
+            var godotDefines = features;
+
+            if (!BuildManager.BuildProjectBlocking(buildConfig, godotDefines))
+            {
+                GD.PushError("Failed to build project");
+                return false;
+            }
+
+            // Add dependency assemblies
+
+            var dependencies = new Godot.Collections.Dictionary<string, string>();
+
+            var projectDllName = (string) ProjectSettings.GetSetting("application/config/name");
+            if (projectDllName.Empty())
+            {
+                projectDllName = "UnnamedProject";
+            }
+
+            string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig);
+            string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll");
+
+            dependencies[projectDllName] = projectDllSrcPath;
+
+            {
+                string templatesDir = Internal.FullTemplatesDir;
+                string platformBclDir = Path.Combine(templatesDir, $"{platform}-bcl", platform);
+
+                string customBclDir = Directory.Exists(platformBclDir) ? platformBclDir : string.Empty;
+
+                internal_GetExportedAssemblyDependencies(projectDllName, projectDllSrcPath, buildConfig, customBclDir, dependencies);
+            }
+
+            string apiConfig = isDebug ? "Debug" : "Release";
+            string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, apiConfig);
+
+            foreach (var dependency in dependencies)
+            {
+                string dependSrcPath = dependency.Value;
+                string dependDstPath = Path.Combine(resAssembliesDir, dependSrcPath.GetFile());
+                AddFile(dependSrcPath, dependDstPath);
+            }
+
+            // Mono specific export template extras (data dir)
+            ExportDataDirectory(features, platform, isDebug, path);
+
+            return true;
+        }
+
+        private static void ExportDataDirectory(ICollection<string> features, string platform, bool debug, string path)
+        {
+            if (!PlatformHasTemplateDir(platform))
+                return;
+
+            string bits = features.Contains("64") ? "64" : "32";
+            string target = debug ? "release_debug" : "release";
+
+            string TemplateDirName() => $"data.mono.{platform}.{bits}.{target}";
+
+            string templateDirPath = Path.Combine(Internal.FullTemplatesDir, TemplateDirName());
+
+            if (!Directory.Exists(templateDirPath))
+            {
+                templateDirPath = null;
+                
+                if (debug)
+                {
+                    target = "debug"; // Support both 'release_debug' and 'debug' for the template data directory name
+                    templateDirPath = Path.Combine(Internal.FullTemplatesDir, TemplateDirName());
+
+                    if (!Directory.Exists(templateDirPath))
+                        templateDirPath = null;
+                }
+            }
+
+            if (templateDirPath == null)
+                throw new FileNotFoundException("Data template directory not found");
+
+            string outputDir = new FileInfo(path).Directory?.FullName ??
+                               throw new FileNotFoundException("Base directory not found");
+
+            string outputDataDir = Path.Combine(outputDir, DataDirName);
+
+            if (Directory.Exists(outputDataDir))
+                Directory.Delete(outputDataDir, recursive: true); // Clean first
+
+            Directory.CreateDirectory(outputDataDir);
+
+            foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories))
+            {
+                Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1)));
+            }
+
+            foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories))
+            {
+                File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1)));
+            }
+        }
+
+        private static bool PlatformHasTemplateDir(string platform)
+        {
+            // OSX export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest.
+            return !new[] {OS.Platforms.OSX, OS.Platforms.Android, OS.Platforms.HTML5}.Contains(platform);
+        }
+
+        private static string DeterminePlatformFromFeatures(IEnumerable<string> features)
+        {
+            foreach (var feature in features)
+            {
+                if (OS.PlatformNameMap.TryGetValue(feature, out string platform))
+                    return platform;
+            }
+
+            return null;
+        }
+
+        private static string DataDirName
+        {
+            get
+            {
+                var appName = (string) ProjectSettings.GetSetting("application/config/name");
+                string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false);
+                return $"data_{appNameSafe}";
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void internal_GetExportedAssemblyDependencies(string projectDllName, string projectDllSrcPath,
+            string buildConfig, string customBclDir, Godot.Collections.Dictionary<string, string> dependencies);
+    }
+}

+ 6 - 5
modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs

@@ -1,4 +1,5 @@
 using Godot;
 using Godot;
+using GodotTools.Export;
 using GodotTools.Utils;
 using GodotTools.Utils;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -225,7 +226,7 @@ namespace GodotTools
 
 
                     bool osxAppBundleInstalled = false;
                     bool osxAppBundleInstalled = false;
 
 
-                    if (OS.IsOSX())
+                    if (OS.IsOSX)
                     {
                     {
                         // The package path is '/Applications/Visual Studio Code.app'
                         // The package path is '/Applications/Visual Studio Code.app'
                         const string vscodeBundleId = "com.microsoft.VSCode";
                         const string vscodeBundleId = "com.microsoft.VSCode";
@@ -265,7 +266,7 @@ namespace GodotTools
 
 
                     string command;
                     string command;
 
 
-                    if (OS.IsOSX())
+                    if (OS.IsOSX)
                     {
                     {
                         if (!osxAppBundleInstalled && _vsCodePath.Empty())
                         if (!osxAppBundleInstalled && _vsCodePath.Empty())
                         {
                         {
@@ -420,7 +421,7 @@ namespace GodotTools
                 settingsHintStr += $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
                 settingsHintStr += $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
                                    $",Visual Studio Code:{(int) ExternalEditorId.VsCode}";
                                    $",Visual Studio Code:{(int) ExternalEditorId.VsCode}";
             }
             }
-            else if (OS.IsOSX())
+            else if (OS.IsOSX)
             {
             {
                 settingsHintStr += $",Visual Studio:{(int) ExternalEditorId.VisualStudioForMac}" +
                 settingsHintStr += $",Visual Studio:{(int) ExternalEditorId.VisualStudioForMac}" +
                                    $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
                                    $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
@@ -441,7 +442,7 @@ namespace GodotTools
             });
             });
 
 
             // Export plugin
             // Export plugin
-            var exportPlugin = new GodotSharpExport();
+            var exportPlugin = new ExportPlugin();
             AddExportPlugin(exportPlugin);
             AddExportPlugin(exportPlugin);
             exportPluginWeak = WeakRef(exportPlugin);
             exportPluginWeak = WeakRef(exportPlugin);
 
 
@@ -461,7 +462,7 @@ namespace GodotTools
                 // Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid
                 // Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid
                 // will be freed after EditorSettings already was, and its device polling thread
                 // will be freed after EditorSettings already was, and its device polling thread
                 // will try to access the EditorSettings singleton, resulting in null dereferencing.
                 // will try to access the EditorSettings singleton, resulting in null dereferencing.
-                (exportPluginWeak.GetRef() as GodotSharpExport)?.Dispose();
+                (exportPluginWeak.GetRef() as ExportPlugin)?.Dispose();
 
 
                 exportPluginWeak.Dispose();
                 exportPluginWeak.Dispose();
             }
             }

+ 0 - 197
modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs

@@ -1,197 +0,0 @@
-using Godot;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using GodotTools.Core;
-using GodotTools.Internals;
-using Directory = GodotTools.Utils.Directory;
-using File = GodotTools.Utils.File;
-using Path = System.IO.Path;
-
-namespace GodotTools
-{
-    public class GodotSharpExport : EditorExportPlugin
-    {
-        private void AddFile(string srcPath, string dstPath, bool remap = false)
-        {
-            AddFile(dstPath.Replace("\\", "/"), File.ReadAllBytes(srcPath), remap);
-        }
-
-        public override void _ExportFile(string path, string type, string[] features)
-        {
-            base._ExportFile(path, type, features);
-
-            if (type != Internal.CSharpLanguageType)
-                return;
-
-            if (Path.GetExtension(path) != $".{Internal.CSharpLanguageExtension}")
-                throw new ArgumentException($"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}", nameof(path));
-
-            // TODO What if the source file is not part of the game's C# project
-
-            bool includeScriptsContent = (bool) ProjectSettings.GetSetting("mono/export/include_scripts_content");
-
-            if (!includeScriptsContent)
-            {
-                // We don't want to include the source code on exported games
-                AddFile(path, new byte[] { }, remap: false);
-                Skip();
-            }
-        }
-
-        public override void _ExportBegin(string[] features, bool isDebug, string path, int flags)
-        {
-            base._ExportBegin(features, isDebug, path, flags);
-
-            try
-            {
-                _ExportBeginImpl(features, isDebug, path, flags);
-            }
-            catch (Exception e)
-            {
-                GD.PushError($"Failed to export project. Exception message: {e.Message}");
-                Console.Error.WriteLine(e);
-            }
-        }
-
-        public void _ExportBeginImpl(string[] features, bool isDebug, string path, int flags)
-        {
-            // TODO Right now there is no way to stop the export process with an error
-
-            if (File.Exists(GodotSharpDirs.ProjectSlnPath))
-            {
-                string buildConfig = isDebug ? "Debug" : "Release";
-
-                string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}");
-                CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath);
-
-                AddFile(scriptsMetadataPath, scriptsMetadataPath);
-
-                // Turn export features into defines
-                var godotDefines = features;
-
-                if (!BuildManager.BuildProjectBlocking(buildConfig, godotDefines))
-                {
-                    GD.PushError("Failed to build project");
-                    return;
-                }
-
-                // Add dependency assemblies
-
-                var dependencies = new Godot.Collections.Dictionary<string, string>();
-
-                var projectDllName = (string) ProjectSettings.GetSetting("application/config/name");
-                if (projectDllName.Empty())
-                {
-                    projectDllName = "UnnamedProject";
-                }
-
-                string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig);
-                string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll");
-
-                dependencies[projectDllName] = projectDllSrcPath;
-
-                {
-                    string templatesDir = Internal.FullTemplatesDir;
-                    string androidBclDir = Path.Combine(templatesDir, "android-bcl");
-
-                    string customLibDir = features.Contains("Android") && Directory.Exists(androidBclDir) ? androidBclDir : string.Empty;
-
-                    GetExportedAssemblyDependencies(projectDllName, projectDllSrcPath, buildConfig, customLibDir, dependencies);
-                }
-
-                string apiConfig = isDebug ? "Debug" : "Release";
-                string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, apiConfig);
-
-                foreach (var dependency in dependencies)
-                {
-                    string dependSrcPath = dependency.Value;
-                    string dependDstPath = Path.Combine(resAssembliesDir, dependSrcPath.GetFile());
-                    AddFile(dependSrcPath, dependDstPath);
-                }
-            }
-
-            // Mono specific export template extras (data dir)
-            ExportDataDirectory(features, isDebug, path);
-        }
-
-        private static void ExportDataDirectory(IEnumerable<string> features, bool debug, string path)
-        {
-            var featureSet = new HashSet<string>(features);
-
-            if (!PlatformHasTemplateDir(featureSet))
-                return;
-
-            string templateDirName = "data.mono";
-
-            if (featureSet.Contains("Windows"))
-            {
-                templateDirName += ".windows";
-                templateDirName += featureSet.Contains("64") ? ".64" : ".32";
-            }
-            else if (featureSet.Contains("X11"))
-            {
-                templateDirName += ".x11";
-                templateDirName += featureSet.Contains("64") ? ".64" : ".32";
-            }
-            else
-            {
-                throw new NotSupportedException("Target platform not supported");
-            }
-
-            templateDirName += debug ? ".release_debug" : ".release";
-
-            string templateDirPath = Path.Combine(Internal.FullTemplatesDir, templateDirName);
-
-            if (!Directory.Exists(templateDirPath))
-                throw new FileNotFoundException("Data template directory not found");
-
-            string outputDir = new FileInfo(path).Directory?.FullName ??
-                               throw new FileNotFoundException("Base directory not found");
-
-            string outputDataDir = Path.Combine(outputDir, DataDirName);
-
-            if (Directory.Exists(outputDataDir))
-                Directory.Delete(outputDataDir, recursive: true); // Clean first
-
-            Directory.CreateDirectory(outputDataDir);
-
-            foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories))
-            {
-                Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1)));
-            }
-
-            foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories))
-            {
-                File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1)));
-            }
-        }
-
-        private static bool PlatformHasTemplateDir(IEnumerable<string> featureSet)
-        {
-            // OSX export templates are contained in a zip, so we place
-            // our custom template inside it and let Godot do the rest.
-            return !featureSet.Any(f => new[] {"OSX", "Android"}.Contains(f));
-        }
-
-        private static string DataDirName
-        {
-            get
-            {
-                var appName = (string) ProjectSettings.GetSetting("application/config/name");
-                string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false);
-                return $"data_{appNameSafe}";
-            }
-        }
-
-        private static void GetExportedAssemblyDependencies(string projectDllName, string projectDllSrcPath,
-            string buildConfig, string customLibDir, Godot.Collections.Dictionary<string, string> dependencies) =>
-            internal_GetExportedAssemblyDependencies(projectDllName, projectDllSrcPath, buildConfig, customLibDir, dependencies);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void internal_GetExportedAssemblyDependencies(string projectDllName, string projectDllSrcPath,
-            string buildConfig, string customLibDir, Godot.Collections.Dictionary<string, string> dependencies);
-    }
-}

+ 1 - 1
modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj

@@ -40,6 +40,7 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="Build\MsBuildFinder.cs" />
     <Compile Include="Build\MsBuildFinder.cs" />
+    <Compile Include="Export\ExportPlugin.cs" />
     <Compile Include="ExternalEditorId.cs" />
     <Compile Include="ExternalEditorId.cs" />
     <Compile Include="Ides\GodotIdeManager.cs" />
     <Compile Include="Ides\GodotIdeManager.cs" />
     <Compile Include="Ides\GodotIdeServer.cs" />
     <Compile Include="Ides\GodotIdeServer.cs" />
@@ -63,7 +64,6 @@
     <Compile Include="BuildInfo.cs" />
     <Compile Include="BuildInfo.cs" />
     <Compile Include="BuildTab.cs" />
     <Compile Include="BuildTab.cs" />
     <Compile Include="BottomPanel.cs" />
     <Compile Include="BottomPanel.cs" />
-    <Compile Include="GodotSharpExport.cs" />
     <Compile Include="CsProjOperations.cs" />
     <Compile Include="CsProjOperations.cs" />
     <Compile Include="Utils\CollectionExtensions.cs" />
     <Compile Include="Utils\CollectionExtensions.cs" />
   </ItemGroup>
   </ItemGroup>

+ 1 - 1
modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs

@@ -79,7 +79,7 @@ namespace GodotTools.Ides
                 {
                 {
                     MonoDevelop.Instance GetMonoDevelopInstance(string solutionPath)
                     MonoDevelop.Instance GetMonoDevelopInstance(string solutionPath)
                     {
                     {
-                        if (Utils.OS.IsOSX() && editor == ExternalEditorId.VisualStudioForMac)
+                        if (Utils.OS.IsOSX && editor == ExternalEditorId.VisualStudioForMac)
                         {
                         {
                             vsForMacInstance = vsForMacInstance ??
                             vsForMacInstance = vsForMacInstance ??
                                                new MonoDevelop.Instance(solutionPath, MonoDevelop.EditorId.VisualStudioForMac);
                                                new MonoDevelop.Instance(solutionPath, MonoDevelop.EditorId.VisualStudioForMac);

+ 3 - 3
modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs

@@ -24,7 +24,7 @@ namespace GodotTools.Ides.MonoDevelop
 
 
             string command;
             string command;
 
 
-            if (OS.IsOSX())
+            if (OS.IsOSX)
             {
             {
                 string bundleId = BundleIds[editorId];
                 string bundleId = BundleIds[editorId];
 
 
@@ -81,7 +81,7 @@ namespace GodotTools.Ides.MonoDevelop
 
 
         public Instance(string solutionFile, EditorId editorId)
         public Instance(string solutionFile, EditorId editorId)
         {
         {
-            if (editorId == EditorId.VisualStudioForMac && !OS.IsOSX())
+            if (editorId == EditorId.VisualStudioForMac && !OS.IsOSX)
                 throw new InvalidOperationException($"{nameof(EditorId.VisualStudioForMac)} not supported on this platform");
                 throw new InvalidOperationException($"{nameof(EditorId.VisualStudioForMac)} not supported on this platform");
 
 
             this.solutionFile = solutionFile;
             this.solutionFile = solutionFile;
@@ -93,7 +93,7 @@ namespace GodotTools.Ides.MonoDevelop
 
 
         static Instance()
         static Instance()
         {
         {
-            if (OS.IsOSX())
+            if (OS.IsOSX)
             {
             {
                 ExecutableNames = new Dictionary<EditorId, string>
                 ExecutableNames = new Dictionary<EditorId, string>
                 {
                 {

+ 49 - 27
modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs

@@ -1,56 +1,78 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 
 
 namespace GodotTools.Utils
 namespace GodotTools.Utils
 {
 {
+    [SuppressMessage("ReSharper", "InconsistentNaming")]
     public static class OS
     public static class OS
     {
     {
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
-        extern static string GetPlatformName();
+        static extern string GetPlatformName();
 
 
-        const string HaikuName = "Haiku";
-        const string OSXName = "OSX";
-        const string ServerName = "Server";
-        const string UWPName = "UWP";
-        const string WindowsName = "Windows";
-        const string X11Name = "X11";
-
-        public static bool IsHaiku()
+        public static class Names
         {
         {
-            return HaikuName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+            public const string Windows = "Windows";
+            public const string OSX = "OSX";
+            public const string X11 = "X11";
+            public const string Server = "Server";
+            public const string UWP = "UWP";
+            public const string Haiku = "Haiku";
+            public const string Android = "Android";
+            public const string HTML5 = "HTML5";
         }
         }
 
 
-        public static bool IsOSX()
+        public static class Platforms
         {
         {
-            return OSXName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+            public const string Windows = "windows";
+            public const string OSX = "osx";
+            public const string X11 = "x11";
+            public const string Server = "server";
+            public const string UWP = "uwp";
+            public const string Haiku = "haiku";
+            public const string Android = "android";
+            public const string HTML5 = "javascript";
         }
         }
 
 
-        public static bool IsServer()
+        public static readonly Dictionary<string, string> PlatformNameMap = new Dictionary<string, string>
         {
         {
-            return ServerName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
-        }
-
-        public static bool IsUWP()
+            [Names.Windows] = Platforms.Windows,
+            [Names.OSX] = Platforms.OSX,
+            [Names.X11] = Platforms.X11,
+            [Names.Server] = Platforms.Server,
+            [Names.UWP] = Platforms.UWP,
+            [Names.Haiku] = Platforms.Haiku,
+            [Names.Android] = Platforms.Android,
+            [Names.HTML5] = Platforms.HTML5
+        };
+
+        private static bool IsOS(string name)
         {
         {
-            return UWPName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+            return name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
         }
         }
 
 
-        public static bool IsWindows()
-        {
-            return WindowsName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
-        }
+        public static bool IsWindows() => IsOS(Names.Windows);
 
 
-        public static bool IsX11()
-        {
-            return X11Name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
-        }
+        public static bool IsOSX => IsOS(Names.OSX);
+
+        public static bool IsX11 => IsOS(Names.X11);
+
+        public static bool IsServer => IsOS(Names.Server);
+
+        public static bool IsUWP => IsOS(Names.UWP);
+
+        public static bool IsHaiku => IsOS(Names.Haiku);
+
+        public static bool IsAndroid => IsOS(Names.Android);
+
+        public static bool IsHTML5 => IsOS(Names.HTML5);
 
 
         private static bool? _isUnixCache;
         private static bool? _isUnixCache;
-        private static readonly string[] UnixPlatforms = {HaikuName, OSXName, ServerName, X11Name};
+        private static readonly string[] UnixPlatforms = {Names.OSX, Names.X11, Names.Server, Names.Haiku, Names.Android};
 
 
         public static bool IsUnix()
         public static bool IsUnix()
         {
         {

+ 6 - 6
modules/mono/editor/editor_internal_calls.cpp

@@ -219,15 +219,15 @@ int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObje
 	return err;
 	return err;
 }
 }
 
 
-uint32_t godot_icall_GodotSharpExport_GetExportedAssemblyDependencies(MonoString *p_project_dll_name, MonoString *p_project_dll_src_path,
-		MonoString *p_build_config, MonoString *p_custom_lib_dir, MonoObject *r_dependencies) {
+uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoString *p_project_dll_name, MonoString *p_project_dll_src_path,
+		MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_dependencies) {
 	String project_dll_name = GDMonoMarshal::mono_string_to_godot(p_project_dll_name);
 	String project_dll_name = GDMonoMarshal::mono_string_to_godot(p_project_dll_name);
 	String project_dll_src_path = GDMonoMarshal::mono_string_to_godot(p_project_dll_src_path);
 	String project_dll_src_path = GDMonoMarshal::mono_string_to_godot(p_project_dll_src_path);
 	String build_config = GDMonoMarshal::mono_string_to_godot(p_build_config);
 	String build_config = GDMonoMarshal::mono_string_to_godot(p_build_config);
-	String custom_lib_dir = GDMonoMarshal::mono_string_to_godot(p_custom_lib_dir);
+	String custom_bcl_dir = GDMonoMarshal::mono_string_to_godot(p_custom_bcl_dir);
 	Dictionary dependencies = GDMonoMarshal::mono_object_to_variant(r_dependencies);
 	Dictionary dependencies = GDMonoMarshal::mono_object_to_variant(r_dependencies);
 
 
-	return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_lib_dir, dependencies);
+	return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_bcl_dir, dependencies);
 }
 }
 
 
 MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) {
 MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) {
@@ -411,8 +411,8 @@ void register_editor_internal_calls() {
 	// ScriptClassParser
 	// ScriptClassParser
 	mono_add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", (void *)godot_icall_ScriptClassParser_ParseFile);
 	mono_add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", (void *)godot_icall_ScriptClassParser_ParseFile);
 
 
-	// GodotSharpExport
-	mono_add_internal_call("GodotTools.GodotSharpExport::internal_GetExportedAssemblyDependencies", (void *)godot_icall_GodotSharpExport_GetExportedAssemblyDependencies);
+	// ExportPlugin
+	mono_add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", (void *)godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
 
 
 	// Internals
 	// Internals
 	mono_add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", (void *)godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
 	mono_add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", (void *)godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);

+ 1 - 0
modules/mono/editor/godotsharp_export.cpp

@@ -36,6 +36,7 @@
 
 
 #include "../mono_gd/gd_mono.h"
 #include "../mono_gd/gd_mono.h"
 #include "../mono_gd/gd_mono_assembly.h"
 #include "../mono_gd/gd_mono_assembly.h"
+#include "../mono_gd/gd_mono_cache.h"
 
 
 namespace GodotSharpExport {
 namespace GodotSharpExport {
 
 

+ 1 - 0
modules/mono/glue/base_object_glue.cpp

@@ -36,6 +36,7 @@
 #include "core/string_name.h"
 #include "core/string_name.h"
 
 
 #include "../csharp_script.h"
 #include "../csharp_script.h"
+#include "../mono_gd/gd_mono_cache.h"
 #include "../mono_gd/gd_mono_class.h"
 #include "../mono_gd/gd_mono_class.h"
 #include "../mono_gd/gd_mono_internals.h"
 #include "../mono_gd/gd_mono_internals.h"
 #include "../mono_gd/gd_mono_utils.h"
 #include "../mono_gd/gd_mono_utils.h"

+ 1 - 0
modules/mono/glue/collections_glue.cpp

@@ -34,6 +34,7 @@
 
 
 #include <mono/metadata/exception.h>
 #include <mono/metadata/exception.h>
 
 
+#include "../mono_gd/gd_mono_cache.h"
 #include "../mono_gd/gd_mono_class.h"
 #include "../mono_gd/gd_mono_class.h"
 #include "../mono_gd/gd_mono_utils.h"
 #include "../mono_gd/gd_mono_utils.h"
 
 

+ 2 - 1
modules/mono/glue/gd_glue.cpp

@@ -39,6 +39,7 @@
 #include "core/variant.h"
 #include "core/variant.h"
 #include "core/variant_parser.h"
 #include "core/variant_parser.h"
 
 
+#include "../mono_gd/gd_mono_cache.h"
 #include "../mono_gd/gd_mono_utils.h"
 #include "../mono_gd/gd_mono_utils.h"
 
 
 MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
 MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
@@ -211,7 +212,7 @@ MonoString *godot_icall_GD_var2str(MonoObject *p_var) {
 }
 }
 
 
 MonoObject *godot_icall_DefaultGodotTaskScheduler() {
 MonoObject *godot_icall_DefaultGodotTaskScheduler() {
-	return GDMonoUtils::mono_cache.task_scheduler_handle->get_target();
+	return GDMonoCache::cached_data.task_scheduler_handle->get_target();
 }
 }
 
 
 void godot_register_gd_icalls() {
 void godot_register_gd_icalls() {

+ 4 - 0
modules/mono/godotsharp_dirs.cpp

@@ -130,7 +130,11 @@ private:
 		res_temp_assemblies_base_dir = res_temp_dir.plus_file("bin");
 		res_temp_assemblies_base_dir = res_temp_dir.plus_file("bin");
 		res_temp_assemblies_dir = res_temp_assemblies_base_dir.plus_file(_get_expected_build_config());
 		res_temp_assemblies_dir = res_temp_assemblies_base_dir.plus_file(_get_expected_build_config());
 
 
+#ifdef JAVASCRIPT_ENABLED
+		mono_user_dir = "user://";
+#else
 		mono_user_dir = _get_mono_user_dir();
 		mono_user_dir = _get_mono_user_dir();
+#endif
 		mono_logs_dir = mono_user_dir.plus_file("mono_logs");
 		mono_logs_dir = mono_user_dir.plus_file("mono_logs");
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED

+ 65 - 19
modules/mono/mono_gd/gd_mono.cpp

@@ -46,6 +46,7 @@
 #include "../csharp_script.h"
 #include "../csharp_script.h"
 #include "../godotsharp_dirs.h"
 #include "../godotsharp_dirs.h"
 #include "../utils/path_utils.h"
 #include "../utils/path_utils.h"
+#include "gd_mono_cache.h"
 #include "gd_mono_class.h"
 #include "gd_mono_class.h"
 #include "gd_mono_marshal.h"
 #include "gd_mono_marshal.h"
 #include "gd_mono_utils.h"
 #include "gd_mono_utils.h"
@@ -56,13 +57,26 @@
 
 
 #ifdef ANDROID_ENABLED
 #ifdef ANDROID_ENABLED
 #include "android_mono_config.h"
 #include "android_mono_config.h"
+#include "gd_mono_android.h"
 #endif
 #endif
 
 
+// TODO:
+// This has turn into a gigantic mess. There's too much going on here. Too much #ifdef as well.
+// It's just painful to read... It needs to be re-structured. Please, clean this up, future me.
+
 GDMono *GDMono::singleton = NULL;
 GDMono *GDMono::singleton = NULL;
 
 
 namespace {
 namespace {
 
 
-void setup_runtime_main_args() {
+#if defined(JAVASCRIPT_ENABLED)
+extern "C" {
+void mono_wasm_load_runtime(const char *managed_path, int enable_debugging);
+}
+#endif
+
+#if !defined(JAVASCRIPT_ENABLED)
+
+void gd_mono_setup_runtime_main_args() {
 	CharString execpath = OS::get_singleton()->get_executable_path().utf8();
 	CharString execpath = OS::get_singleton()->get_executable_path().utf8();
 
 
 	List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
 	List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
@@ -83,7 +97,7 @@ void setup_runtime_main_args() {
 	mono_runtime_set_main_args(main_args.size(), main_args.ptrw());
 	mono_runtime_set_main_args(main_args.size(), main_args.ptrw());
 }
 }
 
 
-void gdmono_profiler_init() {
+void gd_mono_profiler_init() {
 	String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd");
 	String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd");
 	bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false);
 	bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false);
 	if (profiler_enabled) {
 	if (profiler_enabled) {
@@ -91,9 +105,9 @@ void gdmono_profiler_init() {
 	}
 	}
 }
 }
 
 
-#ifdef DEBUG_ENABLED
+#if defined(DEBUG_ENABLED)
 
 
-bool _wait_for_debugger_msecs(uint32_t p_msecs) {
+bool gd_mono_wait_for_debugger_msecs(uint32_t p_msecs) {
 
 
 	do {
 	do {
 		if (mono_is_debugger_attached())
 		if (mono_is_debugger_attached())
@@ -115,7 +129,7 @@ bool _wait_for_debugger_msecs(uint32_t p_msecs) {
 	return mono_is_debugger_attached();
 	return mono_is_debugger_attached();
 }
 }
 
 
-void gdmono_debug_init() {
+void gd_mono_debug_init() {
 
 
 	mono_debug_init(MONO_DEBUG_FORMAT_MONO);
 	mono_debug_init(MONO_DEBUG_FORMAT_MONO);
 
 
@@ -151,11 +165,37 @@ void gdmono_debug_init() {
 	mono_jit_parse_options(2, (char **)options);
 	mono_jit_parse_options(2, (char **)options);
 }
 }
 
 
+#endif // defined(DEBUG_ENABLED)
+#endif // !defined(JAVASCRIPT_ENABLED)
+
+#if defined(JAVASCRIPT_ENABLED)
+MonoDomain *gd_initialize_mono_runtime() {
+	const char *vfs_prefix = "managed";
+	int enable_debugging = 0;
+
+#ifdef DEBUG_ENABLED
+	enable_debugging = 1;
+#endif
+
+	mono_wasm_load_runtime(vfs_prefix, enable_debugging);
+
+	return mono_get_root_domain();
+}
+#else
+MonoDomain *gd_initialize_mono_runtime() {
+#ifdef DEBUG_ENABLED
+	gd_mono_debug_init();
+#endif
+
+	return mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
+}
 #endif
 #endif
 
 
 } // namespace
 } // namespace
 
 
 void GDMono::add_mono_shared_libs_dir_to_path() {
 void GDMono::add_mono_shared_libs_dir_to_path() {
+	// TODO: Replace this with a mono_dl_fallback
+
 	// By default Mono seems to search shared libraries in the following directories:
 	// By default Mono seems to search shared libraries in the following directories:
 	// Current working directory, @executable_path@ and PATH
 	// Current working directory, @executable_path@ and PATH
 	// The parent directory of the image file (assembly where the dllimport method is declared)
 	// The parent directory of the image file (assembly where the dllimport method is declared)
@@ -279,11 +319,17 @@ void GDMono::initialize() {
 	config_dir = bundled_config_dir;
 	config_dir = bundled_config_dir;
 #endif // TOOLS_ENABLED
 #endif // TOOLS_ENABLED
 
 
+#if !defined(JAVASCRIPT_ENABLED)
 	// Leak if we call mono_set_dirs more than once
 	// Leak if we call mono_set_dirs more than once
 	mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL,
 	mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL,
 			config_dir.length() ? config_dir.utf8().get_data() : NULL);
 			config_dir.length() ? config_dir.utf8().get_data() : NULL);
 
 
 	add_mono_shared_libs_dir_to_path();
 	add_mono_shared_libs_dir_to_path();
+#endif
+
+#if defined(ANDROID_ENABLED)
+	GDMonoAndroid::register_android_dl_fallback();
+#endif
 
 
 	{
 	{
 		PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/unhandled_exception_policy", PROPERTY_HINT_ENUM,
 		PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/unhandled_exception_policy", PROPERTY_HINT_ENUM,
@@ -299,10 +345,8 @@ void GDMono::initialize() {
 
 
 	GDMonoAssembly::initialize();
 	GDMonoAssembly::initialize();
 
 
-	gdmono_profiler_init();
-
-#ifdef DEBUG_ENABLED
-	gdmono_debug_init();
+#if !defined(JAVASCRIPT_ENABLED)
+	gd_mono_profiler_init();
 #endif
 #endif
 
 
 #ifdef ANDROID_ENABLED
 #ifdef ANDROID_ENABLED
@@ -326,12 +370,14 @@ void GDMono::initialize() {
 	}
 	}
 #endif
 #endif
 
 
-	root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
+	root_domain = gd_initialize_mono_runtime();
 	ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime.");
 	ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime.");
 
 
 	GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread());
 	GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread());
 
 
-	setup_runtime_main_args(); // Required for System.Environment.GetCommandLineArgs
+#if !defined(JAVASCRIPT_ENABLED)
+	gd_mono_setup_runtime_main_args(); // Required for System.Environment.GetCommandLineArgs
+#endif
 
 
 	runtime_initialized = true;
 	runtime_initialized = true;
 
 
@@ -344,8 +390,8 @@ void GDMono::initialize() {
 	Error domain_load_err = _load_scripts_domain();
 	Error domain_load_err = _load_scripts_domain();
 	ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
 	ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
 
 
-#ifdef DEBUG_ENABLED
-	bool debugger_attached = _wait_for_debugger_msecs(500);
+#if defined(DEBUG_ENABLED) && !defined(JAVASCRIPT_ENABLED)
+	bool debugger_attached = gd_mono_wait_for_debugger_msecs(500);
 	if (!debugger_attached && OS::get_singleton()->is_stdout_verbose())
 	if (!debugger_attached && OS::get_singleton()->is_stdout_verbose())
 		print_error("Mono: Debugger wait timeout");
 		print_error("Mono: Debugger wait timeout");
 #endif
 #endif
@@ -381,7 +427,7 @@ void GDMono::initialize_load_assemblies() {
 }
 }
 
 
 bool GDMono::_are_api_assemblies_out_of_sync() {
 bool GDMono::_are_api_assemblies_out_of_sync() {
-	bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated);
+	bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoCache::cached_data.godot_api_cache_updated);
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	if (!out_of_sync)
 	if (!out_of_sync)
 		out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync;
 		out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync;
@@ -561,7 +607,7 @@ bool GDMono::_load_corlib_assembly() {
 	bool success = load_assembly("mscorlib", &corlib_assembly);
 	bool success = load_assembly("mscorlib", &corlib_assembly);
 
 
 	if (success)
 	if (success)
-		GDMonoUtils::update_corlib_cache();
+		GDMonoCache::update_corlib_cache();
 
 
 	return success;
 	return success;
 }
 }
@@ -834,9 +880,9 @@ bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, Lo
 }
 }
 
 
 bool GDMono::_on_core_api_assembly_loaded() {
 bool GDMono::_on_core_api_assembly_loaded() {
-	GDMonoUtils::update_godot_api_cache();
+	GDMonoCache::update_godot_api_cache();
 
 
-	if (!GDMonoUtils::mono_cache.godot_api_cache_updated)
+	if (!GDMonoCache::cached_data.godot_api_cache_updated)
 		return false;
 		return false;
 
 
 	get_singleton()->_install_trace_listener();
 	get_singleton()->_install_trace_listener();
@@ -884,7 +930,7 @@ void GDMono::_load_api_assemblies() {
 		if (_are_api_assemblies_out_of_sync()) {
 		if (_are_api_assemblies_out_of_sync()) {
 			if (core_api_assembly.out_of_sync) {
 			if (core_api_assembly.out_of_sync) {
 				ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync.");
 				ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync.");
-			} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
+			} else if (!GDMonoCache::cached_data.godot_api_cache_updated) {
 				ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed.");
 				ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed.");
 			}
 			}
 
 
@@ -984,7 +1030,7 @@ Error GDMono::_unload_scripts_domain() {
 
 
 	mono_gc_collect(mono_gc_max_generation());
 	mono_gc_collect(mono_gc_max_generation());
 
 
-	GDMonoUtils::clear_godot_api_cache();
+	GDMonoCache::clear_godot_api_cache();
 
 
 	_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
 	_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
 
 

+ 1 - 0
modules/mono/mono_gd/gd_mono_assembly.cpp

@@ -39,6 +39,7 @@
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 
 
 #include "../godotsharp_dirs.h"
 #include "../godotsharp_dirs.h"
+#include "gd_mono_cache.h"
 #include "gd_mono_class.h"
 #include "gd_mono_class.h"
 
 
 bool GDMonoAssembly::no_search = false;
 bool GDMonoAssembly::no_search = false;

+ 282 - 0
modules/mono/mono_gd/gd_mono_cache.cpp

@@ -0,0 +1,282 @@
+#include "gd_mono_cache.h"
+
+#include "gd_mono.h"
+#include "gd_mono_class.h"
+#include "gd_mono_marshal.h"
+#include "gd_mono_method.h"
+#include "gd_mono_utils.h"
+
+namespace GDMonoCache {
+
+CachedData cached_data;
+
+#define CACHE_AND_CHECK(m_var, m_val)                                               \
+	{                                                                               \
+		CRASH_COND(m_var != NULL);                                                  \
+		m_var = m_val;                                                              \
+		ERR_FAIL_COND_MSG(m_var == NULL, "Mono Cache: Member " #m_var " is null."); \
+	}
+
+#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_class, m_val)
+#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_ns##_##m_class, m_val)
+#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.rawclass_##m_class, m_val)
+#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(cached_data.field_##m_class##_##m_field, m_val)
+#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(cached_data.method_##m_class##_##m_method, m_val)
+#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(cached_data.property_##m_class##_##m_property, m_val)
+
+#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val)                                        \
+	{                                                                                          \
+		CRASH_COND(!m_var.is_null());                                                          \
+		ERR_FAIL_COND_MSG(m_val == NULL, "Mono Cache: Method for member " #m_var " is null."); \
+		m_var.set_from_method(m_val);                                                          \
+		ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null.");          \
+	}
+
+#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_METHOD_THUNK_AND_CHECK_IMPL(cached_data.methodthunk_##m_class##_##m_method, m_val)
+
+void CachedData::clear_corlib_cache() {
+
+	corlib_cache_updated = false;
+
+	class_MonoObject = NULL;
+	class_bool = NULL;
+	class_int8_t = NULL;
+	class_int16_t = NULL;
+	class_int32_t = NULL;
+	class_int64_t = NULL;
+	class_uint8_t = NULL;
+	class_uint16_t = NULL;
+	class_uint32_t = NULL;
+	class_uint64_t = NULL;
+	class_float = NULL;
+	class_double = NULL;
+	class_String = NULL;
+	class_IntPtr = NULL;
+
+	class_System_Collections_IEnumerable = NULL;
+	class_System_Collections_IDictionary = NULL;
+
+#ifdef DEBUG_ENABLED
+	class_System_Diagnostics_StackTrace = NULL;
+	methodthunk_System_Diagnostics_StackTrace_GetFrames.nullify();
+	method_System_Diagnostics_StackTrace_ctor_bool = NULL;
+	method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL;
+#endif
+
+	class_KeyNotFoundException = NULL;
+}
+
+void CachedData::clear_godot_api_cache() {
+
+	godot_api_cache_updated = false;
+
+	rawclass_Dictionary = NULL;
+
+	class_Vector2 = NULL;
+	class_Rect2 = NULL;
+	class_Transform2D = NULL;
+	class_Vector3 = NULL;
+	class_Basis = NULL;
+	class_Quat = NULL;
+	class_Transform = NULL;
+	class_AABB = NULL;
+	class_Color = NULL;
+	class_Plane = NULL;
+	class_NodePath = NULL;
+	class_RID = NULL;
+	class_GodotObject = NULL;
+	class_GodotResource = NULL;
+	class_Node = NULL;
+	class_Control = NULL;
+	class_Spatial = NULL;
+	class_WeakRef = NULL;
+	class_Array = NULL;
+	class_Dictionary = NULL;
+	class_MarshalUtils = NULL;
+	class_ISerializationListener = NULL;
+
+#ifdef DEBUG_ENABLED
+	class_DebuggingUtils = NULL;
+	methodthunk_DebuggingUtils_GetStackFrameInfo.nullify();
+#endif
+
+	class_ExportAttribute = NULL;
+	field_ExportAttribute_hint = NULL;
+	field_ExportAttribute_hintString = NULL;
+	class_SignalAttribute = NULL;
+	class_ToolAttribute = NULL;
+	class_RemoteAttribute = NULL;
+	class_SyncAttribute = NULL;
+	class_MasterAttribute = NULL;
+	class_PuppetAttribute = NULL;
+	class_SlaveAttribute = NULL;
+	class_RemoteSyncAttribute = NULL;
+	class_MasterSyncAttribute = NULL;
+	class_PuppetSyncAttribute = NULL;
+	class_GodotMethodAttribute = NULL;
+	field_GodotMethodAttribute_methodName = NULL;
+
+	field_GodotObject_ptr = NULL;
+	field_NodePath_ptr = NULL;
+	field_Image_ptr = NULL;
+	field_RID_ptr = NULL;
+
+	methodthunk_GodotObject_Dispose.nullify();
+	methodthunk_Array_GetPtr.nullify();
+	methodthunk_Dictionary_GetPtr.nullify();
+	methodthunk_SignalAwaiter_SignalCallback.nullify();
+	methodthunk_SignalAwaiter_FailureCallback.nullify();
+	methodthunk_GodotTaskScheduler_Activate.nullify();
+
+	// Start of MarshalUtils methods
+
+	methodthunk_MarshalUtils_TypeIsGenericArray.nullify();
+	methodthunk_MarshalUtils_TypeIsGenericDictionary.nullify();
+
+	methodthunk_MarshalUtils_ArrayGetElementType.nullify();
+	methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();
+
+	methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType.nullify();
+	methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType.nullify();
+	methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info.nullify();
+	methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info.nullify();
+
+	methodthunk_MarshalUtils_MakeGenericArrayType.nullify();
+	methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify();
+
+	methodthunk_MarshalUtils_EnumerableToArray.nullify();
+	methodthunk_MarshalUtils_IDictionaryToDictionary.nullify();
+	methodthunk_MarshalUtils_GenericIDictionaryToDictionary.nullify();
+
+	// End of MarshalUtils methods
+
+	task_scheduler_handle = Ref<MonoGCHandle>();
+}
+
+#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
+#define GODOT_API_NS_CLASS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class))
+
+void update_corlib_cache() {
+
+	CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class()));
+	CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class()));
+	CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class()));
+	CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class()));
+	CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class()));
+	CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class()));
+	CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class()));
+	CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class()));
+	CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class()));
+	CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class()));
+	CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class()));
+	CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class()));
+	CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
+	CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
+
+	CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
+	CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
+
+#ifdef DEBUG_ENABLED
+	CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace"));
+	CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method("GetFrames"));
+	CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true));
+	CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
+#endif
+
+	CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException"));
+
+	cached_data.corlib_cache_updated = true;
+}
+
+void update_godot_api_cache() {
+
+	CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2));
+	CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2));
+	CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
+	CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
+	CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
+	CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat));
+	CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform));
+	CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB));
+	CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
+	CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
+	CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
+	CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID));
+	CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
+	CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource));
+	CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
+	CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
+	CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
+	CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
+	CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array));
+	CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary));
+	CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
+	CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener));
+
+#ifdef DEBUG_ENABLED
+	CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils));
+#endif
+
+	// Attributes
+	CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
+	CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
+	CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
+	CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute));
+	CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
+	CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
+	CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute));
+	CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute));
+	CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute));
+	CACHE_CLASS_AND_CHECK(SlaveAttribute, GODOT_API_CLASS(SlaveAttribute));
+	CACHE_CLASS_AND_CHECK(RemoteSyncAttribute, GODOT_API_CLASS(RemoteSyncAttribute));
+	CACHE_CLASS_AND_CHECK(MasterSyncAttribute, GODOT_API_CLASS(MasterSyncAttribute));
+	CACHE_CLASS_AND_CHECK(PuppetSyncAttribute, GODOT_API_CLASS(PuppetSyncAttribute));
+	CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
+	CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
+
+	CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
+	CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
+	CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
+
+	CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, CACHED_CLASS(GodotObject)->get_method("Dispose", 0));
+	CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method("GetPtr", 0));
+	CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method("GetPtr", 0));
+	CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1));
+	CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0));
+	CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0));
+
+	// Start of MarshalUtils methods
+
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1));
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericDictionary", 1));
+
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2));
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3));
+
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIEnumerableIsAssignableFromType", 1));
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryIsAssignableFromType", 1));
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIEnumerableIsAssignableFromType", 2));
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryIsAssignableFromType", 3));
+
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericArrayType", 1));
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericDictionaryType", 2));
+
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, GODOT_API_CLASS(MarshalUtils)->get_method("EnumerableToArray", 2));
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("IDictionaryToDictionary", 2));
+	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryToDictionary", 2));
+
+	// End of MarshalUtils methods
+
+#ifdef DEBUG_ENABLED
+	CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4));
+#endif
+
+	// TODO Move to CSharpLanguage::init() and do handle disposal
+	MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
+	GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler));
+	cached_data.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
+
+	cached_data.godot_api_cache_updated = true;
+}
+
+} // namespace GDMonoCache

+ 174 - 0
modules/mono/mono_gd/gd_mono_cache.h

@@ -0,0 +1,174 @@
+#ifndef GD_MONO_CACHE_H
+#define GD_MONO_CACHE_H
+
+#include "gd_mono_header.h"
+#include "gd_mono_method_thunk.h"
+
+namespace GDMonoCache {
+
+struct CachedData {
+
+	// -----------------------------------------------
+	// corlib classes
+
+	// Let's use the no-namespace format for these too
+	GDMonoClass *class_MonoObject;
+	GDMonoClass *class_bool;
+	GDMonoClass *class_int8_t;
+	GDMonoClass *class_int16_t;
+	GDMonoClass *class_int32_t;
+	GDMonoClass *class_int64_t;
+	GDMonoClass *class_uint8_t;
+	GDMonoClass *class_uint16_t;
+	GDMonoClass *class_uint32_t;
+	GDMonoClass *class_uint64_t;
+	GDMonoClass *class_float;
+	GDMonoClass *class_double;
+	GDMonoClass *class_String;
+	GDMonoClass *class_IntPtr;
+
+	GDMonoClass *class_System_Collections_IEnumerable;
+	GDMonoClass *class_System_Collections_IDictionary;
+
+#ifdef DEBUG_ENABLED
+	GDMonoClass *class_System_Diagnostics_StackTrace;
+	GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames;
+	GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool;
+	GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
+#endif
+
+	GDMonoClass *class_KeyNotFoundException;
+
+	MonoClass *rawclass_Dictionary;
+	// -----------------------------------------------
+
+	GDMonoClass *class_Vector2;
+	GDMonoClass *class_Rect2;
+	GDMonoClass *class_Transform2D;
+	GDMonoClass *class_Vector3;
+	GDMonoClass *class_Basis;
+	GDMonoClass *class_Quat;
+	GDMonoClass *class_Transform;
+	GDMonoClass *class_AABB;
+	GDMonoClass *class_Color;
+	GDMonoClass *class_Plane;
+	GDMonoClass *class_NodePath;
+	GDMonoClass *class_RID;
+	GDMonoClass *class_GodotObject;
+	GDMonoClass *class_GodotResource;
+	GDMonoClass *class_Node;
+	GDMonoClass *class_Control;
+	GDMonoClass *class_Spatial;
+	GDMonoClass *class_WeakRef;
+	GDMonoClass *class_Array;
+	GDMonoClass *class_Dictionary;
+	GDMonoClass *class_MarshalUtils;
+	GDMonoClass *class_ISerializationListener;
+
+#ifdef DEBUG_ENABLED
+	GDMonoClass *class_DebuggingUtils;
+	GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo;
+#endif
+
+	GDMonoClass *class_ExportAttribute;
+	GDMonoField *field_ExportAttribute_hint;
+	GDMonoField *field_ExportAttribute_hintString;
+	GDMonoClass *class_SignalAttribute;
+	GDMonoClass *class_ToolAttribute;
+	GDMonoClass *class_RemoteAttribute;
+	GDMonoClass *class_SyncAttribute;
+	GDMonoClass *class_RemoteSyncAttribute;
+	GDMonoClass *class_MasterSyncAttribute;
+	GDMonoClass *class_PuppetSyncAttribute;
+	GDMonoClass *class_MasterAttribute;
+	GDMonoClass *class_PuppetAttribute;
+	GDMonoClass *class_SlaveAttribute;
+	GDMonoClass *class_GodotMethodAttribute;
+	GDMonoField *field_GodotMethodAttribute_methodName;
+
+	GDMonoField *field_GodotObject_ptr;
+	GDMonoField *field_NodePath_ptr;
+	GDMonoField *field_Image_ptr;
+	GDMonoField *field_RID_ptr;
+
+	GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose;
+	GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr;
+	GDMonoMethodThunkR<Dictionary *, MonoObject *> methodthunk_Dictionary_GetPtr;
+	GDMonoMethodThunk<MonoObject *, MonoArray *> methodthunk_SignalAwaiter_SignalCallback;
+	GDMonoMethodThunk<MonoObject *> methodthunk_SignalAwaiter_FailureCallback;
+	GDMonoMethodThunk<MonoObject *> methodthunk_GodotTaskScheduler_Activate;
+
+	// Start of MarshalUtils methods
+
+	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray;
+	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericDictionary;
+
+	GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
+	GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
+
+	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType;
+	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType;
+	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info;
+	GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info;
+
+	GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType;
+	GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType;
+
+	GDMonoMethodThunk<MonoObject *, Array *> methodthunk_MarshalUtils_EnumerableToArray;
+	GDMonoMethodThunk<MonoObject *, Dictionary *> methodthunk_MarshalUtils_IDictionaryToDictionary;
+	GDMonoMethodThunk<MonoObject *, Dictionary *> methodthunk_MarshalUtils_GenericIDictionaryToDictionary;
+
+	// End of MarshalUtils methods
+
+	Ref<MonoGCHandle> task_scheduler_handle;
+
+	bool corlib_cache_updated;
+	bool godot_api_cache_updated;
+
+	void clear_corlib_cache();
+	void clear_godot_api_cache();
+
+	CachedData() {
+		clear_corlib_cache();
+		clear_godot_api_cache();
+	}
+};
+
+extern CachedData cached_data;
+
+void update_corlib_cache();
+void update_godot_api_cache();
+
+inline void clear_corlib_cache() {
+	cached_data.clear_corlib_cache();
+}
+
+inline void clear_godot_api_cache() {
+	cached_data.clear_godot_api_cache();
+}
+
+_FORCE_INLINE_ bool tools_godot_api_check() {
+#ifdef TOOLS_ENABLED
+	return cached_data.godot_api_cache_updated;
+#else
+	return true; // Assume it's updated if this was called, otherwise it's a bug
+#endif
+}
+
+} // namespace GDMonoCache
+
+#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class)
+#define CACHED_CLASS_RAW(m_class) (GDMonoCache::cached_data.class_##m_class->get_mono_ptr())
+#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoCache::cached_data.rawclass_##m_class)
+#define CACHED_FIELD(m_class, m_field) (GDMonoCache::cached_data.field_##m_class##_##m_field)
+#define CACHED_METHOD(m_class, m_method) (GDMonoCache::cached_data.method_##m_class##_##m_method)
+#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoCache::cached_data.methodthunk_##m_class##_##m_method)
+#define CACHED_PROPERTY(m_class, m_property) (GDMonoCache::cached_data.property_##m_class##_##m_property)
+
+#ifdef REAL_T_IS_DOUBLE
+#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
+#else
+#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float)
+#endif
+
+#endif // GD_MONO_CACHE_H

+ 1 - 6
modules/mono/mono_gd/gd_mono_class.cpp

@@ -33,6 +33,7 @@
 #include <mono/metadata/attrdefs.h>
 #include <mono/metadata/attrdefs.h>
 
 
 #include "gd_mono_assembly.h"
 #include "gd_mono_assembly.h"
+#include "gd_mono_cache.h"
 #include "gd_mono_marshal.h"
 #include "gd_mono_marshal.h"
 
 
 String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
 String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
@@ -332,12 +333,6 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo
 	return get_method(method);
 	return get_method(method);
 }
 }
 
 
-void *GDMonoClass::get_method_thunk(const StringName &p_name, int p_params_count) {
-
-	GDMonoMethod *method = get_method(p_name, p_params_count);
-	return method ? method->get_thunk() : NULL;
-}
-
 GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
 GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
 
 
 	Map<StringName, GDMonoField *>::Element *result = fields.find(p_name);
 	Map<StringName, GDMonoField *>::Element *result = fields.find(p_name);

+ 0 - 2
modules/mono/mono_gd/gd_mono_class.h

@@ -144,8 +144,6 @@ public:
 	GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count);
 	GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count);
 	GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace);
 	GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace);
 
 
-	void *get_method_thunk(const StringName &p_name, int p_params_count = 0);
-
 	GDMonoField *get_field(const StringName &p_name);
 	GDMonoField *get_field(const StringName &p_name);
 	const Vector<GDMonoField *> &get_all_fields();
 	const Vector<GDMonoField *> &get_all_fields();
 
 

+ 4 - 2
modules/mono/mono_gd/gd_mono_field.cpp

@@ -32,8 +32,10 @@
 
 
 #include <mono/metadata/attrdefs.h>
 #include <mono/metadata/attrdefs.h>
 
 
+#include "gd_mono_cache.h"
 #include "gd_mono_class.h"
 #include "gd_mono_class.h"
 #include "gd_mono_marshal.h"
 #include "gd_mono_marshal.h"
+#include "gd_mono_utils.h"
 
 
 void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
 void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
 	mono_field_set_value(p_object, mono_field, &p_ptr);
 	mono_field_set_value(p_object, mono_field, &p_ptr);
@@ -337,7 +339,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 			}
 			}
 
 
 			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
 			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
-				if (GDMonoUtils::tools_godot_api_check()) {
+				if (GDMonoCache::tools_godot_api_check()) {
 					MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
 					MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
 					mono_field_set_value(p_object, mono_field, managed);
 					mono_field_set_value(p_object, mono_field, managed);
 					break;
 					break;
@@ -491,7 +493,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 			}
 			}
 
 
 			if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
 			if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
-				if (GDMonoUtils::tools_godot_api_check()) {
+				if (GDMonoCache::tools_godot_api_check()) {
 					MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
 					MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
 					mono_field_set_value(p_object, mono_field, managed);
 					mono_field_set_value(p_object, mono_field, managed);
 					break;
 					break;

+ 6 - 0
modules/mono/mono_gd/gd_mono_header.h

@@ -33,6 +33,12 @@
 
 
 #include "core/int_types.h"
 #include "core/int_types.h"
 
 
+#ifdef WIN32
+#define GD_MONO_STDCALL __stdcall
+#else
+#define GD_MONO_STDCALL
+#endif
+
 class GDMonoAssembly;
 class GDMonoAssembly;
 class GDMonoClass;
 class GDMonoClass;
 class GDMonoField;
 class GDMonoField;

+ 45 - 18
modules/mono/mono_gd/gd_mono_log.cpp

@@ -30,7 +30,6 @@
 
 
 #include "gd_mono_log.h"
 #include "gd_mono_log.h"
 
 
-#include <mono/utils/mono-logger.h>
 #include <stdlib.h> // abort
 #include <stdlib.h> // abort
 
 
 #include "core/os/dir_access.h"
 #include "core/os/dir_access.h"
@@ -39,7 +38,19 @@
 #include "../godotsharp_dirs.h"
 #include "../godotsharp_dirs.h"
 #include "../utils/string_utils.h"
 #include "../utils/string_utils.h"
 
 
-static int log_level_get_id(const char *p_log_level) {
+static CharString get_default_log_level() {
+#ifdef DEBUG_ENABLED
+	return String("info").utf8();
+#else
+	return String("warning").utf8();
+#endif
+}
+
+GDMonoLog *GDMonoLog::singleton = NULL;
+
+#if !defined(JAVASCRIPT_ENABLED)
+
+static int get_log_level_id(const char *p_log_level) {
 
 
 	const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", NULL };
 	const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", NULL };
 
 
@@ -53,11 +64,11 @@ static int log_level_get_id(const char *p_log_level) {
 	return -1;
 	return -1;
 }
 }
 
 
-static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
+void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) {
 
 
-	FileAccess *f = GDMonoLog::get_singleton()->get_log_file();
+	FileAccess *f = GDMonoLog::get_singleton()->log_file;
 
 
-	if (GDMonoLog::get_singleton()->get_log_level_id() >= log_level_get_id(log_level)) {
+	if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) {
 		String text(message);
 		String text(message);
 		text += " (in domain ";
 		text += " (in domain ";
 		text += log_domain;
 		text += log_domain;
@@ -72,7 +83,7 @@ static void mono_log_callback(const char *log_domain, const char *log_level, con
 	}
 	}
 
 
 	if (fatal) {
 	if (fatal) {
-		ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: '" + GDMonoLog::get_singleton()->get_log_file_path() + "'.");
+		ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'.");
 		// Make sure to flush before aborting
 		// Make sure to flush before aborting
 		f->flush();
 		f->flush();
 		f->close();
 		f->close();
@@ -82,8 +93,6 @@ static void mono_log_callback(const char *log_domain, const char *log_level, con
 	}
 	}
 }
 }
 
 
-GDMonoLog *GDMonoLog::singleton = NULL;
-
 bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
 bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
 
 
 	if (!DirAccess::exists(p_logs_dir)) {
 	if (!DirAccess::exists(p_logs_dir)) {
@@ -129,17 +138,13 @@ void GDMonoLog::initialize() {
 
 
 	CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
 	CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
 
 
-	if (log_level.length() != 0 && log_level_get_id(log_level.get_data()) == -1) {
+	if (log_level.length() != 0 && get_log_level_id(log_level.get_data()) == -1) {
 		ERR_PRINTS(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): '" + log_level.get_data() + "'.");
 		ERR_PRINTS(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): '" + log_level.get_data() + "'.");
 		log_level = CharString();
 		log_level = CharString();
 	}
 	}
 
 
 	if (log_level.length() == 0) {
 	if (log_level.length() == 0) {
-#ifdef DEBUG_ENABLED
-		log_level = String("info").utf8();
-#else
-		log_level = String("warning").utf8();
-#endif
+		log_level = get_default_log_level();
 	}
 	}
 
 
 	String logs_dir = GodotSharpDirs::get_mono_logs_dir();
 	String logs_dir = GodotSharpDirs::get_mono_logs_dir();
@@ -149,11 +154,14 @@ void GDMonoLog::initialize() {
 
 
 		OS::Date date_now = OS::get_singleton()->get_date();
 		OS::Date date_now = OS::get_singleton()->get_date();
 		OS::Time time_now = OS::get_singleton()->get_time();
 		OS::Time time_now = OS::get_singleton()->get_time();
-		int pid = OS::get_singleton()->get_process_id();
 
 
-		String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d (%d).txt",
+		String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d",
 				date_now.year, date_now.month, date_now.day,
 				date_now.year, date_now.month, date_now.day,
-				time_now.hour, time_now.min, time_now.sec, pid);
+				time_now.hour, time_now.min, time_now.sec);
+
+		log_file_name += str_format(" (%d)", OS::get_singleton()->get_process_id());
+
+		log_file_name += ".txt";
 
 
 		log_file_path = logs_dir.plus_file(log_file_name);
 		log_file_path = logs_dir.plus_file(log_file_name);
 
 
@@ -164,7 +172,7 @@ void GDMonoLog::initialize() {
 	}
 	}
 
 
 	mono_trace_set_level_string(log_level.get_data());
 	mono_trace_set_level_string(log_level.get_data());
-	log_level_id = log_level_get_id(log_level.get_data());
+	log_level_id = get_log_level_id(log_level.get_data());
 
 
 	if (log_file) {
 	if (log_file) {
 		OS::get_singleton()->print("Mono: Logfile is: %s\n", log_file_path.utf8().get_data());
 		OS::get_singleton()->print("Mono: Logfile is: %s\n", log_file_path.utf8().get_data());
@@ -190,3 +198,22 @@ GDMonoLog::~GDMonoLog() {
 		memdelete(log_file);
 		memdelete(log_file);
 	}
 	}
 }
 }
+
+#else
+
+void GDMonoLog::initialize() {
+	CharString log_level = get_default_log_level();
+	mono_trace_set_level_string(log_level.get_data());
+}
+
+GDMonoLog::GDMonoLog() {
+
+	singleton = this;
+}
+
+GDMonoLog::~GDMonoLog() {
+
+	singleton = NULL;
+}
+
+#endif // !defined(JAVASCRIPT_ENABLED)

+ 10 - 4
modules/mono/mono_gd/gd_mono_log.h

@@ -31,10 +31,17 @@
 #ifndef GD_MONO_LOG_H
 #ifndef GD_MONO_LOG_H
 #define GD_MONO_LOG_H
 #define GD_MONO_LOG_H
 
 
+#include <mono/utils/mono-logger.h>
+
+#include "core/typedefs.h"
+
+#if !defined(JAVASCRIPT_ENABLED)
 #include "core/os/file_access.h"
 #include "core/os/file_access.h"
+#endif
 
 
 class GDMonoLog {
 class GDMonoLog {
 
 
+#if !defined(JAVASCRIPT_ENABLED)
 	int log_level_id;
 	int log_level_id;
 
 
 	FileAccess *log_file;
 	FileAccess *log_file;
@@ -43,6 +50,9 @@ class GDMonoLog {
 	bool _try_create_logs_dir(const String &p_logs_dir);
 	bool _try_create_logs_dir(const String &p_logs_dir);
 	void _delete_old_log_files(const String &p_logs_dir);
 	void _delete_old_log_files(const String &p_logs_dir);
 
 
+	static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data);
+#endif
+
 	static GDMonoLog *singleton;
 	static GDMonoLog *singleton;
 
 
 public:
 public:
@@ -50,10 +60,6 @@ public:
 
 
 	void initialize();
 	void initialize();
 
 
-	_FORCE_INLINE_ FileAccess *get_log_file() { return log_file; }
-	_FORCE_INLINE_ String get_log_file_path() { return log_file_path; }
-	_FORCE_INLINE_ int get_log_level_id() { return log_level_id; }
-
 	GDMonoLog();
 	GDMonoLog();
 	~GDMonoLog();
 	~GDMonoLog();
 };
 };

+ 5 - 4
modules/mono/mono_gd/gd_mono_marshal.cpp

@@ -31,6 +31,7 @@
 #include "gd_mono_marshal.h"
 #include "gd_mono_marshal.h"
 
 
 #include "gd_mono.h"
 #include "gd_mono.h"
+#include "gd_mono_cache.h"
 #include "gd_mono_class.h"
 #include "gd_mono_class.h"
 
 
 namespace GDMonoMarshal {
 namespace GDMonoMarshal {
@@ -556,7 +557,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 			}
 			}
 
 
 			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
 			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
-				if (GDMonoUtils::tools_godot_api_check()) {
+				if (GDMonoCache::tools_godot_api_check()) {
 					return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
 					return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
 				} else {
 				} else {
 					return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array());
 					return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array());
@@ -683,7 +684,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 				}
 				}
 
 
 				if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
 				if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
-					if (GDMonoUtils::tools_godot_api_check()) {
+					if (GDMonoCache::tools_godot_api_check()) {
 						return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
 						return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
 					} else {
 					} else {
 						return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array());
 						return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array());
@@ -834,14 +835,14 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 
 
 			if (CACHED_CLASS(Array) == type_class) {
 			if (CACHED_CLASS(Array) == type_class) {
 				MonoException *exc = NULL;
 				MonoException *exc = NULL;
-				Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc);
+				Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc);
 				UNHANDLED_EXCEPTION(exc);
 				UNHANDLED_EXCEPTION(exc);
 				return ptr ? Variant(*ptr) : Variant();
 				return ptr ? Variant(*ptr) : Variant();
 			}
 			}
 
 
 			if (CACHED_CLASS(Dictionary) == type_class) {
 			if (CACHED_CLASS(Dictionary) == type_class) {
 				MonoException *exc = NULL;
 				MonoException *exc = NULL;
-				Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc);
+				Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc);
 				UNHANDLED_EXCEPTION(exc);
 				UNHANDLED_EXCEPTION(exc);
 				return ptr ? Variant(*ptr) : Variant();
 				return ptr ? Variant(*ptr) : Variant();
 			}
 			}

+ 5 - 0
modules/mono/mono_gd/gd_mono_marshal.h

@@ -43,6 +43,11 @@ T unbox(MonoObject *p_obj) {
 	return *(T *)mono_object_unbox(p_obj);
 	return *(T *)mono_object_unbox(p_obj);
 }
 }
 
 
+template <typename T>
+T *unbox_addr(MonoObject *p_obj) {
+	return (T *)mono_object_unbox(p_obj);
+}
+
 #define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x)
 #define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x)
 #define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x)
 #define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x)
 #define BOX_INT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int64_t), &x)
 #define BOX_INT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int64_t), &x)

+ 2 - 4
modules/mono/mono_gd/gd_mono_method.cpp

@@ -30,8 +30,10 @@
 
 
 #include "gd_mono_method.h"
 #include "gd_mono_method.h"
 
 
+#include "gd_mono_cache.h"
 #include "gd_mono_class.h"
 #include "gd_mono_class.h"
 #include "gd_mono_marshal.h"
 #include "gd_mono_marshal.h"
+#include "gd_mono_utils.h"
 
 
 #include <mono/metadata/attrdefs.h>
 #include <mono/metadata/attrdefs.h>
 
 
@@ -99,10 +101,6 @@ IMonoClassMember::Visibility GDMonoMethod::get_visibility() {
 	}
 	}
 }
 }
 
 
-void *GDMonoMethod::get_thunk() {
-	return mono_method_get_unmanaged_thunk(mono_method);
-}
-
 MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) {
 MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) {
 	if (get_return_type().type_encoding != MONO_TYPE_VOID || get_parameters_count() > 0) {
 	if (get_return_type().type_encoding != MONO_TYPE_VOID || get_parameters_count() > 0) {
 		MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
 		MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());

+ 2 - 2
modules/mono/mono_gd/gd_mono_method.h

@@ -71,11 +71,11 @@ public:
 	virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
 	virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
 	void fetch_attributes();
 	void fetch_attributes();
 
 
+	_FORCE_INLINE_ MonoMethod *get_mono_ptr() { return mono_method; }
+
 	_FORCE_INLINE_ int get_parameters_count() { return params_count; }
 	_FORCE_INLINE_ int get_parameters_count() { return params_count; }
 	_FORCE_INLINE_ ManagedType get_return_type() { return return_type; }
 	_FORCE_INLINE_ ManagedType get_return_type() { return return_type; }
 
 
-	void *get_thunk();
-
 	MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = NULL);
 	MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = NULL);
 	MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = NULL);
 	MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = NULL);
 	MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL);
 	MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL);

+ 302 - 0
modules/mono/mono_gd/gd_mono_method_thunk.h

@@ -0,0 +1,302 @@
+#ifndef GD_MONO_METHOD_THUNK_H
+#define GD_MONO_METHOD_THUNK_H
+
+#include <type_traits>
+
+#include "gd_mono_class.h"
+#include "gd_mono_header.h"
+#include "gd_mono_marshal.h"
+#include "gd_mono_method.h"
+#include "gd_mono_utils.h"
+
+#if !defined(JAVASCRIPT_ENABLED)
+#define HAVE_METHOD_THUNKS
+#endif
+
+#ifdef HAVE_METHOD_THUNKS
+
+template <class... ParamTypes>
+struct GDMonoMethodThunk {
+
+	typedef void(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **);
+
+	M mono_method_thunk;
+
+public:
+	_FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) {
+		GD_MONO_BEGIN_RUNTIME_INVOKE;
+		mono_method_thunk(p_args..., r_exc);
+		GD_MONO_END_RUNTIME_INVOKE;
+	}
+
+	_FORCE_INLINE_ bool is_null() {
+		return mono_method_thunk == NULL;
+	}
+
+	_FORCE_INLINE_ void nullify() {
+		mono_method_thunk = NULL;
+	}
+
+	_FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
+#ifdef DEBUG_ENABLED
+		CRASH_COND(p_mono_method == NULL);
+		CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID);
+
+		if (p_mono_method->is_static()) {
+			CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
+		} else {
+			CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
+		}
+#endif
+		mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
+	}
+
+	GDMonoMethodThunk() :
+			mono_method_thunk(NULL) {
+	}
+
+	explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) {
+		set_from_method(p_mono_method);
+	}
+};
+
+template <class R, class... ParamTypes>
+struct GDMonoMethodThunkR {
+
+	typedef R(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **);
+
+	M mono_method_thunk;
+
+public:
+	_FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) {
+		GD_MONO_BEGIN_RUNTIME_INVOKE;
+		R r = mono_method_thunk(p_args..., r_exc);
+		GD_MONO_END_RUNTIME_INVOKE;
+		return r;
+	}
+
+	_FORCE_INLINE_ bool is_null() {
+		return mono_method_thunk == NULL;
+	}
+
+	_FORCE_INLINE_ void nullify() {
+		mono_method_thunk = NULL;
+	}
+
+	_FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
+#ifdef DEBUG_ENABLED
+		CRASH_COND(p_mono_method == NULL);
+		CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID);
+
+		if (p_mono_method->is_static()) {
+			CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
+		} else {
+			CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
+		}
+#endif
+		mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
+	}
+
+	GDMonoMethodThunkR() :
+			mono_method_thunk(NULL) {
+	}
+
+	explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) {
+#ifdef DEBUG_ENABLED
+		CRASH_COND(p_mono_method == NULL);
+#endif
+		mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
+	}
+};
+
+#else
+
+template <unsigned int ThunkParamCount, class P1, class... ParamTypes>
+struct VariadicInvokeMonoMethodImpl {
+	static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) {
+		if (p_mono_method->is_static()) {
+			void *args[ThunkParamCount] = { p_arg1, p_args... };
+			p_mono_method->invoke_raw(NULL, args, r_exc);
+		} else {
+			void *args[ThunkParamCount] = { p_args... };
+			p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc);
+		}
+	}
+};
+
+template <unsigned int ThunkParamCount, class... ParamTypes>
+struct VariadicInvokeMonoMethod {
+	static void invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) {
+		VariadicInvokeMonoMethodImpl<ThunkParamCount, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc);
+	}
+};
+
+template <>
+struct VariadicInvokeMonoMethod<0> {
+	static void invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) {
+#ifdef DEBUG_ENABLED
+		CRASH_COND(!p_mono_method->is_static());
+#endif
+		p_mono_method->invoke_raw(NULL, NULL, r_exc);
+	}
+};
+
+template <class P1>
+struct VariadicInvokeMonoMethod<1, P1> {
+	static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) {
+		if (p_mono_method->is_static()) {
+			void *args[1] = { p_arg1 };
+			p_mono_method->invoke_raw(NULL, args, r_exc);
+		} else {
+			p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc);
+		}
+	}
+};
+
+template <class R>
+R unbox_if_needed(MonoObject *p_val, const ManagedType &, typename std::enable_if<!std::is_pointer<R>::value>::type * = 0) {
+	return GDMonoMarshal::unbox<R>(p_val);
+}
+
+template <class R>
+R unbox_if_needed(MonoObject *p_val, const ManagedType &p_type, typename std::enable_if<std::is_pointer<R>::value>::type * = 0) {
+	if (mono_class_is_valuetype(p_type.type_class->get_mono_ptr())) {
+		return GDMonoMarshal::unbox<R>(p_val);
+	} else {
+		// If it's not a value type, we assume 'R' is a pointer to 'MonoObject' or a compatible type, like 'MonoException'.
+		return (R)p_val;
+	}
+}
+
+template <unsigned int ThunkParamCount, class R, class P1, class... ParamTypes>
+struct VariadicInvokeMonoMethodRImpl {
+	static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) {
+		if (p_mono_method->is_static()) {
+			void *args[ThunkParamCount] = { p_arg1, p_args... };
+			MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc);
+			return unbox_if_needed<R>(r, p_mono_method->get_return_type());
+		} else {
+			void *args[ThunkParamCount] = { p_args... };
+			MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc);
+			return unbox_if_needed<R>(r, p_mono_method->get_return_type());
+		}
+	}
+};
+
+template <unsigned int ThunkParamCount, class R, class... ParamTypes>
+struct VariadicInvokeMonoMethodR {
+	static R invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) {
+		return VariadicInvokeMonoMethodRImpl<ThunkParamCount, R, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc);
+	}
+};
+
+template <class R>
+struct VariadicInvokeMonoMethodR<0, R> {
+	static R invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) {
+#ifdef DEBUG_ENABLED
+		CRASH_COND(!p_mono_method->is_static());
+#endif
+		MonoObject *r = p_mono_method->invoke_raw(NULL, NULL, r_exc);
+		return unbox_if_needed<R>(r, p_mono_method->get_return_type());
+	}
+};
+
+template <class R, class P1>
+struct VariadicInvokeMonoMethodR<1, R, P1> {
+	static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) {
+		if (p_mono_method->is_static()) {
+			void *args[1] = { p_arg1 };
+			MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc);
+			return unbox_if_needed<R>(r, p_mono_method->get_return_type());
+		} else {
+			MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc);
+			return unbox_if_needed<R>(r, p_mono_method->get_return_type());
+		}
+	}
+};
+
+template <class... ParamTypes>
+struct GDMonoMethodThunk {
+
+	GDMonoMethod *mono_method;
+
+public:
+	_FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) {
+		VariadicInvokeMonoMethod<sizeof...(ParamTypes), ParamTypes...>::invoke(mono_method, p_args..., r_exc);
+	}
+
+	_FORCE_INLINE_ bool is_null() {
+		return mono_method == NULL;
+	}
+
+	_FORCE_INLINE_ void nullify() {
+		mono_method = NULL;
+	}
+
+	_FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
+#ifdef DEBUG_ENABLED
+		CRASH_COND(p_mono_method == NULL);
+		CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID);
+
+		if (p_mono_method->is_static()) {
+			CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
+		} else {
+			CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
+		}
+#endif
+		mono_method = p_mono_method;
+	}
+
+	GDMonoMethodThunk() :
+			mono_method(NULL) {
+	}
+
+	explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) {
+		set_from_method(p_mono_method);
+	}
+};
+
+template <class R, class... ParamTypes>
+struct GDMonoMethodThunkR {
+
+	GDMonoMethod *mono_method;
+
+public:
+	_FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) {
+		return VariadicInvokeMonoMethodR<sizeof...(ParamTypes), R, ParamTypes...>::invoke(mono_method, p_args..., r_exc);
+	}
+
+	_FORCE_INLINE_ bool is_null() {
+		return mono_method == NULL;
+	}
+
+	_FORCE_INLINE_ void nullify() {
+		mono_method = NULL;
+	}
+
+	_FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
+#ifdef DEBUG_ENABLED
+		CRASH_COND(p_mono_method == NULL);
+		CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID);
+
+		if (p_mono_method->is_static()) {
+			CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
+		} else {
+			CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
+		}
+#endif
+		mono_method = p_mono_method;
+	}
+
+	GDMonoMethodThunkR() :
+			mono_method(NULL) {
+	}
+
+	explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) {
+		set_from_method(p_mono_method);
+	}
+};
+
+#endif
+
+#endif // GD_MONO_METHOD_THUNK_H

+ 2 - 0
modules/mono/mono_gd/gd_mono_property.cpp

@@ -30,8 +30,10 @@
 
 
 #include "gd_mono_property.h"
 #include "gd_mono_property.h"
 
 
+#include "gd_mono_cache.h"
 #include "gd_mono_class.h"
 #include "gd_mono_class.h"
 #include "gd_mono_marshal.h"
 #include "gd_mono_marshal.h"
+#include "gd_mono_utils.h"
 
 
 #include <mono/metadata/attrdefs.h>
 #include <mono/metadata/attrdefs.h>
 
 

+ 21 - 294
modules/mono/mono_gd/gd_mono_utils.cpp

@@ -45,273 +45,13 @@
 #include "../utils/macros.h"
 #include "../utils/macros.h"
 #include "../utils/mutex_utils.h"
 #include "../utils/mutex_utils.h"
 #include "gd_mono.h"
 #include "gd_mono.h"
+#include "gd_mono_cache.h"
 #include "gd_mono_class.h"
 #include "gd_mono_class.h"
 #include "gd_mono_marshal.h"
 #include "gd_mono_marshal.h"
+#include "gd_mono_method_thunk.h"
 
 
 namespace GDMonoUtils {
 namespace GDMonoUtils {
 
 
-MonoCache mono_cache;
-
-#define CACHE_AND_CHECK(m_var, m_val)                                        \
-	{                                                                        \
-		CRASH_COND(m_var != NULL);                                           \
-		m_var = m_val;                                                       \
-		ERR_FAIL_COND_MSG(!m_var, "Mono Cache: Member " #m_var " is null."); \
-	}
-
-#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_class, m_val)
-#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_ns##_##m_class, m_val)
-#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.rawclass_##m_class, m_val)
-#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val)
-#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val)
-#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
-#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.property_##m_class##_##m_property, m_val)
-
-void MonoCache::clear_corlib_cache() {
-
-	corlib_cache_updated = false;
-
-	class_MonoObject = NULL;
-	class_bool = NULL;
-	class_int8_t = NULL;
-	class_int16_t = NULL;
-	class_int32_t = NULL;
-	class_int64_t = NULL;
-	class_uint8_t = NULL;
-	class_uint16_t = NULL;
-	class_uint32_t = NULL;
-	class_uint64_t = NULL;
-	class_float = NULL;
-	class_double = NULL;
-	class_String = NULL;
-	class_IntPtr = NULL;
-
-	class_System_Collections_IEnumerable = NULL;
-	class_System_Collections_IDictionary = NULL;
-
-#ifdef DEBUG_ENABLED
-	class_System_Diagnostics_StackTrace = NULL;
-	methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL;
-	method_System_Diagnostics_StackTrace_ctor_bool = NULL;
-	method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL;
-#endif
-
-	class_KeyNotFoundException = NULL;
-}
-
-void MonoCache::clear_godot_api_cache() {
-
-	godot_api_cache_updated = false;
-
-	rawclass_Dictionary = NULL;
-
-	class_Vector2 = NULL;
-	class_Rect2 = NULL;
-	class_Transform2D = NULL;
-	class_Vector3 = NULL;
-	class_Basis = NULL;
-	class_Quat = NULL;
-	class_Transform = NULL;
-	class_AABB = NULL;
-	class_Color = NULL;
-	class_Plane = NULL;
-	class_NodePath = NULL;
-	class_RID = NULL;
-	class_GodotObject = NULL;
-	class_GodotResource = NULL;
-	class_Node = NULL;
-	class_Control = NULL;
-	class_Spatial = NULL;
-	class_WeakRef = NULL;
-	class_Array = NULL;
-	class_Dictionary = NULL;
-	class_MarshalUtils = NULL;
-	class_ISerializationListener = NULL;
-
-#ifdef DEBUG_ENABLED
-	class_DebuggingUtils = NULL;
-	methodthunk_DebuggingUtils_GetStackFrameInfo = NULL;
-#endif
-
-	class_ExportAttribute = NULL;
-	field_ExportAttribute_hint = NULL;
-	field_ExportAttribute_hintString = NULL;
-	class_SignalAttribute = NULL;
-	class_ToolAttribute = NULL;
-	class_RemoteAttribute = NULL;
-	class_SyncAttribute = NULL;
-	class_MasterAttribute = NULL;
-	class_PuppetAttribute = NULL;
-	class_SlaveAttribute = NULL;
-	class_RemoteSyncAttribute = NULL;
-	class_MasterSyncAttribute = NULL;
-	class_PuppetSyncAttribute = NULL;
-	class_GodotMethodAttribute = NULL;
-	field_GodotMethodAttribute_methodName = NULL;
-
-	field_GodotObject_ptr = NULL;
-	field_NodePath_ptr = NULL;
-	field_Image_ptr = NULL;
-	field_RID_ptr = NULL;
-
-	methodthunk_GodotObject_Dispose = NULL;
-	methodthunk_Array_GetPtr = NULL;
-	methodthunk_Dictionary_GetPtr = NULL;
-	methodthunk_SignalAwaiter_SignalCallback = NULL;
-	methodthunk_SignalAwaiter_FailureCallback = NULL;
-	methodthunk_GodotTaskScheduler_Activate = NULL;
-
-	// Start of MarshalUtils methods
-
-	methodthunk_MarshalUtils_TypeIsGenericArray = NULL;
-	methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL;
-
-	methodthunk_MarshalUtils_ArrayGetElementType = NULL;
-	methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL;
-
-	methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType = NULL;
-	methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType = NULL;
-	methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info = NULL;
-	methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info = NULL;
-
-	methodthunk_MarshalUtils_MakeGenericArrayType = NULL;
-	methodthunk_MarshalUtils_MakeGenericDictionaryType = NULL;
-
-	methodthunk_MarshalUtils_EnumerableToArray = NULL;
-	methodthunk_MarshalUtils_IDictionaryToDictionary = NULL;
-	methodthunk_MarshalUtils_GenericIDictionaryToDictionary = NULL;
-
-	// End of MarshalUtils methods
-
-	task_scheduler_handle = Ref<MonoGCHandle>();
-}
-
-#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
-#define GODOT_API_NS_CLAS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class))
-
-void update_corlib_cache() {
-
-	CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class()));
-	CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class()));
-	CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class()));
-	CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class()));
-	CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class()));
-	CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class()));
-	CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class()));
-	CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class()));
-	CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class()));
-	CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class()));
-	CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class()));
-	CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class()));
-	CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
-	CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
-
-	CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
-	CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
-
-#ifdef DEBUG_ENABLED
-	CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace"));
-	CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_thunk("GetFrames"));
-	CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true));
-	CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
-#endif
-
-	CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException"));
-
-	mono_cache.corlib_cache_updated = true;
-}
-
-void update_godot_api_cache() {
-
-	CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2));
-	CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2));
-	CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
-	CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
-	CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
-	CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat));
-	CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform));
-	CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB));
-	CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
-	CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
-	CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
-	CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID));
-	CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
-	CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource));
-	CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
-	CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
-	CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
-	CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
-	CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array));
-	CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary));
-	CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
-	CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener));
-
-#ifdef DEBUG_ENABLED
-	CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils));
-#endif
-
-	// Attributes
-	CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
-	CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
-	CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
-	CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute));
-	CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
-	CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
-	CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute));
-	CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute));
-	CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute));
-	CACHE_CLASS_AND_CHECK(SlaveAttribute, GODOT_API_CLASS(SlaveAttribute));
-	CACHE_CLASS_AND_CHECK(RemoteSyncAttribute, GODOT_API_CLASS(RemoteSyncAttribute));
-	CACHE_CLASS_AND_CHECK(MasterSyncAttribute, GODOT_API_CLASS(MasterSyncAttribute));
-	CACHE_CLASS_AND_CHECK(PuppetSyncAttribute, GODOT_API_CLASS(PuppetSyncAttribute));
-	CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
-	CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
-
-	CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
-	CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
-	CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
-
-	CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, (GodotObject_Dispose)CACHED_CLASS(GodotObject)->get_method_thunk("Dispose", 0));
-	CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0));
-	CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0));
-	CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1));
-	CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0));
-	CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0));
-
-	// Start of MarshalUtils methods
-
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1));
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1));
-
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
-
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, (GenericIEnumerableIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 1));
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 1));
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2));
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info, (GenericIDictionaryIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3));
-
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, (MakeGenericArrayType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericArrayType", 1));
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, (MakeGenericDictionaryType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericDictionaryType", 2));
-
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2));
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2));
-	CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, (GenericIDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryToDictionary", 2));
-
-	// End of MarshalUtils methods
-
-#ifdef DEBUG_ENABLED
-	CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4));
-#endif
-
-	// TODO Move to CSharpLanguage::init() and do handle disposal
-	MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
-	GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler));
-	mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
-
-	mono_cache.godot_api_cache_updated = true;
-}
-
 MonoObject *unmanaged_get_managed(Object *unmanaged) {
 MonoObject *unmanaged_get_managed(Object *unmanaged) {
 
 
 	if (!unmanaged)
 	if (!unmanaged)
@@ -386,7 +126,7 @@ void set_main_thread(MonoThread *p_thread) {
 
 
 void attach_current_thread() {
 void attach_current_thread() {
 	ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
 	ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
-	MonoThread *mono_thread = mono_thread_attach(mono_domain_get());
+	MonoThread *mono_thread = mono_thread_attach(mono_get_root_domain());
 	ERR_FAIL_NULL(mono_thread);
 	ERR_FAIL_NULL(mono_thread);
 }
 }
 
 
@@ -421,7 +161,7 @@ GDMonoClass *type_get_proxy_class(const StringName &p_type) {
 
 
 	if (klass && klass->is_static()) {
 	if (klass && klass->is_static()) {
 		// A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object.
 		// A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object.
-		return mono_cache.class_GodotObject;
+		return GDMonoCache::cached_data.class_GodotObject;
 	}
 	}
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
@@ -751,16 +491,16 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &
 }
 }
 
 
 void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
 void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
-	invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc);
+	CACHED_METHOD_THUNK(GodotObject, Dispose).invoke(p_mono_object, r_exc);
 }
 }
 
 
 namespace Marshal {
 namespace Marshal {
 
 
 #ifdef MONO_GLUE_ENABLED
 #ifdef MONO_GLUE_ENABLED
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
-#define NO_GLUE_RET(m_ret)                                     \
-	{                                                          \
-		if (!mono_cache.godot_api_cache_updated) return m_ret; \
+#define NO_GLUE_RET(m_ret)                                                   \
+	{                                                                        \
+		if (!GDMonoCache::cached_data.godot_api_cache_updated) return m_ret; \
 	}
 	}
 #else
 #else
 #define NO_GLUE_RET(m_ret) \
 #define NO_GLUE_RET(m_ret) \
@@ -773,68 +513,60 @@ namespace Marshal {
 
 
 bool type_is_generic_array(MonoReflectionType *p_reftype) {
 bool type_is_generic_array(MonoReflectionType *p_reftype) {
 	NO_GLUE_RET(false);
 	NO_GLUE_RET(false);
-	TypeIsGenericArray thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
+	MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray).invoke(p_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return (bool)res;
 	return (bool)res;
 }
 }
 
 
 bool type_is_generic_dictionary(MonoReflectionType *p_reftype) {
 bool type_is_generic_dictionary(MonoReflectionType *p_reftype) {
 	NO_GLUE_RET(false);
 	NO_GLUE_RET(false);
-	TypeIsGenericDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
+	MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary).invoke(p_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return (bool)res;
 	return (bool)res;
 }
 }
 
 
 void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
 void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
-	ArrayGetElementType thunk = CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	invoke_method_thunk(thunk, p_array_reftype, r_elem_reftype, &exc);
+	CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 }
 }
 
 
 void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
 void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
-	DictionaryGetKeyValueTypes thunk = CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	invoke_method_thunk(thunk, p_dict_reftype, r_key_reftype, r_value_reftype, &exc);
+	CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes).invoke(p_dict_reftype, r_key_reftype, r_value_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 }
 }
 
 
 bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) {
 bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) {
 	NO_GLUE_RET(false);
 	NO_GLUE_RET(false);
-	GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
+	MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType).invoke(p_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return (bool)res;
 	return (bool)res;
 }
 }
 
 
 bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) {
 bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) {
 	NO_GLUE_RET(false);
 	NO_GLUE_RET(false);
-	GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc);
+	MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType).invoke(p_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return (bool)res;
 	return (bool)res;
 }
 }
 
 
 bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) {
 bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) {
 	NO_GLUE_RET(false);
 	NO_GLUE_RET(false);
-	GenericIEnumerableIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_elem_reftype, &exc);
+	MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info).invoke(p_reftype, r_elem_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return (bool)res;
 	return (bool)res;
 }
 }
 
 
 bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
 bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
 	NO_GLUE_RET(false);
 	NO_GLUE_RET(false);
-	GenericIDictionaryIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_key_reftype, r_value_reftype, &exc);
+	MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info).invoke(p_reftype, r_key_reftype, r_value_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return (bool)res;
 	return (bool)res;
 }
 }
@@ -842,9 +574,8 @@ bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoR
 Array enumerable_to_array(MonoObject *p_enumerable) {
 Array enumerable_to_array(MonoObject *p_enumerable) {
 	NO_GLUE_RET(Array());
 	NO_GLUE_RET(Array());
 	Array result;
 	Array result;
-	EnumerableToArray thunk = CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	invoke_method_thunk(thunk, p_enumerable, &result, &exc);
+	CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray).invoke(p_enumerable, &result, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return result;
 	return result;
 }
 }
@@ -852,9 +583,8 @@ Array enumerable_to_array(MonoObject *p_enumerable) {
 Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) {
 Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) {
 	NO_GLUE_RET(Dictionary());
 	NO_GLUE_RET(Dictionary());
 	Dictionary result;
 	Dictionary result;
-	IDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	invoke_method_thunk(thunk, p_idictionary, &result, &exc);
+	CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary).invoke(p_idictionary, &result, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return result;
 	return result;
 }
 }
@@ -862,27 +592,24 @@ Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) {
 Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) {
 Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) {
 	NO_GLUE_RET(Dictionary());
 	NO_GLUE_RET(Dictionary());
 	Dictionary result;
 	Dictionary result;
-	GenericIDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	invoke_method_thunk(thunk, p_generic_idictionary, &result, &exc);
+	CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary).invoke(p_generic_idictionary, &result, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return result;
 	return result;
 }
 }
 
 
 GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
 GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
 	NO_GLUE_RET(NULL);
 	NO_GLUE_RET(NULL);
-	MakeGenericArrayType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	MonoReflectionType *reftype = invoke_method_thunk(thunk, p_elem_reftype, &exc);
+	MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType).invoke(p_elem_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
 	return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
 }
 }
 
 
 GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
 GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
 	NO_GLUE_RET(NULL);
 	NO_GLUE_RET(NULL);
-	MakeGenericDictionaryType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType);
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
-	MonoReflectionType *reftype = invoke_method_thunk(thunk, p_key_reftype, p_value_reftype, &exc);
+	MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType).invoke(p_key_reftype, p_value_reftype, &exc);
 	UNHANDLED_EXCEPTION(exc);
 	UNHANDLED_EXCEPTION(exc);
 	return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
 	return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
 }
 }

+ 0 - 281
modules/mono/mono_gd/gd_mono_utils.h

@@ -49,33 +49,6 @@
 
 
 namespace GDMonoUtils {
 namespace GDMonoUtils {
 
 
-typedef void (*GodotObject_Dispose)(MonoObject *, MonoException **);
-typedef Array *(*Array_GetPtr)(MonoObject *, MonoException **);
-typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoException **);
-typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoException **);
-typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoException **);
-typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoException **);
-typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoException **);
-typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoException **);
-
-typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **);
-typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **);
-
-typedef void (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **);
-typedef void (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
-
-typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType)(MonoReflectionType *, MonoException **);
-typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType)(MonoReflectionType *, MonoException **);
-typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoException **);
-typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **);
-
-typedef MonoReflectionType *(*MakeGenericArrayType)(MonoReflectionType *, MonoException **);
-typedef MonoReflectionType *(*MakeGenericDictionaryType)(MonoReflectionType *, MonoReflectionType *, MonoException **);
-
-typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **);
-typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **);
-typedef void (*GenericIDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **);
-
 namespace Marshal {
 namespace Marshal {
 
 
 bool type_is_generic_array(MonoReflectionType *p_reftype);
 bool type_is_generic_array(MonoReflectionType *p_reftype);
@@ -98,157 +71,6 @@ Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary);
 
 
 } // namespace Marshal
 } // namespace Marshal
 
 
-// End of MarshalUtils methods
-
-struct MonoCache {
-
-	// -----------------------------------------------
-	// corlib classes
-
-	// Let's use the no-namespace format for these too
-	GDMonoClass *class_MonoObject;
-	GDMonoClass *class_bool;
-	GDMonoClass *class_int8_t;
-	GDMonoClass *class_int16_t;
-	GDMonoClass *class_int32_t;
-	GDMonoClass *class_int64_t;
-	GDMonoClass *class_uint8_t;
-	GDMonoClass *class_uint16_t;
-	GDMonoClass *class_uint32_t;
-	GDMonoClass *class_uint64_t;
-	GDMonoClass *class_float;
-	GDMonoClass *class_double;
-	GDMonoClass *class_String;
-	GDMonoClass *class_IntPtr;
-
-	GDMonoClass *class_System_Collections_IEnumerable;
-	GDMonoClass *class_System_Collections_IDictionary;
-
-#ifdef DEBUG_ENABLED
-	GDMonoClass *class_System_Diagnostics_StackTrace;
-	StackTrace_GetFrames methodthunk_System_Diagnostics_StackTrace_GetFrames;
-	GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool;
-	GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
-#endif
-
-	GDMonoClass *class_KeyNotFoundException;
-
-	MonoClass *rawclass_Dictionary;
-	// -----------------------------------------------
-
-	GDMonoClass *class_Vector2;
-	GDMonoClass *class_Rect2;
-	GDMonoClass *class_Transform2D;
-	GDMonoClass *class_Vector3;
-	GDMonoClass *class_Basis;
-	GDMonoClass *class_Quat;
-	GDMonoClass *class_Transform;
-	GDMonoClass *class_AABB;
-	GDMonoClass *class_Color;
-	GDMonoClass *class_Plane;
-	GDMonoClass *class_NodePath;
-	GDMonoClass *class_RID;
-	GDMonoClass *class_GodotObject;
-	GDMonoClass *class_GodotResource;
-	GDMonoClass *class_Node;
-	GDMonoClass *class_Control;
-	GDMonoClass *class_Spatial;
-	GDMonoClass *class_WeakRef;
-	GDMonoClass *class_Array;
-	GDMonoClass *class_Dictionary;
-	GDMonoClass *class_MarshalUtils;
-	GDMonoClass *class_ISerializationListener;
-
-#ifdef DEBUG_ENABLED
-	GDMonoClass *class_DebuggingUtils;
-	DebugUtils_StackFrameInfo methodthunk_DebuggingUtils_GetStackFrameInfo;
-#endif
-
-	GDMonoClass *class_ExportAttribute;
-	GDMonoField *field_ExportAttribute_hint;
-	GDMonoField *field_ExportAttribute_hintString;
-	GDMonoClass *class_SignalAttribute;
-	GDMonoClass *class_ToolAttribute;
-	GDMonoClass *class_RemoteAttribute;
-	GDMonoClass *class_SyncAttribute;
-	GDMonoClass *class_RemoteSyncAttribute;
-	GDMonoClass *class_MasterSyncAttribute;
-	GDMonoClass *class_PuppetSyncAttribute;
-	GDMonoClass *class_MasterAttribute;
-	GDMonoClass *class_PuppetAttribute;
-	GDMonoClass *class_SlaveAttribute;
-	GDMonoClass *class_GodotMethodAttribute;
-	GDMonoField *field_GodotMethodAttribute_methodName;
-
-	GDMonoField *field_GodotObject_ptr;
-	GDMonoField *field_NodePath_ptr;
-	GDMonoField *field_Image_ptr;
-	GDMonoField *field_RID_ptr;
-
-	GodotObject_Dispose methodthunk_GodotObject_Dispose;
-	Array_GetPtr methodthunk_Array_GetPtr;
-	Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
-	SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
-	SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
-	GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
-
-	// Start of MarshalUtils methods
-
-	TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray;
-	TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary;
-
-	ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType;
-	DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
-
-	GenericIEnumerableIsAssignableFromType methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType;
-	GenericIDictionaryIsAssignableFromType methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType;
-	GenericIEnumerableIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info;
-	GenericIDictionaryIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info;
-
-	MakeGenericArrayType methodthunk_MarshalUtils_MakeGenericArrayType;
-	MakeGenericDictionaryType methodthunk_MarshalUtils_MakeGenericDictionaryType;
-
-	EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray;
-	IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary;
-	GenericIDictionaryToDictionary methodthunk_MarshalUtils_GenericIDictionaryToDictionary;
-
-	// End of MarshalUtils methods
-
-	Ref<MonoGCHandle> task_scheduler_handle;
-
-	bool corlib_cache_updated;
-	bool godot_api_cache_updated;
-
-	void clear_corlib_cache();
-	void clear_godot_api_cache();
-
-	MonoCache() {
-		clear_corlib_cache();
-		clear_godot_api_cache();
-	}
-};
-
-extern MonoCache mono_cache;
-
-void update_corlib_cache();
-void update_godot_api_cache();
-
-inline void clear_corlib_cache() {
-	mono_cache.clear_corlib_cache();
-}
-
-inline void clear_godot_api_cache() {
-	mono_cache.clear_godot_api_cache();
-}
-
-_FORCE_INLINE_ bool tools_godot_api_check() {
-#ifdef TOOLS_ENABLED
-	return mono_cache.godot_api_cache_updated;
-#else
-	return true; // Assume it's updated if this was called, otherwise it's a bug
-#endif
-}
-
 _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
 _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
 	p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
 	p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
 }
 }
@@ -324,20 +146,6 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc);
 
 
 #define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL)))
 #define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL)))
 
 
-#define CACHED_CLASS(m_class) (GDMonoUtils::mono_cache.class_##m_class)
-#define CACHED_CLASS_RAW(m_class) (GDMonoUtils::mono_cache.class_##m_class->get_mono_ptr())
-#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoUtils::mono_cache.rawclass_##m_class)
-#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field)
-#define CACHED_METHOD(m_class, m_method) (GDMonoUtils::mono_cache.method_##m_class##_##m_method)
-#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method)
-#define CACHED_PROPERTY(m_class, m_property) (GDMonoUtils::mono_cache.property_##m_class##_##m_property)
-
-#ifdef REAL_T_IS_DOUBLE
-#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
-#else
-#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float)
-#endif
-
 #define GD_MONO_BEGIN_RUNTIME_INVOKE                                              \
 #define GD_MONO_BEGIN_RUNTIME_INVOKE                                              \
 	int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \
 	int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \
 	_runtime_invoke_count_ref += 1;
 	_runtime_invoke_count_ref += 1;
@@ -345,93 +153,4 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc);
 #define GD_MONO_END_RUNTIME_INVOKE \
 #define GD_MONO_END_RUNTIME_INVOKE \
 	_runtime_invoke_count_ref -= 1;
 	_runtime_invoke_count_ref -= 1;
 
 
-inline void invoke_method_thunk(void (*p_method_thunk)()) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	p_method_thunk();
-	GD_MONO_END_RUNTIME_INVOKE;
-}
-
-template <class R>
-R invoke_method_thunk(R (*p_method_thunk)()) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	R r = p_method_thunk();
-	GD_MONO_END_RUNTIME_INVOKE;
-	return r;
-}
-
-template <class P1>
-void invoke_method_thunk(void (*p_method_thunk)(P1), P1 p_arg1) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	p_method_thunk(p_arg1);
-	GD_MONO_END_RUNTIME_INVOKE;
-}
-
-template <class R, class P1>
-R invoke_method_thunk(R (*p_method_thunk)(P1), P1 p_arg1) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	R r = p_method_thunk(p_arg1);
-	GD_MONO_END_RUNTIME_INVOKE;
-	return r;
-}
-
-template <class P1, class P2>
-void invoke_method_thunk(void (*p_method_thunk)(P1, P2), P1 p_arg1, P2 p_arg2) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	p_method_thunk(p_arg1, p_arg2);
-	GD_MONO_END_RUNTIME_INVOKE;
-}
-
-template <class R, class P1, class P2>
-R invoke_method_thunk(R (*p_method_thunk)(P1, P2), P1 p_arg1, P2 p_arg2) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	R r = p_method_thunk(p_arg1, p_arg2);
-	GD_MONO_END_RUNTIME_INVOKE;
-	return r;
-}
-
-template <class P1, class P2, class P3>
-void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3), P1 p_arg1, P2 p_arg2, P3 p_arg3) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	p_method_thunk(p_arg1, p_arg2, p_arg3);
-	GD_MONO_END_RUNTIME_INVOKE;
-}
-
-template <class R, class P1, class P2, class P3>
-R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3), P1 p_arg1, P2 p_arg2, P3 p_arg3) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	R r = p_method_thunk(p_arg1, p_arg2, p_arg3);
-	GD_MONO_END_RUNTIME_INVOKE;
-	return r;
-}
-
-template <class P1, class P2, class P3, class P4>
-void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3, P4), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4);
-	GD_MONO_END_RUNTIME_INVOKE;
-}
-
-template <class R, class P1, class P2, class P3, class P4>
-R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3, P4), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	R r = p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4);
-	GD_MONO_END_RUNTIME_INVOKE;
-	return r;
-}
-
-template <class P1, class P2, class P3, class P4, class P5>
-void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3, P4, P5), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4, P5 p_arg5) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4, p_arg5);
-	GD_MONO_END_RUNTIME_INVOKE;
-}
-
-template <class R, class P1, class P2, class P3, class P4, class P5>
-R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3, P4, P5), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4, P5 p_arg5) {
-	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	R r = p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4, p_arg5);
-	GD_MONO_END_RUNTIME_INVOKE;
-	return r;
-}
-
 #endif // GD_MONOUTILS_H
 #endif // GD_MONOUTILS_H

+ 3 - 2
modules/mono/signal_awaiter_utils.cpp

@@ -31,6 +31,7 @@
 #include "signal_awaiter_utils.h"
 #include "signal_awaiter_utils.h"
 
 
 #include "csharp_script.h"
 #include "csharp_script.h"
+#include "mono_gd/gd_mono_cache.h"
 #include "mono_gd/gd_mono_class.h"
 #include "mono_gd/gd_mono_class.h"
 #include "mono_gd/gd_mono_marshal.h"
 #include "mono_gd/gd_mono_marshal.h"
 #include "mono_gd/gd_mono_utils.h"
 #include "mono_gd/gd_mono_utils.h"
@@ -98,7 +99,7 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc
 
 
 	MonoException *exc = NULL;
 	MonoException *exc = NULL;
 	GD_MONO_BEGIN_RUNTIME_INVOKE;
 	GD_MONO_BEGIN_RUNTIME_INVOKE;
-	invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, &exc);
+	CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback).invoke(get_target(), signal_args, &exc);
 	GD_MONO_END_RUNTIME_INVOKE;
 	GD_MONO_END_RUNTIME_INVOKE;
 
 
 	if (exc) {
 	if (exc) {
@@ -130,7 +131,7 @@ SignalAwaiterHandle::~SignalAwaiterHandle() {
 		if (awaiter) {
 		if (awaiter) {
 			MonoException *exc = NULL;
 			MonoException *exc = NULL;
 			GD_MONO_BEGIN_RUNTIME_INVOKE;
 			GD_MONO_BEGIN_RUNTIME_INVOKE;
-			invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, &exc);
+			CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback).invoke(awaiter, &exc);
 			GD_MONO_END_RUNTIME_INVOKE;
 			GD_MONO_END_RUNTIME_INVOKE;
 
 
 			if (exc) {
 			if (exc) {