Merge pull request #35208 from neikeq/mono-lazy-thread-attach
Mono/C#: Script interface calls now attach the current thread
This commit is contained in:
commit
1191d26ddc
3 changed files with 128 additions and 42 deletions
|
@ -559,6 +559,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>());
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoCache::cached_data.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>();
|
||||||
|
@ -583,6 +584,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
|
||||||
Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
|
Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
|
||||||
|
|
||||||
_TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
|
_TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
MonoException *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
|
|
||||||
|
@ -689,6 +691,7 @@ void CSharpLanguage::reload_all_scripts() {
|
||||||
|
|
||||||
#ifdef GD_MONO_HOT_RELOAD
|
#ifdef GD_MONO_HOT_RELOAD
|
||||||
if (is_assembly_reloading_needed()) {
|
if (is_assembly_reloading_needed()) {
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
reload_assemblies(false);
|
reload_assemblies(false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -706,6 +709,7 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft
|
||||||
|
|
||||||
#ifdef GD_MONO_HOT_RELOAD
|
#ifdef GD_MONO_HOT_RELOAD
|
||||||
if (is_assembly_reloading_needed()) {
|
if (is_assembly_reloading_needed()) {
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
reload_assemblies(p_soft_reload);
|
reload_assemblies(p_soft_reload);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1356,6 +1360,8 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
|
||||||
if (finalizing)
|
if (finalizing)
|
||||||
return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
|
return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
|
||||||
|
|
||||||
|
GD_MONO_ASSERT_THREAD_ATTACHED;
|
||||||
|
|
||||||
{
|
{
|
||||||
SCOPED_MUTEX_LOCK(language_bind_mutex);
|
SCOPED_MUTEX_LOCK(language_bind_mutex);
|
||||||
|
|
||||||
|
@ -1382,6 +1388,7 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
CRASH_COND(!ref_owner);
|
CRASH_COND(!ref_owner);
|
||||||
|
CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *data = p_object->get_script_instance_binding(get_language_index());
|
void *data = p_object->get_script_instance_binding(get_language_index());
|
||||||
|
@ -1394,6 +1401,8 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
|
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.
|
// 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,
|
// 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.
|
// so the owner must hold the managed side alive again to avoid it from being GCed.
|
||||||
|
@ -1415,6 +1424,7 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
CRASH_COND(!ref_owner);
|
CRASH_COND(!ref_owner);
|
||||||
|
CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *data = p_object->get_script_instance_binding(get_language_index());
|
void *data = p_object->get_script_instance_binding(get_language_index());
|
||||||
|
@ -1429,6 +1439,8 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
|
||||||
return refcount == 0;
|
return refcount == 0;
|
||||||
|
|
||||||
if (refcount == 1 && gchandle.is_valid() && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 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,
|
// If owner owner is no longer referenced by the unmanaged side,
|
||||||
// the managed instance takes responsibility of deleting the owner when GCed.
|
// the managed instance takes responsibility of deleting the owner when GCed.
|
||||||
|
|
||||||
|
@ -1480,6 +1492,8 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!script.is_valid(), false);
|
ERR_FAIL_COND_V(!script.is_valid(), false);
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
MonoObject *mono_object = get_mono_object();
|
MonoObject *mono_object = get_mono_object();
|
||||||
ERR_FAIL_NULL_V(mono_object, false);
|
ERR_FAIL_NULL_V(mono_object, false);
|
||||||
|
|
||||||
|
@ -1532,6 +1546,8 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!script.is_valid(), false);
|
ERR_FAIL_COND_V(!script.is_valid(), false);
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
MonoObject *mono_object = get_mono_object();
|
MonoObject *mono_object = get_mono_object();
|
||||||
ERR_FAIL_NULL_V(mono_object, false);
|
ERR_FAIL_NULL_V(mono_object, false);
|
||||||
|
|
||||||
|
@ -1625,6 +1641,8 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
|
||||||
|
|
||||||
ERR_FAIL_COND(!script.is_valid());
|
ERR_FAIL_COND(!script.is_valid());
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
MonoObject *mono_object = get_mono_object();
|
MonoObject *mono_object = get_mono_object();
|
||||||
ERR_FAIL_NULL(mono_object);
|
ERR_FAIL_NULL(mono_object);
|
||||||
|
|
||||||
|
@ -1669,6 +1687,8 @@ bool CSharpInstance::has_method(const StringName &p_method) const {
|
||||||
if (!script.is_valid())
|
if (!script.is_valid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
GDMonoClass *top = script->script_class;
|
GDMonoClass *top = script->script_class;
|
||||||
|
|
||||||
while (top && top != script->native) {
|
while (top && top != script->native) {
|
||||||
|
@ -1684,6 +1704,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) {
|
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();
|
MonoObject *mono_object = get_mono_object();
|
||||||
|
|
||||||
if (!mono_object) {
|
if (!mono_object) {
|
||||||
|
@ -1691,9 +1716,6 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args,
|
||||||
ERR_FAIL_V(Variant());
|
ERR_FAIL_V(Variant());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!script.is_valid())
|
|
||||||
ERR_FAIL_V(Variant());
|
|
||||||
|
|
||||||
GDMonoClass *top = script->script_class;
|
GDMonoClass *top = script->script_class;
|
||||||
|
|
||||||
while (top && top != script->native) {
|
while (top && top != script->native) {
|
||||||
|
@ -1721,6 +1743,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) {
|
void CSharpInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
if (script.is_valid()) {
|
if (script.is_valid()) {
|
||||||
MonoObject *mono_object = get_mono_object();
|
MonoObject *mono_object = get_mono_object();
|
||||||
|
|
||||||
|
@ -1732,6 +1756,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) {
|
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;
|
GDMonoClass *top = script->script_class;
|
||||||
|
|
||||||
while (top && top != script->native) {
|
while (top && top != script->native) {
|
||||||
|
@ -1894,6 +1920,8 @@ void CSharpInstance::refcount_incremented() {
|
||||||
Reference *ref_owner = Object::cast_to<Reference>(owner);
|
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
|
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.
|
// 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,
|
// 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.
|
// so the owner must hold the managed side alive again to avoid it from being GCed.
|
||||||
|
@ -1917,6 +1945,8 @@ bool CSharpInstance::refcount_decremented() {
|
||||||
int refcount = ref_owner->reference_get_count();
|
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
|
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,
|
// If owner owner is no longer referenced by the unmanaged side,
|
||||||
// the managed instance takes responsibility of deleting the owner when GCed.
|
// the managed instance takes responsibility of deleting the owner when GCed.
|
||||||
|
|
||||||
|
@ -1957,6 +1987,8 @@ MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(IMonoClassMember *p
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
|
MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
GDMonoClass *top = script->script_class;
|
GDMonoClass *top = script->script_class;
|
||||||
|
|
||||||
while (top && top != script->native) {
|
while (top && top != script->native) {
|
||||||
|
@ -1973,6 +2005,8 @@ MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method)
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const {
|
MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
GDMonoClass *top = script->script_class;
|
GDMonoClass *top = script->script_class;
|
||||||
|
|
||||||
while (top && top != script->native) {
|
while (top && top != script->native) {
|
||||||
|
@ -1994,6 +2028,8 @@ MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variab
|
||||||
|
|
||||||
void CSharpInstance::notification(int p_notification) {
|
void CSharpInstance::notification(int p_notification) {
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
if (p_notification == Object::NOTIFICATION_PREDELETE) {
|
if (p_notification == Object::NOTIFICATION_PREDELETE) {
|
||||||
// When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose().
|
// 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
|
// It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed
|
||||||
|
@ -2031,6 +2067,8 @@ void CSharpInstance::notification(int p_notification) {
|
||||||
|
|
||||||
void CSharpInstance::_call_notification(int p_notification) {
|
void CSharpInstance::_call_notification(int p_notification) {
|
||||||
|
|
||||||
|
GD_MONO_ASSERT_THREAD_ATTACHED;
|
||||||
|
|
||||||
MonoObject *mono_object = get_mono_object();
|
MonoObject *mono_object = get_mono_object();
|
||||||
ERR_FAIL_NULL(mono_object);
|
ERR_FAIL_NULL(mono_object);
|
||||||
|
|
||||||
|
@ -2055,6 +2093,8 @@ void CSharpInstance::_call_notification(int p_notification) {
|
||||||
}
|
}
|
||||||
|
|
||||||
String CSharpInstance::to_string(bool *r_valid) {
|
String CSharpInstance::to_string(bool *r_valid) {
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
MonoObject *mono_object = get_mono_object();
|
MonoObject *mono_object = get_mono_object();
|
||||||
|
|
||||||
if (mono_object == NULL) {
|
if (mono_object == NULL) {
|
||||||
|
@ -2103,6 +2143,8 @@ CSharpInstance::CSharpInstance() :
|
||||||
|
|
||||||
CSharpInstance::~CSharpInstance() {
|
CSharpInstance::~CSharpInstance() {
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
destructing_script_instance = true;
|
destructing_script_instance = true;
|
||||||
|
|
||||||
if (gchandle.is_valid()) {
|
if (gchandle.is_valid()) {
|
||||||
|
@ -2206,6 +2248,8 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List
|
||||||
void CSharpScript::_update_member_info_no_exports() {
|
void CSharpScript::_update_member_info_no_exports() {
|
||||||
|
|
||||||
if (exports_invalidated) {
|
if (exports_invalidated) {
|
||||||
|
GD_MONO_ASSERT_THREAD_ATTACHED;
|
||||||
|
|
||||||
exports_invalidated = false;
|
exports_invalidated = false;
|
||||||
|
|
||||||
member_info.clear();
|
member_info.clear();
|
||||||
|
@ -2264,6 +2308,8 @@ bool CSharpScript::_update_exports() {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
if (exports_invalidated) {
|
if (exports_invalidated) {
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
exports_invalidated = false;
|
exports_invalidated = false;
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
|
@ -2413,6 +2459,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
|
// make sure this classes signals are empty when loading for the first time
|
||||||
_signals.clear();
|
_signals.clear();
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
GDMonoClass *top = p_class;
|
GDMonoClass *top = p_class;
|
||||||
while (top && top != p_native_class) {
|
while (top && top != p_native_class) {
|
||||||
const Vector<GDMonoClass *> &delegates = top->get_all_delegates();
|
const Vector<GDMonoClass *> &delegates = top->get_all_delegates();
|
||||||
|
@ -2433,6 +2481,8 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms) {
|
bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms) {
|
||||||
|
GD_MONO_ASSERT_THREAD_ATTACHED;
|
||||||
|
|
||||||
if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
|
if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
|
||||||
MonoType *raw_type = p_delegate->get_mono_type();
|
MonoType *raw_type = p_delegate->get_mono_type();
|
||||||
|
|
||||||
|
@ -2474,6 +2524,8 @@ 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) {
|
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.
|
// Goddammit, C++. All I wanted was some nested functions.
|
||||||
#define MEMBER_FULL_QUALIFIED_NAME(m_member) \
|
#define MEMBER_FULL_QUALIFIED_NAME(m_member) \
|
||||||
(m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name())
|
(m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name())
|
||||||
|
@ -2552,6 +2604,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) {
|
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())) {
|
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;
|
r_hint = PROPERTY_HINT_ENUM;
|
||||||
|
|
||||||
|
@ -2661,6 +2715,8 @@ Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, i
|
||||||
return Variant();
|
return Variant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
GDMonoClass *top = script_class;
|
GDMonoClass *top = script_class;
|
||||||
|
|
||||||
while (top && top != native) {
|
while (top && top != native) {
|
||||||
|
@ -2853,6 +2909,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) {
|
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 */
|
/* STEP 1, CREATE */
|
||||||
|
|
||||||
// Search the constructor first, to fail with an error if it's not found before allocating anything else.
|
// Search the constructor first, to fail with an error if it's not found before allocating anything else.
|
||||||
|
@ -2947,12 +3005,14 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call
|
||||||
}
|
}
|
||||||
|
|
||||||
r_error.error = Variant::CallError::CALL_OK;
|
r_error.error = Variant::CallError::CALL_OK;
|
||||||
REF ref;
|
|
||||||
|
|
||||||
ERR_FAIL_NULL_V(native, Variant());
|
ERR_FAIL_NULL_V(native, Variant());
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native));
|
Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native));
|
||||||
|
|
||||||
|
REF ref;
|
||||||
Reference *r = Object::cast_to<Reference>(owner);
|
Reference *r = Object::cast_to<Reference>(owner);
|
||||||
if (r) {
|
if (r) {
|
||||||
ref = REF(r);
|
ref = REF(r);
|
||||||
|
@ -2990,6 +3050,8 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
Variant::CallError unchecked_error;
|
Variant::CallError unchecked_error;
|
||||||
return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error);
|
return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error);
|
||||||
}
|
}
|
||||||
|
@ -3037,6 +3099,8 @@ void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const {
|
||||||
if (!script_class)
|
if (!script_class)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
// TODO: Filter out things unsuitable for explicit calls, like constructors.
|
// TODO: Filter out things unsuitable for explicit calls, like constructors.
|
||||||
const Vector<GDMonoMethod *> &methods = script_class->get_all_methods();
|
const Vector<GDMonoMethod *> &methods = script_class->get_all_methods();
|
||||||
for (int i = 0; i < methods.size(); ++i) {
|
for (int i = 0; i < methods.size(); ++i) {
|
||||||
|
@ -3049,6 +3113,8 @@ bool CSharpScript::has_method(const StringName &p_method) const {
|
||||||
if (!script_class)
|
if (!script_class)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
return script_class->has_fetched_method_unknown_params(p_method);
|
return script_class->has_fetched_method_unknown_params(p_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3057,6 +3123,8 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const {
|
||||||
if (!script_class)
|
if (!script_class)
|
||||||
return MethodInfo();
|
return MethodInfo();
|
||||||
|
|
||||||
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
GDMonoClass *top = script_class;
|
GDMonoClass *top = script_class;
|
||||||
|
|
||||||
while (top && top != native) {
|
while (top && top != native) {
|
||||||
|
@ -3081,6 +3149,8 @@ Error CSharpScript::reload(bool p_keep_state) {
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE);
|
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();
|
GDMonoAssembly *project_assembly = GDMono::get_singleton()->get_project_assembly();
|
||||||
|
|
||||||
if (project_assembly) {
|
if (project_assembly) {
|
||||||
|
@ -3308,39 +3378,7 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p
|
||||||
|
|
||||||
script->set_path(p_original_path);
|
script->set_path(p_original_path);
|
||||||
|
|
||||||
#ifndef TOOLS_ENABLED
|
script->reload();
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
if (r_error)
|
if (r_error)
|
||||||
*r_error = OK;
|
*r_error = OK;
|
||||||
|
|
|
@ -125,10 +125,12 @@ void set_main_thread(MonoThread *p_thread) {
|
||||||
mono_thread_set_main(p_thread);
|
mono_thread_set_main(p_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void attach_current_thread() {
|
MonoThread *attach_current_thread() {
|
||||||
ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
|
ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), NULL);
|
||||||
MonoThread *mono_thread = mono_thread_attach(mono_get_root_domain());
|
MonoDomain *scripts_domain = GDMono::get_singleton()->get_scripts_domain();
|
||||||
ERR_FAIL_NULL(mono_thread);
|
MonoThread *mono_thread = mono_thread_attach(scripts_domain ? scripts_domain : mono_get_root_domain());
|
||||||
|
ERR_FAIL_NULL_V(mono_thread, NULL);
|
||||||
|
return mono_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void detach_current_thread() {
|
void detach_current_thread() {
|
||||||
|
@ -138,10 +140,20 @@ void detach_current_thread() {
|
||||||
mono_thread_detach(mono_thread);
|
mono_thread_detach(mono_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void detach_current_thread(MonoThread *p_mono_thread) {
|
||||||
|
ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
|
||||||
|
ERR_FAIL_NULL(p_mono_thread);
|
||||||
|
mono_thread_detach(p_mono_thread);
|
||||||
|
}
|
||||||
|
|
||||||
MonoThread *get_current_thread() {
|
MonoThread *get_current_thread() {
|
||||||
return mono_thread_current();
|
return mono_thread_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_thread_attached() {
|
||||||
|
return mono_domain_get() != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) {
|
void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) {
|
||||||
GDMonoMethod *ctor = p_class->get_method(".ctor", 0);
|
GDMonoMethod *ctor = p_class->get_method(".ctor", 0);
|
||||||
ERR_FAIL_NULL(ctor);
|
ERR_FAIL_NULL(ctor);
|
||||||
|
@ -617,4 +629,19 @@ GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, Mon
|
||||||
|
|
||||||
} // namespace Marshal
|
} // namespace Marshal
|
||||||
|
|
||||||
|
ScopeThreadAttach::ScopeThreadAttach() :
|
||||||
|
mono_thread(NULL) {
|
||||||
|
if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) {
|
||||||
|
mono_thread = GDMonoUtils::attach_current_thread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeThreadAttach::~ScopeThreadAttach() {
|
||||||
|
if (unlikely(mono_thread)) {
|
||||||
|
GDMonoUtils::detach_current_thread(mono_thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// namespace Marshal
|
||||||
|
|
||||||
} // namespace GDMonoUtils
|
} // namespace GDMonoUtils
|
||||||
|
|
|
@ -83,9 +83,11 @@ _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash)
|
||||||
MonoObject *unmanaged_get_managed(Object *unmanaged);
|
MonoObject *unmanaged_get_managed(Object *unmanaged);
|
||||||
|
|
||||||
void set_main_thread(MonoThread *p_thread);
|
void set_main_thread(MonoThread *p_thread);
|
||||||
void attach_current_thread();
|
MonoThread *attach_current_thread();
|
||||||
void detach_current_thread();
|
void detach_current_thread();
|
||||||
|
void detach_current_thread(MonoThread *p_mono_thread);
|
||||||
MonoThread *get_current_thread();
|
MonoThread *get_current_thread();
|
||||||
|
bool is_thread_attached();
|
||||||
|
|
||||||
_FORCE_INLINE_ bool is_main_thread() {
|
_FORCE_INLINE_ bool is_main_thread() {
|
||||||
return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
|
return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
|
||||||
|
@ -142,6 +144,14 @@ 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);
|
||||||
|
|
||||||
|
struct ScopeThreadAttach {
|
||||||
|
ScopeThreadAttach();
|
||||||
|
~ScopeThreadAttach();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MonoThread *mono_thread;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace GDMonoUtils
|
} // namespace GDMonoUtils
|
||||||
|
|
||||||
#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)))
|
||||||
|
@ -153,4 +163,15 @@ 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;
|
||||||
|
|
||||||
|
#define GD_MONO_SCOPE_THREAD_ATTACH \
|
||||||
|
GDMonoUtils::ScopeThreadAttach __gdmono__scope__thread__attach__; \
|
||||||
|
(void)__gdmono__scope__thread__attach__;
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
#define GD_MONO_ASSERT_THREAD_ATTACHED \
|
||||||
|
{ CRASH_COND(!GDMonoUtils::is_thread_attached()); }
|
||||||
|
#else
|
||||||
|
#define GD_MONO_ASSERT_THREAD_ATTACHED
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // GD_MONOUTILS_H
|
#endif // GD_MONOUTILS_H
|
||||||
|
|
Loading…
Reference in a new issue