summaryrefslogtreecommitdiff
path: root/modules/mono/csharp_script.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/csharp_script.cpp')
-rw-r--r--modules/mono/csharp_script.cpp221
1 files changed, 170 insertions, 51 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index d82e78d080..752fc9e2cc 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -106,7 +106,7 @@ Error CSharpLanguage::execute_file(const String &p_path) {
void CSharpLanguage::init() {
#ifdef DEBUG_METHODS_ENABLED
- if (OS::get_singleton()->get_cmdline_args().find("--class_db_to_json")) {
+ if (OS::get_singleton()->get_cmdline_args().find("--class-db-json")) {
class_db_api_to_json("user://class_db_api.json", ClassDB::API_CORE);
#ifdef TOOLS_ENABLED
class_db_api_to_json("user://class_db_api_editor.json", ClassDB::API_EDITOR);
@@ -159,6 +159,19 @@ void CSharpLanguage::finish() {
// Clear here, after finalizing all domains to make sure there is nothing else referencing the elements.
script_bindings.clear();
+#ifdef DEBUG_ENABLED
+ for (Map<ObjectID, int>::Element *E = unsafe_object_references.front(); E; E = E->next()) {
+ const ObjectID &id = E->get();
+ Object *obj = ObjectDB::get_instance(id);
+
+ if (obj) {
+ ERR_PRINT("Leaked unsafe reference to object: " + obj->get_class() + ":" + itos(id));
+ } else {
+ ERR_PRINT("Leaked unsafe reference to deleted object: " + itos(id));
+ }
+ }
+#endif
+
finalizing = false;
}
@@ -546,6 +559,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
#ifdef DEBUG_ENABLED
_TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
+ GD_MONO_SCOPE_THREAD_ATTACH;
if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoCache::cached_data.corlib_cache_updated)
return Vector<StackInfo>();
@@ -570,6 +584,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
_TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
+ GD_MONO_SCOPE_THREAD_ATTACH;
MonoException *exc = NULL;
@@ -615,6 +630,25 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
}
#endif
+void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
+#ifdef DEBUG_ENABLED
+ SCOPED_MUTEX_LOCK(unsafe_object_references_lock);
+ ObjectID id = p_obj->get_instance_id();
+ unsafe_object_references[id]++;
+#endif
+}
+
+void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
+#ifdef DEBUG_ENABLED
+ SCOPED_MUTEX_LOCK(unsafe_object_references_lock);
+ ObjectID id = p_obj->get_instance_id();
+ Map<ObjectID, int>::Element *elem = unsafe_object_references.find(id);
+ ERR_FAIL_NULL(elem);
+ if (--elem->value() == 0)
+ unsafe_object_references.erase(elem);
+#endif
+}
+
void CSharpLanguage::frame() {
if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != NULL) {
@@ -659,6 +693,7 @@ void CSharpLanguage::reload_all_scripts() {
#ifdef GD_MONO_HOT_RELOAD
if (is_assembly_reloading_needed()) {
+ GD_MONO_SCOPE_THREAD_ATTACH;
reload_assemblies(false);
}
#endif
@@ -676,6 +711,7 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft
#ifdef GD_MONO_HOT_RELOAD
if (is_assembly_reloading_needed()) {
+ GD_MONO_SCOPE_THREAD_ATTACH;
reload_assemblies(p_soft_reload);
}
#endif
@@ -1044,7 +1080,7 @@ void CSharpLanguage::_load_scripts_metadata() {
int err_line;
Error json_err = JSON::parse(old_json, old_dict_var, err_str, err_line);
if (json_err != OK) {
- ERR_PRINTS("Failed to parse metadata file: '" + err_str + "' (" + String::num_int64(err_line) + ").");
+ ERR_PRINT("Failed to parse metadata file: '" + err_str + "' (" + String::num_int64(err_line) + ").");
return;
}
@@ -1212,6 +1248,14 @@ CSharpLanguage::CSharpLanguage() {
language_bind_mutex = Mutex::create();
#endif
+#ifdef DEBUG_ENABLED
+#ifdef NO_THREADS
+ unsafe_object_references_lock = NULL;
+#else
+ unsafe_object_references_lock = Mutex::create();
+#endif
+#endif
+
lang_idx = -1;
scripts_metadata_invalidated = true;
@@ -1240,6 +1284,13 @@ CSharpLanguage::~CSharpLanguage() {
script_gchandle_release_mutex = NULL;
}
+#ifdef DEBUG_ENABLED
+ if (unsafe_object_references_lock) {
+ memdelete(unsafe_object_references_lock);
+ unsafe_object_references_lock = NULL;
+ }
+#endif
+
singleton = NULL;
}
@@ -1286,6 +1337,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
// See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
ref->reference();
+ CSharpLanguage::get_singleton()->post_unsafe_reference(ref);
}
return true;
@@ -1325,6 +1377,8 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
if (finalizing)
return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
+ GD_MONO_ASSERT_THREAD_ATTACHED;
+
{
SCOPED_MUTEX_LOCK(language_bind_mutex);
@@ -1351,6 +1405,7 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
#ifdef DEBUG_ENABLED
CRASH_COND(!ref_owner);
+ CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
#endif
void *data = p_object->get_script_instance_binding(get_language_index());
@@ -1363,6 +1418,8 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
return;
if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
@@ -1384,6 +1441,7 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
#ifdef DEBUG_ENABLED
CRASH_COND(!ref_owner);
+ CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
#endif
void *data = p_object->get_script_instance_binding(get_language_index());
@@ -1398,6 +1456,8 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
return refcount == 0;
if (refcount == 1 && gchandle.is_valid() && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
@@ -1449,6 +1509,8 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND_V(!script.is_valid(), false);
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
MonoObject *mono_object = get_mono_object();
ERR_FAIL_NULL_V(mono_object, false);
@@ -1501,6 +1563,8 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
ERR_FAIL_COND_V(!script.is_valid(), false);
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
MonoObject *mono_object = get_mono_object();
ERR_FAIL_NULL_V(mono_object, false);
@@ -1594,6 +1658,8 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
ERR_FAIL_COND(!script.is_valid());
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
MonoObject *mono_object = get_mono_object();
ERR_FAIL_NULL(mono_object);
@@ -1638,6 +1704,8 @@ bool CSharpInstance::has_method(const StringName &p_method) const {
if (!script.is_valid())
return false;
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
GDMonoClass *top = script->script_class;
while (top && top != script->native) {
@@ -1653,6 +1721,11 @@ bool CSharpInstance::has_method(const StringName &p_method) const {
Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+ if (!script.is_valid())
+ ERR_FAIL_V(Variant());
+
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
MonoObject *mono_object = get_mono_object();
if (!mono_object) {
@@ -1660,9 +1733,6 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args,
ERR_FAIL_V(Variant());
}
- if (!script.is_valid())
- ERR_FAIL_V(Variant());
-
GDMonoClass *top = script->script_class;
while (top && top != script->native) {
@@ -1690,6 +1760,8 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args,
void CSharpInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
if (script.is_valid()) {
MonoObject *mono_object = get_mono_object();
@@ -1701,6 +1773,8 @@ void CSharpInstance::call_multilevel(const StringName &p_method, const Variant *
void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
+ GD_MONO_ASSERT_THREAD_ATTACHED;
+
GDMonoClass *top = script->script_class;
while (top && top != script->native) {
@@ -1736,9 +1810,12 @@ bool CSharpInstance::_reference_owner_unsafe() {
// See: _unreference_owner_unsafe()
// May not me referenced yet, so we must use init_ref() instead of reference()
- bool success = Object::cast_to<Reference>(owner)->init_ref();
- unsafe_referenced = success;
- return success;
+ if (static_cast<Reference *>(owner)->init_ref()) {
+ CSharpLanguage::get_singleton()->post_unsafe_reference(owner);
+ unsafe_referenced = true;
+ }
+
+ return unsafe_referenced;
}
bool CSharpInstance::_unreference_owner_unsafe() {
@@ -1759,6 +1836,7 @@ bool CSharpInstance::_unreference_owner_unsafe() {
// See: _reference_owner_unsafe()
// Destroying the owner here means self destructing, so we defer the owner destruction to the caller.
+ CSharpLanguage::get_singleton()->pre_unsafe_unreference(owner);
return static_cast<Reference *>(owner)->unreference();
}
@@ -1859,6 +1937,8 @@ void CSharpInstance::refcount_incremented() {
Reference *ref_owner = Object::cast_to<Reference>(owner);
if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
@@ -1882,6 +1962,8 @@ bool CSharpInstance::refcount_decremented() {
int refcount = ref_owner->reference_get_count();
if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
@@ -1922,6 +2004,8 @@ MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(IMonoClassMember *p
MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
GDMonoClass *top = script->script_class;
while (top && top != script->native) {
@@ -1938,6 +2022,8 @@ MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method)
MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const {
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
GDMonoClass *top = script->script_class;
while (top && top != script->native) {
@@ -1959,6 +2045,8 @@ MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variab
void CSharpInstance::notification(int p_notification) {
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
if (p_notification == Object::NOTIFICATION_PREDELETE) {
// When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose().
// It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed
@@ -1996,6 +2084,8 @@ void CSharpInstance::notification(int p_notification) {
void CSharpInstance::_call_notification(int p_notification) {
+ GD_MONO_ASSERT_THREAD_ATTACHED;
+
MonoObject *mono_object = get_mono_object();
ERR_FAIL_NULL(mono_object);
@@ -2020,6 +2110,8 @@ void CSharpInstance::_call_notification(int p_notification) {
}
String CSharpInstance::to_string(bool *r_valid) {
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
MonoObject *mono_object = get_mono_object();
if (mono_object == NULL) {
@@ -2068,6 +2160,8 @@ CSharpInstance::CSharpInstance() :
CSharpInstance::~CSharpInstance() {
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
destructing_script_instance = true;
if (gchandle.is_valid()) {
@@ -2099,6 +2193,17 @@ CSharpInstance::~CSharpInstance() {
// Transfer ownership to an "instance binding"
+ Reference *ref_owner = static_cast<Reference *>(owner);
+
+ // We will unreference the owner before referencing it again, so we need to keep it alive
+ Ref<Reference> scope_keep_owner_alive(ref_owner);
+ (void)scope_keep_owner_alive;
+
+ // Unreference the owner here, before the new "instance binding" references it.
+ // Otherwise, the unsafe reference debug checks will incorrectly detect a bug.
+ bool die = _unreference_owner_unsafe();
+ CRASH_COND(die == true); // `owner_keep_alive` holds a reference, so it can't die
+
void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
CRASH_COND(data == NULL);
@@ -2114,8 +2219,10 @@ CSharpInstance::~CSharpInstance() {
}
}
- bool die = _unreference_owner_unsafe();
- CRASH_COND(die == true); // The "instance binding" should be holding a reference
+#ifdef DEBUG_ENABLED
+ // The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope
+ CRASH_COND(ref_owner->reference_get_count() <= 1);
+#endif
}
if (script.is_valid() && owner) {
@@ -2158,6 +2265,8 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List
void CSharpScript::_update_member_info_no_exports() {
if (exports_invalidated) {
+ GD_MONO_ASSERT_THREAD_ATTACHED;
+
exports_invalidated = false;
member_info.clear();
@@ -2216,6 +2325,8 @@ bool CSharpScript::_update_exports() {
bool changed = false;
if (exports_invalidated) {
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
exports_invalidated = false;
changed = true;
@@ -2243,7 +2354,11 @@ bool CSharpScript::_update_exports() {
MonoException *ctor_exc = NULL;
ctor->invoke(tmp_object, NULL, &ctor_exc);
+ Object *tmp_native = GDMonoMarshal::unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(tmp_object));
+
if (ctor_exc) {
+ // TODO: Should we free 'tmp_native' if the exception was thrown after its creation?
+
MonoGCHandle::free_handle(tmp_pinned_gchandle);
tmp_object = NULL;
@@ -2310,6 +2425,9 @@ bool CSharpScript::_update_exports() {
top = top->get_parent_class();
}
+ // Need to check this here, before disposal
+ bool base_ref = Object::cast_to<Reference>(tmp_native) != NULL;
+
// Dispose the temporary managed instance
MonoException *exc = NULL;
@@ -2322,6 +2440,15 @@ bool CSharpScript::_update_exports() {
MonoGCHandle::free_handle(tmp_pinned_gchandle);
tmp_object = NULL;
+
+ if (tmp_native && !base_ref) {
+ Node *node = Object::cast_to<Node>(tmp_native);
+ if (node && node->is_inside_tree()) {
+ ERR_PRINT("Temporary instance was added to the scene tree.");
+ } else {
+ memdelete(tmp_native);
+ }
+ }
}
placeholder_fallback_enabled = false;
@@ -2352,6 +2479,8 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati
// make sure this classes signals are empty when loading for the first time
_signals.clear();
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
GDMonoClass *top = p_class;
while (top && top != p_native_class) {
const Vector<GDMonoClass *> &delegates = top->get_all_delegates();
@@ -2372,6 +2501,8 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati
}
bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> &params) {
+ GD_MONO_ASSERT_THREAD_ATTACHED;
+
if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
MonoType *raw_type = p_delegate->get_mono_type();
@@ -2391,7 +2522,7 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve
arg.type = GDMonoMarshal::managed_to_variant_type(types[i]);
if (arg.type == Variant::NIL) {
- ERR_PRINTS("Unknown type of signal parameter: '" + arg.name + "' in '" + p_class->get_full_name() + "'.");
+ ERR_PRINT("Unknown type of signal parameter: '" + arg.name + "' in '" + p_class->get_full_name() + "'.");
return false;
}
@@ -2413,13 +2544,15 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve
*/
bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported) {
+ GD_MONO_ASSERT_THREAD_ATTACHED;
+
// Goddammit, C++. All I wanted was some nested functions.
#define MEMBER_FULL_QUALIFIED_NAME(m_member) \
(m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name())
if (p_member->is_static()) {
if (p_member->has_attribute(CACHED_CLASS(ExportAttribute)))
- ERR_PRINTS("Cannot export member because it is static: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
+ ERR_PRINT("Cannot export member because it is static: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
return false;
}
@@ -2442,12 +2575,12 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
if (!property->has_getter()) {
if (exported)
- ERR_PRINTS("Read-only property cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
+ ERR_PRINT("Read-only property cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
return false;
}
if (!property->has_setter()) {
if (exported)
- ERR_PRINTS("Write-only property (without getter) cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
+ ERR_PRINT("Write-only property (without getter) cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
return false;
}
}
@@ -2466,7 +2599,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
String hint_string;
if (variant_type == Variant::NIL) {
- ERR_PRINTS("Unknown exported member type: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
+ ERR_PRINT("Unknown exported member type: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
return false;
}
@@ -2491,6 +2624,8 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) {
+ GD_MONO_ASSERT_THREAD_ATTACHED;
+
if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) {
r_hint = PROPERTY_HINT_ENUM;
@@ -2600,6 +2735,8 @@ Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, i
return Variant();
}
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
GDMonoClass *top = script_class;
while (top && top != native) {
@@ -2754,7 +2891,7 @@ bool CSharpScript::can_instance() const {
"Compile",
ProjectSettings::get_singleton()->globalize_path(get_path()));
} else {
- ERR_PRINTS("C# project could not be created; cannot add file: '" + get_path() + "'.");
+ ERR_PRINT("C# project could not be created; cannot add file: '" + get_path() + "'.");
}
}
}
@@ -2792,6 +2929,8 @@ StringName CSharpScript::get_instance_base_type() const {
CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) {
+ GD_MONO_ASSERT_THREAD_ATTACHED;
+
/* STEP 1, CREATE */
// Search the constructor first, to fail with an error if it's not found before allocating anything else.
@@ -2886,12 +3025,14 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call
}
r_error.error = Variant::CallError::CALL_OK;
- REF ref;
ERR_FAIL_NULL_V(native, Variant());
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native));
+ REF ref;
Reference *r = Object::cast_to<Reference>(owner);
if (r) {
ref = REF(r);
@@ -2929,6 +3070,8 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
}
}
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
Variant::CallError unchecked_error;
return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error);
}
@@ -2976,6 +3119,8 @@ void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const {
if (!script_class)
return;
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
// TODO: Filter out things unsuitable for explicit calls, like constructors.
const Vector<GDMonoMethod *> &methods = script_class->get_all_methods();
for (int i = 0; i < methods.size(); ++i) {
@@ -2988,6 +3133,8 @@ bool CSharpScript::has_method(const StringName &p_method) const {
if (!script_class)
return false;
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
return script_class->has_fetched_method_unknown_params(p_method);
}
@@ -2996,6 +3143,8 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const {
if (!script_class)
return MethodInfo();
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
GDMonoClass *top = script_class;
while (top && top != native) {
@@ -3020,6 +3169,8 @@ Error CSharpScript::reload(bool p_keep_state) {
ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE);
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
GDMonoAssembly *project_assembly = GDMono::get_singleton()->get_project_assembly();
if (project_assembly) {
@@ -3247,39 +3398,7 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p
script->set_path(p_original_path);
-#ifndef TOOLS_ENABLED
-
-#ifdef DEBUG_ENABLED
- // User is responsible for thread attach/detach
- CRASH_COND_MSG(mono_domain_get() == NULL, "Thread is not attached.");
-#endif
-
-#endif
-
-#ifdef TOOLS_ENABLED
- MonoDomain *domain = mono_domain_get();
- if (Engine::get_singleton()->is_editor_hint() && domain == NULL) {
-
- CRASH_COND(Thread::get_caller_id() == Thread::get_main_id());
-
- // Thread is not attached, but we will make an exception in this case
- // because this may be called by one of the editor's worker threads.
- // Attach this thread temporarily to reload the script.
-
- if (domain) {
- MonoThread *mono_thread = mono_thread_attach(domain);
- CRASH_COND(mono_thread == NULL);
- script->reload();
- mono_thread_detach(mono_thread);
- }
-
- } else { // just reload it normally
-#endif
- script->reload();
-
-#ifdef TOOLS_ENABLED
- }
-#endif
+ script->reload();
if (r_error)
*r_error = OK;
@@ -3318,7 +3437,7 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
"Compile",
ProjectSettings::get_singleton()->globalize_path(p_path));
} else {
- ERR_PRINTS("C# project could not be created; cannot add file: '" + p_path + "'.");
+ ERR_PRINT("C# project could not be created; cannot add file: '" + p_path + "'.");
}
}
#endif