235 lines
12 KiB
C++
235 lines
12 KiB
C++
/*************************************************************************/
|
|
/* gd_mono_cache.cpp */
|
|
/*************************************************************************/
|
|
/* This file is part of: */
|
|
/* GODOT ENGINE */
|
|
/* https://godotengine.org */
|
|
/*************************************************************************/
|
|
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
|
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
|
/* */
|
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
/* a copy of this software and associated documentation files (the */
|
|
/* "Software"), to deal in the Software without restriction, including */
|
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
/* the following conditions: */
|
|
/* */
|
|
/* The above copyright notice and this permission notice shall be */
|
|
/* included in all copies or substantial portions of the Software. */
|
|
/* */
|
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
/*************************************************************************/
|
|
|
|
#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 != nullptr); \
|
|
m_var = m_val; \
|
|
ERR_FAIL_COND_MSG(m_var == nullptr, "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_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_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \
|
|
{ \
|
|
CRASH_COND(!m_var.is_null()); \
|
|
ERR_FAIL_COND_MSG(m_val == nullptr, "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 = nullptr;
|
|
class_String = nullptr;
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
class_System_Diagnostics_StackTrace = nullptr;
|
|
methodthunk_System_Diagnostics_StackTrace_GetFrames.nullify();
|
|
method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
|
|
method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
|
|
#endif
|
|
|
|
class_KeyNotFoundException = nullptr;
|
|
}
|
|
|
|
void CachedData::clear_godot_api_cache() {
|
|
godot_api_cache_updated = false;
|
|
|
|
class_GodotObject = nullptr;
|
|
class_GodotResource = nullptr;
|
|
class_Control = nullptr;
|
|
class_Callable = nullptr;
|
|
class_SignalInfo = nullptr;
|
|
class_ISerializationListener = nullptr;
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
class_DebuggingUtils = nullptr;
|
|
methodthunk_DebuggingUtils_GetStackFrameInfo.nullify();
|
|
#endif
|
|
|
|
class_ExportAttribute = nullptr;
|
|
field_ExportAttribute_hint = nullptr;
|
|
field_ExportAttribute_hintString = nullptr;
|
|
class_SignalAttribute = nullptr;
|
|
class_ToolAttribute = nullptr;
|
|
class_RemoteAttribute = nullptr;
|
|
class_MasterAttribute = nullptr;
|
|
class_PuppetAttribute = nullptr;
|
|
class_GodotMethodAttribute = nullptr;
|
|
field_GodotMethodAttribute_methodName = nullptr;
|
|
class_ScriptPathAttribute = nullptr;
|
|
field_ScriptPathAttribute_path = nullptr;
|
|
class_AssemblyHasScriptsAttribute = nullptr;
|
|
field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
|
|
field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
|
|
|
|
field_GodotObject_ptr = nullptr;
|
|
|
|
methodthunk_GodotObject_Dispose.nullify();
|
|
methodthunk_SignalAwaiter_SignalCallback.nullify();
|
|
|
|
methodthunk_Delegate_Equals.nullify();
|
|
|
|
methodthunk_DelegateUtils_TrySerializeDelegateWithGCHandle.nullify();
|
|
methodthunk_DelegateUtils_TryDeserializeDelegateWithGCHandle.nullify();
|
|
methodthunk_DelegateUtils_TrySerializeDelegate.nullify();
|
|
methodthunk_DelegateUtils_TryDeserializeDelegate.nullify();
|
|
methodthunk_DelegateUtils_InvokeWithVariantArgs.nullify();
|
|
methodthunk_DelegateUtils_DelegateEquals.nullify();
|
|
methodthunk_DelegateUtils_FreeGCHandle.nullify();
|
|
|
|
methodthunk_Marshaling_managed_to_variant_type.nullify();
|
|
methodthunk_Marshaling_try_get_array_element_type.nullify();
|
|
methodthunk_Marshaling_variant_to_mono_object_of_type.nullify();
|
|
methodthunk_Marshaling_variant_to_mono_object.nullify();
|
|
methodthunk_Marshaling_mono_object_to_variant_out.nullify();
|
|
|
|
methodthunk_Marshaling_SetFieldValue.nullify();
|
|
}
|
|
|
|
#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #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(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
|
|
|
|
#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_METHOD_THUNK_AND_CHECK(Delegate, Equals, GDMono::get_singleton()->get_corlib_assembly()->get_class("System", "Delegate")->get_method_with_desc("System.Delegate:Equals(object)", true));
|
|
|
|
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(GodotObject, GODOT_API_CLASS(Object));
|
|
CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource));
|
|
CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
|
|
CACHE_CLASS_AND_CHECK(Callable, GODOT_API_CLASS(Callable));
|
|
CACHE_CLASS_AND_CHECK(SignalInfo, GODOT_API_CLASS(SignalInfo));
|
|
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(MasterAttribute, GODOT_API_CLASS(MasterAttribute));
|
|
CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute));
|
|
CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
|
|
CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
|
|
CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute));
|
|
CACHE_FIELD_AND_CHECK(ScriptPathAttribute, path, CACHED_CLASS(ScriptPathAttribute)->get_field("path"));
|
|
CACHE_CLASS_AND_CHECK(AssemblyHasScriptsAttribute, GODOT_API_CLASS(AssemblyHasScriptsAttribute));
|
|
CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, requiresLookup, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("requiresLookup"));
|
|
CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, scriptTypes, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("scriptTypes"));
|
|
|
|
CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
|
|
|
|
CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, CACHED_CLASS(GodotObject)->get_method("Dispose", 0));
|
|
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1));
|
|
|
|
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegateWithGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegateWithGCHandle", 2));
|
|
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegateWithGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegateWithGCHandle", 2));
|
|
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegate", 2));
|
|
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegate", 2));
|
|
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, InvokeWithVariantArgs, GODOT_API_CLASS(DelegateUtils)->get_method("InvokeWithVariantArgs", 4));
|
|
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, DelegateEquals, GODOT_API_CLASS(DelegateUtils)->get_method("DelegateEquals", 2));
|
|
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, FreeGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("FreeGCHandle", 1));
|
|
|
|
GDMonoClass *gd_mono_marshal_class = GDMono::get_singleton()->get_core_api_assembly()->get_class(
|
|
"Godot.NativeInterop", "Marshaling");
|
|
|
|
ERR_FAIL_COND_MSG(gd_mono_marshal_class == nullptr,
|
|
"Mono Cache: Class `Godot.NativeInterop.Marshaling` not found.");
|
|
|
|
CACHE_METHOD_THUNK_AND_CHECK(Marshaling, managed_to_variant_type,
|
|
gd_mono_marshal_class->get_method("managed_to_variant_type", 2));
|
|
CACHE_METHOD_THUNK_AND_CHECK(Marshaling, try_get_array_element_type,
|
|
gd_mono_marshal_class->get_method("try_get_array_element_type", 2));
|
|
CACHE_METHOD_THUNK_AND_CHECK(Marshaling, variant_to_mono_object_of_type,
|
|
gd_mono_marshal_class->get_method("variant_to_mono_object_of_type", 2));
|
|
CACHE_METHOD_THUNK_AND_CHECK(Marshaling, variant_to_mono_object,
|
|
gd_mono_marshal_class->get_method("variant_to_mono_object", 1));
|
|
CACHE_METHOD_THUNK_AND_CHECK(Marshaling, mono_object_to_variant_out,
|
|
gd_mono_marshal_class->get_method("mono_object_to_variant_out", 3));
|
|
|
|
CACHE_METHOD_THUNK_AND_CHECK(Marshaling, SetFieldValue,
|
|
gd_mono_marshal_class->get_method("SetFieldValue", 3));
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4));
|
|
#endif
|
|
|
|
MonoException *exc = nullptr;
|
|
GDMono::get_singleton()
|
|
->get_core_api_assembly()
|
|
->get_class("Godot", "Dispatcher")
|
|
->get_method("InitializeDefaultGodotTaskScheduler")
|
|
->invoke(nullptr, &exc);
|
|
|
|
if (exc) {
|
|
GDMonoUtils::debug_unhandled_exception(exc);
|
|
}
|
|
|
|
cached_data.godot_api_cache_updated = true;
|
|
}
|
|
} // namespace GDMonoCache
|