Mono: Pending exceptions and cleanup
(cherry picked from commit 4739cb8c00
)
This commit is contained in:
parent
291be24742
commit
e1cf8dc2cb
|
@ -5,9 +5,11 @@ Import('env_modules')
|
|||
|
||||
env_mono = env_modules.Clone()
|
||||
|
||||
from compat import byte_to_str
|
||||
# TODO move functions to their own modules
|
||||
|
||||
def make_cs_files_header(src, dst):
|
||||
from compat import byte_to_str
|
||||
|
||||
with open(dst, 'w') as header:
|
||||
header.write('/* This is an automatically generated file; DO NOT EDIT! OK THX */\n')
|
||||
header.write('#ifndef _CS_FILES_DATA_H\n')
|
||||
|
@ -75,6 +77,13 @@ else:
|
|||
if ARGUMENTS.get('yolo_copy', False):
|
||||
env_mono.Append(CPPDEFINES=['YOLO_COPY'])
|
||||
|
||||
# Configure TLS checks
|
||||
|
||||
import tls_configure
|
||||
conf = Configure(env_mono)
|
||||
tls_configure.configure(conf)
|
||||
env_mono = conf.Finish()
|
||||
|
||||
|
||||
# Build GodotSharpTools solution
|
||||
|
||||
|
@ -127,6 +136,21 @@ def find_msbuild_windows():
|
|||
if not mono_root:
|
||||
raise RuntimeError('Cannot find mono root directory')
|
||||
|
||||
framework_path = os.path.join(mono_root, 'lib', 'mono', '4.5')
|
||||
mono_bin_dir = os.path.join(mono_root, 'bin')
|
||||
msbuild_mono = os.path.join(mono_bin_dir, 'msbuild.bat')
|
||||
|
||||
if os.path.isfile(msbuild_mono):
|
||||
# The (Csc/Vbc/Fsc)ToolExe environment variables are required when
|
||||
# building with Mono's MSBuild. They must point to the batch files
|
||||
# in Mono's bin directory to make sure they are executed with Mono.
|
||||
mono_msbuild_env = {
|
||||
'CscToolExe': os.path.join(mono_bin_dir, 'csc.bat'),
|
||||
'VbcToolExe': os.path.join(mono_bin_dir, 'vbc.bat'),
|
||||
'FscToolExe': os.path.join(mono_bin_dir, 'fsharpc.bat')
|
||||
}
|
||||
return (msbuild_mono, framework_path, mono_msbuild_env)
|
||||
|
||||
msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
|
||||
|
||||
if msbuild_tools_path:
|
||||
|
|
|
@ -5,6 +5,8 @@ import sys
|
|||
import subprocess
|
||||
|
||||
from SCons.Script import BoolVariable, Dir, Environment, PathVariable, Variables
|
||||
from distutils.version import LooseVersion
|
||||
from SCons.Script import BoolVariable, Dir, Environment, File, PathVariable, SCons, Variables
|
||||
|
||||
|
||||
monoreg = imp.load_source('mono_reg_utils', 'modules/mono/mono_reg_utils.py')
|
||||
|
@ -20,7 +22,7 @@ def find_file_in_dir(directory, files, prefix='', extension=''):
|
|||
|
||||
|
||||
def can_build(platform):
|
||||
if platform in ["javascript"]:
|
||||
if platform in ['javascript']:
|
||||
return False # Not yet supported
|
||||
return True
|
||||
|
||||
|
@ -30,6 +32,27 @@ def is_enabled():
|
|||
return False
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
'@C#',
|
||||
'CSharpScript',
|
||||
'GodotSharp',
|
||||
]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return 'doc_classes'
|
||||
|
||||
|
||||
def find_file_in_dir(directory, files, prefix='', extension=''):
|
||||
if not extension.startswith('.'):
|
||||
extension = '.' + extension
|
||||
for curfile in files:
|
||||
if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
|
||||
return curfile
|
||||
return ''
|
||||
|
||||
|
||||
def copy_file(src_dir, dst_dir, name):
|
||||
from shutil import copyfile
|
||||
|
||||
|
@ -44,7 +67,7 @@ def copy_file(src_dir, dst_dir, name):
|
|||
|
||||
def configure(env):
|
||||
env.use_ptrcall = True
|
||||
env.add_module_version_string("mono")
|
||||
env.add_module_version_string('mono')
|
||||
|
||||
envvars = Variables()
|
||||
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
|
||||
|
@ -73,6 +96,9 @@ def configure(env):
|
|||
if not mono_root:
|
||||
raise RuntimeError('Mono installation directory not found')
|
||||
|
||||
mono_version = mono_root_try_find_mono_version(mono_root)
|
||||
configure_for_mono_version(env, mono_version)
|
||||
|
||||
mono_lib_path = os.path.join(mono_root, 'lib')
|
||||
|
||||
env.Append(LIBPATH=mono_lib_path)
|
||||
|
@ -135,7 +161,17 @@ def configure(env):
|
|||
if os.getenv('MONO64_PREFIX'):
|
||||
mono_root = os.getenv('MONO64_PREFIX')
|
||||
|
||||
# We can't use pkg-config to link mono statically,
|
||||
# but we can still use it to find the mono root directory
|
||||
if not mono_root and mono_static:
|
||||
mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext)
|
||||
if not mono_root:
|
||||
raise RuntimeError('Building with mono_static=yes, but failed to find the mono prefix with pkg-config. Specify one manually')
|
||||
|
||||
if mono_root:
|
||||
mono_version = mono_root_try_find_mono_version(mono_root)
|
||||
configure_for_mono_version(env, mono_version)
|
||||
|
||||
mono_lib_path = os.path.join(mono_root, 'lib')
|
||||
|
||||
env.Append(LIBPATH=mono_lib_path)
|
||||
|
@ -151,18 +187,18 @@ def configure(env):
|
|||
if mono_static:
|
||||
mono_lib_file = os.path.join(mono_lib_path, 'lib' + mono_lib + '.a')
|
||||
|
||||
if sys.platform == "darwin":
|
||||
if sys.platform == 'darwin':
|
||||
env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file])
|
||||
elif sys.platform == "linux" or sys.platform == "linux2":
|
||||
elif sys.platform == 'linux' or sys.platform == 'linux2':
|
||||
env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
|
||||
else:
|
||||
raise RuntimeError('mono-static: Not supported on this platform')
|
||||
else:
|
||||
env.Append(LIBS=[mono_lib])
|
||||
|
||||
if sys.platform == "darwin":
|
||||
if sys.platform == 'darwin':
|
||||
env.Append(LIBS=['iconv', 'pthread'])
|
||||
elif sys.platform == "linux" or sys.platform == "linux2":
|
||||
elif sys.platform == 'linux' or sys.platform == 'linux2':
|
||||
env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
|
||||
|
||||
if not mono_static:
|
||||
|
@ -178,11 +214,14 @@ def configure(env):
|
|||
if mono_static:
|
||||
raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually')
|
||||
|
||||
mono_version = pkgconfig_try_find_mono_version()
|
||||
configure_for_mono_version(env, mono_version)
|
||||
|
||||
env.ParseConfig('pkg-config monosgen-2 --cflags --libs')
|
||||
|
||||
mono_lib_path = ''
|
||||
mono_so_name = ''
|
||||
mono_prefix = subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).strip()
|
||||
mono_prefix = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
|
||||
|
||||
tmpenv = Environment()
|
||||
tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
|
||||
|
@ -204,13 +243,41 @@ def configure(env):
|
|||
env.Append(LINKFLAGS='-rdynamic')
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
"@C#",
|
||||
"CSharpScript",
|
||||
"GodotSharp",
|
||||
]
|
||||
def configure_for_mono_version(env, mono_version):
|
||||
if mono_version is None:
|
||||
raise RuntimeError('Mono JIT compiler version not found')
|
||||
print('Mono JIT compiler version: ' + str(mono_version))
|
||||
if mono_version >= LooseVersion("5.12.0"):
|
||||
env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS'])
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
||||
def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
|
||||
tmpenv = Environment()
|
||||
tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
|
||||
tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
|
||||
for hint_dir in tmpenv['LIBPATH']:
|
||||
name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
|
||||
if name_found and os.path.isdir(os.path.join(hint_dir, '..', 'include', 'mono-2.0')):
|
||||
return os.path.join(hint_dir, '..')
|
||||
return ''
|
||||
|
||||
|
||||
def pkgconfig_try_find_mono_version():
|
||||
lines = subprocess.check_output(['pkg-config', 'monosgen-2', '--modversion']).splitlines()
|
||||
greater_version = None
|
||||
for line in lines:
|
||||
try:
|
||||
version = LooseVersion(line)
|
||||
if greater_version is None or version > greater_version:
|
||||
greater_version = version
|
||||
except ValueError:
|
||||
pass
|
||||
return greater_version
|
||||
|
||||
|
||||
def mono_root_try_find_mono_version(mono_root):
|
||||
first_line = subprocess.check_output([os.path.join(mono_root, 'bin', 'mono'), '--version']).splitlines()[0]
|
||||
try:
|
||||
return LooseVersion(first_line.split()[len('Mono JIT compiler version'.split())])
|
||||
except (ValueError, IndexError):
|
||||
return None
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
#include "mono_gd/gd_mono_class.h"
|
||||
#include "mono_gd/gd_mono_marshal.h"
|
||||
#include "signal_awaiter_utils.h"
|
||||
#include "utils/macros.h"
|
||||
#include "utils/thread_local.h"
|
||||
|
||||
#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->get_string_names().m_var)
|
||||
|
||||
|
@ -476,7 +478,7 @@ String CSharpLanguage::_get_indentation() const {
|
|||
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// Printing an error here will result in endless recursion, so we must be careful
|
||||
_TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
|
||||
|
||||
if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated)
|
||||
return Vector<StackInfo>();
|
||||
|
@ -500,15 +502,15 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
|
|||
#ifdef DEBUG_ENABLED
|
||||
Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
|
||||
|
||||
// Printing an error here could result in endless recursion, so we must be careful
|
||||
_TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
|
||||
|
||||
MonoObject *exc = NULL;
|
||||
MonoException *exc = NULL;
|
||||
|
||||
GDMonoUtils::StackTrace_GetFrames st_get_frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames);
|
||||
MonoArray *frames = st_get_frames(p_stack_trace, &exc);
|
||||
MonoArray *frames = st_get_frames(p_stack_trace, (MonoObject **)&exc);
|
||||
|
||||
if (exc) {
|
||||
GDMonoUtils::print_unhandled_exception(exc, true /* fail silently to avoid endless recursion */);
|
||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||
return Vector<StackInfo>();
|
||||
}
|
||||
|
||||
|
@ -529,10 +531,10 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
|
|||
MonoString *file_name;
|
||||
int file_line_num;
|
||||
MonoString *method_decl;
|
||||
get_sf_info(frame, &file_name, &file_line_num, &method_decl, &exc);
|
||||
get_sf_info(frame, &file_name, &file_line_num, &method_decl, (MonoObject **)&exc);
|
||||
|
||||
if (exc) {
|
||||
GDMonoUtils::print_unhandled_exception(exc, true /* fail silently to avoid endless recursion */);
|
||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||
return Vector<StackInfo>();
|
||||
}
|
||||
|
||||
|
@ -561,12 +563,12 @@ void CSharpLanguage::frame() {
|
|||
|
||||
ERR_FAIL_NULL(thunk);
|
||||
|
||||
MonoObject *ex;
|
||||
thunk(task_scheduler, &ex);
|
||||
MonoException *exc = NULL;
|
||||
thunk(task_scheduler, (MonoObject **)&exc);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
ERR_FAIL();
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
_UNREACHABLE_();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1077,11 +1079,11 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
|
|||
GDMonoProperty *property = top->get_property(p_name);
|
||||
|
||||
if (property) {
|
||||
MonoObject *exc = NULL;
|
||||
MonoException *exc = NULL;
|
||||
MonoObject *value = property->get_value(mono_object, &exc);
|
||||
if (exc) {
|
||||
r_ret = Variant();
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
} else {
|
||||
r_ret = GDMonoMarshal::mono_object_to_variant(value);
|
||||
}
|
||||
|
@ -1483,12 +1485,12 @@ bool CSharpScript::_update_exports() {
|
|||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(tmp_object, tmp_object); // FIXME WTF is this workaround
|
||||
|
||||
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
|
||||
MonoObject *ex = NULL;
|
||||
ctor->invoke(tmp_object, NULL, &ex);
|
||||
MonoException *exc = NULL;
|
||||
ctor->invoke(tmp_object, NULL, &exc);
|
||||
|
||||
if (ex) {
|
||||
if (exc) {
|
||||
ERR_PRINT("Exception thrown from constructor of temporary MonoObject:");
|
||||
mono_print_unhandled_exception(ex);
|
||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||
tmp_object = NULL;
|
||||
ERR_FAIL_V(false);
|
||||
}
|
||||
|
@ -1537,11 +1539,11 @@ bool CSharpScript::_update_exports() {
|
|||
exported_members_cache.push_front(prop_info);
|
||||
|
||||
if (tmp_object) {
|
||||
MonoObject *exc = NULL;
|
||||
MonoException *exc = NULL;
|
||||
MonoObject *ret = property->get_value(tmp_object, &exc);
|
||||
if (exc) {
|
||||
exported_members_defval_cache[name] = Variant();
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||
} else {
|
||||
exported_members_defval_cache[name] = GDMonoMarshal::mono_object_to_variant(ret);
|
||||
}
|
||||
|
@ -1903,7 +1905,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
|
|||
|
||||
// Construct
|
||||
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
|
||||
ctor->invoke(mono_object, p_args, NULL);
|
||||
ctor->invoke(mono_object, p_args);
|
||||
|
||||
// Tie managed to unmanaged
|
||||
instance->gchandle = MonoGCHandle::create_strong(mono_object);
|
||||
|
|
|
@ -47,11 +47,11 @@ String generate_core_api_project(const String &p_dir, const Vector<String> &p_fi
|
|||
Variant dir = p_dir;
|
||||
Variant compile_items = p_files;
|
||||
const Variant *args[2] = { &dir, &compile_items };
|
||||
MonoObject *ex = NULL;
|
||||
MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &ex);
|
||||
MonoException *exc = NULL;
|
||||
MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &exc);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
ERR_FAIL_V(String());
|
||||
}
|
||||
|
||||
|
@ -68,11 +68,11 @@ String generate_editor_api_project(const String &p_dir, const String &p_core_dll
|
|||
Variant core_dll_path = p_core_dll_path;
|
||||
Variant compile_items = p_files;
|
||||
const Variant *args[3] = { &dir, &core_dll_path, &compile_items };
|
||||
MonoObject *ex = NULL;
|
||||
MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &ex);
|
||||
MonoException *exc = NULL;
|
||||
MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
ERR_FAIL_V(String());
|
||||
}
|
||||
|
||||
|
@ -89,11 +89,11 @@ String generate_game_project(const String &p_dir, const String &p_name, const Ve
|
|||
Variant name = p_name;
|
||||
Variant compile_items = p_files;
|
||||
const Variant *args[3] = { &dir, &name, &compile_items };
|
||||
MonoObject *ex = NULL;
|
||||
MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &ex);
|
||||
MonoException *exc = NULL;
|
||||
MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &exc);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
ERR_FAIL_V(String());
|
||||
}
|
||||
|
||||
|
@ -110,11 +110,11 @@ void add_item(const String &p_project_path, const String &p_item_type, const Str
|
|||
Variant item_type = p_item_type;
|
||||
Variant include = p_include;
|
||||
const Variant *args[3] = { &project_path, &item_type, &include };
|
||||
MonoObject *ex = NULL;
|
||||
klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &ex);
|
||||
MonoException *exc = NULL;
|
||||
klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &exc);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
ERR_FAIL();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -513,14 +513,14 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
|
|||
|
||||
const Variant *ctor_args[2] = { &solution, &config };
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
MonoException *exc = NULL;
|
||||
GDMonoMethod *ctor = klass->get_method(".ctor", 2);
|
||||
ctor->invoke(mono_object, ctor_args, &ex);
|
||||
ctor->invoke(mono_object, ctor_args, &exc);
|
||||
|
||||
if (ex) {
|
||||
if (exc) {
|
||||
exited = true;
|
||||
GDMonoUtils::print_unhandled_exception(ex);
|
||||
String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(exc);
|
||||
build_tab->on_build_exec_failed(message);
|
||||
ERR_EXPLAIN(message);
|
||||
ERR_FAIL();
|
||||
|
@ -535,14 +535,14 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
|
|||
|
||||
const Variant *args[3] = { &logger_assembly, &logger_output_dir, &custom_props };
|
||||
|
||||
ex = NULL;
|
||||
exc = NULL;
|
||||
GDMonoMethod *build_method = klass->get_method(p_blocking ? "Build" : "BuildAsync", 3);
|
||||
build_method->invoke(mono_object, args, &ex);
|
||||
build_method->invoke(mono_object, args, &exc);
|
||||
|
||||
if (ex) {
|
||||
if (exc) {
|
||||
exited = true;
|
||||
GDMonoUtils::print_unhandled_exception(ex);
|
||||
String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(exc);
|
||||
build_tab->on_build_exec_failed(message);
|
||||
ERR_EXPLAIN(message);
|
||||
ERR_FAIL();
|
||||
|
|
|
@ -40,14 +40,14 @@ void MonoDevelopInstance::execute(const Vector<String> &p_files) {
|
|||
ERR_FAIL_NULL(execute_method);
|
||||
ERR_FAIL_COND(gc_handle.is_null());
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
MonoException *exc = NULL;
|
||||
|
||||
Variant files = p_files;
|
||||
const Variant *args[1] = { &files };
|
||||
execute_method->invoke(gc_handle->get_target(), args, &ex);
|
||||
execute_method->invoke(gc_handle->get_target(), args, &exc);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
ERR_FAIL();
|
||||
}
|
||||
}
|
||||
|
@ -68,14 +68,14 @@ MonoDevelopInstance::MonoDevelopInstance(const String &p_solution) {
|
|||
MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_mono_ptr());
|
||||
|
||||
GDMonoMethod *ctor = klass->get_method(".ctor", 1);
|
||||
MonoObject *ex = NULL;
|
||||
MonoException *exc = NULL;
|
||||
|
||||
Variant solution = p_solution;
|
||||
const Variant *args[1] = { &solution };
|
||||
ctor->invoke(obj, args, &ex);
|
||||
ctor->invoke(obj, args, &exc);
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,15 +34,12 @@
|
|||
|
||||
uint32_t MonoGCHandle::make_strong_handle(MonoObject *p_object) {
|
||||
|
||||
return mono_gchandle_new(
|
||||
p_object,
|
||||
false /* do not pin the object */
|
||||
);
|
||||
return mono_gchandle_new(p_object, /* pinned: */ false);
|
||||
}
|
||||
|
||||
uint32_t MonoGCHandle::make_weak_handle(MonoObject *p_object) {
|
||||
|
||||
return mono_gchandle_new_weakref(p_object, false);
|
||||
return mono_gchandle_new_weakref(p_object, /* track_resurrection: */ false);
|
||||
}
|
||||
|
||||
Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) {
|
||||
|
|
|
@ -53,14 +53,6 @@
|
|||
#include "main/main.h"
|
||||
#endif
|
||||
|
||||
void gdmono_unhandled_exception_hook(MonoObject *exc, void *user_data) {
|
||||
|
||||
(void)user_data; // UNUSED
|
||||
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef MONO_PRINT_HANDLER_ENABLED
|
||||
void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) {
|
||||
|
||||
|
@ -197,6 +189,8 @@ void GDMono::initialize() {
|
|||
|
||||
mono_config_parse(NULL);
|
||||
|
||||
mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
|
||||
|
||||
root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
|
||||
|
||||
ERR_EXPLAIN("Mono: Failed to initialize runtime");
|
||||
|
@ -279,8 +273,6 @@ void GDMono::initialize() {
|
|||
OS::get_singleton()->print("Mono: Glue disabled, ignoring script assemblies\n");
|
||||
#endif
|
||||
|
||||
mono_install_unhandled_exception_hook(gdmono_unhandled_exception_hook, NULL);
|
||||
|
||||
OS::get_singleton()->print("Mono: INITIALIZED\n");
|
||||
}
|
||||
|
||||
|
@ -652,12 +644,12 @@ Error GDMono::_unload_scripts_domain() {
|
|||
|
||||
_GodotSharp::get_singleton()->_dispose_callback();
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
mono_domain_try_unload(domain, &ex);
|
||||
MonoException *exc = NULL;
|
||||
mono_domain_try_unload(domain, (MonoObject **)&exc);
|
||||
|
||||
if (ex) {
|
||||
ERR_PRINT("Exception thrown when unloading scripts domain:");
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
ERR_PRINT("Exception thrown when unloading scripts domain");
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
@ -763,12 +755,12 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
|
|||
|
||||
_domain_assemblies_cleanup(mono_domain_get_id(p_domain));
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
mono_domain_try_unload(p_domain, &ex);
|
||||
MonoException *exc = NULL;
|
||||
mono_domain_try_unload(p_domain, (MonoObject **)&exc);
|
||||
|
||||
if (ex) {
|
||||
ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`:");
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`");
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
@ -811,6 +803,21 @@ void GDMono::_domain_assemblies_cleanup(uint32_t p_domain_id) {
|
|||
assemblies.erase(p_domain_id);
|
||||
}
|
||||
|
||||
void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) {
|
||||
|
||||
// This method will be called by the runtime when a thrown exception is not handled.
|
||||
// It won't be called when we manually treat a thrown exception as unhandled.
|
||||
// We assume the exception was already printed before calling this hook.
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
GDMonoUtils::debug_send_unhandled_exception_error((MonoException *)p_exc);
|
||||
if (ScriptDebugger::get_singleton())
|
||||
ScriptDebugger::get_singleton()->idle_poll();
|
||||
#endif
|
||||
abort();
|
||||
_UNREACHABLE_();
|
||||
}
|
||||
|
||||
GDMono::GDMono() {
|
||||
|
||||
singleton = this;
|
||||
|
|
|
@ -164,6 +164,8 @@ public:
|
|||
|
||||
static GDMono *get_singleton() { return singleton; }
|
||||
|
||||
static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data);
|
||||
|
||||
// Do not use these, unless you know what you're doing
|
||||
void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
|
||||
GDMonoAssembly **get_loaded_assembly(const String &p_name);
|
||||
|
|
|
@ -32,8 +32,12 @@
|
|||
|
||||
#include "../csharp_script.h"
|
||||
#include "../mono_gc_handle.h"
|
||||
#include "../utils/macros.h"
|
||||
#include "../utils/thread_local.h"
|
||||
#include "gd_mono_utils.h"
|
||||
|
||||
#include <mono/metadata/exception.h>
|
||||
|
||||
namespace GDMonoInternals {
|
||||
|
||||
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
||||
|
@ -64,4 +68,11 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
void unhandled_exception(MonoException *p_exc) {
|
||||
mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well
|
||||
abort();
|
||||
_UNREACHABLE_();
|
||||
}
|
||||
|
||||
} // namespace GDMonoInternals
|
||||
|
|
|
@ -33,11 +33,20 @@
|
|||
|
||||
#include <mono/jit/jit.h>
|
||||
|
||||
#include "../utils/macros.h"
|
||||
|
||||
#include "core/object.h"
|
||||
|
||||
namespace GDMonoInternals {
|
||||
|
||||
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not call this function directly.
|
||||
* Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
|
||||
*/
|
||||
_NO_RETURN_ void unhandled_exception(MonoException *p_exc);
|
||||
|
||||
} // namespace GDMonoInternals
|
||||
|
||||
#endif // GD_MONO_INTERNALS_H
|
||||
|
|
|
@ -837,11 +837,13 @@ MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict) {
|
|||
|
||||
GDMonoUtils::MarshalUtils_ArraysToDict arrays_to_dict = CACHED_METHOD_THUNK(MarshalUtils, ArraysToDictionary);
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
MonoObject *ret = arrays_to_dict(keys, values, &ex);
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
MonoObject *ret = arrays_to_dict(keys, values, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
|
@ -858,11 +860,13 @@ Dictionary mono_object_to_Dictionary(MonoObject *p_dict) {
|
|||
|
||||
MonoArray *keys = NULL;
|
||||
MonoArray *values = NULL;
|
||||
MonoObject *ex = NULL;
|
||||
dict_to_arrays(p_dict, &keys, &values, &ex);
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
dict_to_arrays(p_dict, &keys, &values, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
ERR_FAIL_V(Dictionary());
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ void *GDMonoMethod::get_thunk() {
|
|||
return mono_method_get_unmanaged_thunk(mono_method);
|
||||
}
|
||||
|
||||
MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoObject **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) {
|
||||
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
|
||||
|
||||
|
@ -104,28 +104,32 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
|
|||
mono_array_set(params, MonoObject *, i, boxed_param);
|
||||
}
|
||||
|
||||
MonoObject *exc = NULL;
|
||||
MonoObject *ret = mono_runtime_invoke_array(mono_method, p_object, params, &exc);
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
MonoObject *ret = mono_runtime_invoke_array(mono_method, p_object, params, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (exc) {
|
||||
ret = NULL;
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
MonoObject *exc = NULL;
|
||||
mono_runtime_invoke(mono_method, p_object, NULL, &exc);
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
mono_runtime_invoke(mono_method, p_object, NULL, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (exc) {
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,21 +137,23 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
|
|||
}
|
||||
}
|
||||
|
||||
MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoObject **r_exc) {
|
||||
MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) {
|
||||
ERR_FAIL_COND_V(get_parameters_count() > 0, NULL);
|
||||
return invoke_raw(p_object, NULL, r_exc);
|
||||
}
|
||||
|
||||
MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoObject **r_exc) {
|
||||
MonoObject *exc = NULL;
|
||||
MonoObject *ret = mono_runtime_invoke(mono_method, p_object, p_params, &exc);
|
||||
MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) {
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
MonoObject *ret = mono_runtime_invoke(mono_method, p_object, p_params, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (exc) {
|
||||
ret = NULL;
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,9 +71,9 @@ public:
|
|||
|
||||
void *get_thunk();
|
||||
|
||||
MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoObject **r_exc = NULL);
|
||||
MonoObject *invoke(MonoObject *p_object, MonoObject **r_exc = NULL);
|
||||
MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoObject **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_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL);
|
||||
|
||||
String get_full_name(bool p_signature = false) const;
|
||||
String get_full_name_no_class() const;
|
||||
|
|
|
@ -138,47 +138,53 @@ bool GDMonoProperty::has_setter() {
|
|||
return mono_property_get_set_method(mono_property) != NULL;
|
||||
}
|
||||
|
||||
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoObject **r_exc) {
|
||||
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
|
||||
MonoMethod *prop_method = mono_property_get_set_method(mono_property);
|
||||
|
||||
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
|
||||
mono_array_set(params, MonoObject *, 0, p_value);
|
||||
|
||||
MonoObject *exc = NULL;
|
||||
mono_runtime_invoke_array(prop_method, p_object, params, &exc);
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
mono_runtime_invoke_array(prop_method, p_object, params, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (exc) {
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoObject **r_exc) {
|
||||
MonoObject *exc = NULL;
|
||||
mono_property_set_value(mono_property, p_object, p_params, &exc);
|
||||
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
mono_property_set_value(mono_property, p_object, p_params, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (exc) {
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoObject **r_exc) {
|
||||
MonoObject *exc = NULL;
|
||||
MonoObject *ret = mono_property_get_value(mono_property, p_object, NULL, &exc);
|
||||
MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoException **r_exc) {
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
MonoObject *ret = mono_property_get_value(mono_property, p_object, NULL, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (exc) {
|
||||
ret = NULL;
|
||||
if (r_exc) {
|
||||
*r_exc = exc;
|
||||
} else {
|
||||
GDMonoUtils::print_unhandled_exception(exc);
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,9 +62,9 @@ public:
|
|||
|
||||
_FORCE_INLINE_ ManagedType get_type() const { return type; }
|
||||
|
||||
void set_value(MonoObject *p_object, MonoObject *p_value, MonoObject **r_exc = NULL);
|
||||
void set_value(MonoObject *p_object, void **p_params, MonoObject **r_exc = NULL);
|
||||
MonoObject *get_value(MonoObject *p_object, MonoObject **r_exc = NULL);
|
||||
void set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc = NULL);
|
||||
void set_value(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL);
|
||||
MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = NULL);
|
||||
|
||||
bool get_bool_value(MonoObject *p_object);
|
||||
int get_int_value(MonoObject *p_object);
|
||||
|
|
|
@ -30,12 +30,15 @@
|
|||
|
||||
#include "gd_mono_utils.h"
|
||||
|
||||
#include <mono/metadata/exception.h>
|
||||
|
||||
#include "os/dir_access.h"
|
||||
#include "os/os.h"
|
||||
#include "project_settings.h"
|
||||
#include "reference.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "../utils/macros.h"
|
||||
#include "gd_mono.h"
|
||||
#include "gd_mono_class.h"
|
||||
#include "gd_mono_marshal.h"
|
||||
|
@ -391,10 +394,10 @@ MonoDomain *create_domain(const String &p_friendly_name) {
|
|||
return domain;
|
||||
}
|
||||
|
||||
String get_exception_name_and_message(MonoObject *p_ex) {
|
||||
String get_exception_name_and_message(MonoException *p_ex) {
|
||||
String res;
|
||||
|
||||
MonoClass *klass = mono_object_get_class(p_ex);
|
||||
MonoClass *klass = mono_object_get_class((MonoObject *)p_ex);
|
||||
MonoType *type = mono_class_get_type(klass);
|
||||
|
||||
char *full_name = mono_type_full_name(type);
|
||||
|
@ -404,29 +407,31 @@ String get_exception_name_and_message(MonoObject *p_ex) {
|
|||
res += ": ";
|
||||
|
||||
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
|
||||
MonoString *msg = (MonoString *)mono_property_get_value(prop, p_ex, NULL, NULL);
|
||||
MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_ex, NULL, NULL);
|
||||
res += GDMonoMarshal::mono_string_to_godot(msg);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void print_unhandled_exception(MonoObject *p_exc) {
|
||||
print_unhandled_exception(p_exc, false);
|
||||
void debug_print_unhandled_exception(MonoException *p_exc) {
|
||||
print_unhandled_exception(p_exc);
|
||||
debug_send_unhandled_exception_error(p_exc);
|
||||
}
|
||||
|
||||
void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) {
|
||||
mono_print_unhandled_exception(p_exc);
|
||||
void debug_send_unhandled_exception_error(MonoException *p_exc) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (!ScriptDebugger::get_singleton())
|
||||
return;
|
||||
|
||||
_TLS_RECURSION_GUARD_;
|
||||
|
||||
ScriptLanguage::StackInfo separator;
|
||||
separator.file = "";
|
||||
separator.file = String();
|
||||
separator.func = "--- " + RTR("End of inner exception stack trace") + " ---";
|
||||
separator.line = 0;
|
||||
|
||||
Vector<ScriptLanguage::StackInfo> si;
|
||||
String exc_msg = "";
|
||||
String exc_msg;
|
||||
|
||||
while (p_exc != NULL) {
|
||||
GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace);
|
||||
|
@ -435,24 +440,16 @@ void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) {
|
|||
MonoBoolean need_file_info = true;
|
||||
void *ctor_args[2] = { p_exc, &need_file_info };
|
||||
|
||||
MonoObject *unexpected_exc = NULL;
|
||||
MonoException *unexpected_exc = NULL;
|
||||
CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc);
|
||||
|
||||
if (unexpected_exc != NULL) {
|
||||
mono_print_unhandled_exception(unexpected_exc);
|
||||
|
||||
if (p_recursion_caution) {
|
||||
// Called from CSharpLanguage::get_current_stack_info,
|
||||
// so printing an error here could result in endless recursion
|
||||
OS::get_singleton()->printerr("Mono: Method GDMonoUtils::print_unhandled_exception failed");
|
||||
return;
|
||||
} else {
|
||||
ERR_FAIL();
|
||||
}
|
||||
if (unexpected_exc) {
|
||||
GDMonoInternals::unhandled_exception(unexpected_exc);
|
||||
_UNREACHABLE_();
|
||||
}
|
||||
|
||||
Vector<ScriptLanguage::StackInfo> _si;
|
||||
if (stack_trace != NULL && !p_recursion_caution) {
|
||||
if (stack_trace != NULL) {
|
||||
_si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace);
|
||||
for (int i = _si.size() - 1; i >= 0; i--)
|
||||
si.insert(0, _si[i]);
|
||||
|
@ -460,10 +457,15 @@ void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) {
|
|||
|
||||
exc_msg += (exc_msg.length() > 0 ? " ---> " : "") + GDMonoUtils::get_exception_name_and_message(p_exc);
|
||||
|
||||
GDMonoProperty *p_prop = GDMono::get_singleton()->get_class(mono_object_get_class(p_exc))->get_property("InnerException");
|
||||
p_exc = p_prop != NULL ? p_prop->get_value(p_exc) : NULL;
|
||||
if (p_exc != NULL)
|
||||
GDMonoClass *exc_class = GDMono::get_singleton()->get_class(mono_get_exception_class());
|
||||
GDMonoProperty *inner_exc_prop = exc_class->get_property("InnerException");
|
||||
CRASH_COND(inner_exc_prop == NULL);
|
||||
|
||||
MonoObject *inner_exc = inner_exc_prop->get_value((MonoObject *)p_exc);
|
||||
if (inner_exc != NULL)
|
||||
si.insert(0, separator);
|
||||
|
||||
p_exc = (MonoException *)inner_exc;
|
||||
}
|
||||
|
||||
String file = si.size() ? si[0].file : __FILE__;
|
||||
|
@ -475,4 +477,38 @@ void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void debug_unhandled_exception(MonoException *p_exc) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
GDMonoUtils::debug_send_unhandled_exception_error(p_exc);
|
||||
if (ScriptDebugger::get_singleton())
|
||||
ScriptDebugger::get_singleton()->idle_poll();
|
||||
#endif
|
||||
GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well
|
||||
_UNREACHABLE_();
|
||||
}
|
||||
|
||||
void print_unhandled_exception(MonoException *p_exc) {
|
||||
mono_print_unhandled_exception((MonoObject *)p_exc);
|
||||
}
|
||||
|
||||
void set_pending_exception(MonoException *p_exc) {
|
||||
#ifdef HAS_PENDING_EXCEPTIONS
|
||||
if (get_runtime_invoke_count() == 0) {
|
||||
debug_unhandled_exception(p_exc);
|
||||
_UNREACHABLE_();
|
||||
}
|
||||
|
||||
if (!mono_runtime_set_pending_exception(p_exc, false)) {
|
||||
ERR_PRINTS("Exception thrown from managed code, but it could not be set as pending:");
|
||||
GDMonoUtils::debug_print_unhandled_exception(p_exc);
|
||||
}
|
||||
#else
|
||||
debug_unhandled_exception(p_exc);
|
||||
_UNREACHABLE_();
|
||||
#endif
|
||||
}
|
||||
|
||||
_THREAD_LOCAL_(int)
|
||||
current_invoke_count = 0;
|
||||
|
||||
} // namespace GDMonoUtils
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <mono/metadata/threads.h>
|
||||
|
||||
#include "../mono_gc_handle.h"
|
||||
#include "../utils/macros.h"
|
||||
#include "../utils/thread_local.h"
|
||||
#include "gd_mono_header.h"
|
||||
|
||||
#include "object.h"
|
||||
|
@ -181,10 +183,28 @@ MonoObject *create_managed_from(const RID &p_from);
|
|||
|
||||
MonoDomain *create_domain(const String &p_friendly_name);
|
||||
|
||||
String get_exception_name_and_message(MonoObject *p_ex);
|
||||
String get_exception_name_and_message(MonoException *p_ex);
|
||||
|
||||
void print_unhandled_exception(MonoObject *p_exc);
|
||||
void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution);
|
||||
void debug_print_unhandled_exception(MonoException *p_exc);
|
||||
void debug_send_unhandled_exception_error(MonoException *p_exc);
|
||||
_NO_RETURN_ void debug_unhandled_exception(MonoException *p_exc);
|
||||
void print_unhandled_exception(MonoException *p_exc);
|
||||
|
||||
/**
|
||||
* Sets the exception as pending. The exception will be thrown when returning to managed code.
|
||||
* If no managed method is being invoked by the runtime, the exception will be treated as
|
||||
* an unhandled exception and the method will not return.
|
||||
*/
|
||||
void set_pending_exception(MonoException *p_exc);
|
||||
|
||||
extern _THREAD_LOCAL_(int) current_invoke_count;
|
||||
|
||||
_FORCE_INLINE_ int get_runtime_invoke_count() {
|
||||
return current_invoke_count;
|
||||
}
|
||||
_FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
|
||||
return current_invoke_count;
|
||||
}
|
||||
|
||||
} // namespace GDMonoUtils
|
||||
|
||||
|
@ -203,4 +223,11 @@ void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution);
|
|||
#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float)
|
||||
#endif
|
||||
|
||||
#define GD_MONO_BEGIN_RUNTIME_INVOKE \
|
||||
int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \
|
||||
_runtime_invoke_count_ref += 1;
|
||||
|
||||
#define GD_MONO_END_RUNTIME_INVOKE \
|
||||
_runtime_invoke_count_ref -= 1;
|
||||
|
||||
#endif // GD_MONOUTILS_H
|
||||
|
|
|
@ -101,11 +101,13 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc
|
|||
|
||||
GDMonoUtils::SignalAwaiter_SignalCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback);
|
||||
|
||||
MonoObject *ex = NULL;
|
||||
thunk(get_target(), signal_args, &ex);
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
thunk(get_target(), signal_args, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
ERR_FAIL_V(Variant());
|
||||
}
|
||||
|
||||
|
@ -133,11 +135,13 @@ SignalAwaiterHandle::~SignalAwaiterHandle() {
|
|||
MonoObject *awaiter = get_target();
|
||||
|
||||
if (awaiter) {
|
||||
MonoObject *ex = NULL;
|
||||
thunk(awaiter, &ex);
|
||||
MonoException *exc = NULL;
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
thunk(awaiter, (MonoObject **)&exc);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
|
||||
if (ex) {
|
||||
mono_print_unhandled_exception(ex);
|
||||
if (exc) {
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
ERR_FAIL_V();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
from __future__ import print_function
|
||||
|
||||
def supported(result):
|
||||
return 'supported' if result else 'not supported'
|
||||
|
||||
|
||||
def check_cxx11_thread_local(conf):
|
||||
print('Checking for `thread_local` support...', end=" ")
|
||||
result = conf.TryCompile('thread_local int foo = 0; int main() { return foo; }', '.cpp')
|
||||
print(supported(result))
|
||||
return bool(result)
|
||||
|
||||
|
||||
def check_declspec_thread(conf):
|
||||
print('Checking for `__declspec(thread)` support...', end=" ")
|
||||
result = conf.TryCompile('__declspec(thread) int foo = 0; int main() { return foo; }', '.cpp')
|
||||
print(supported(result))
|
||||
return bool(result)
|
||||
|
||||
|
||||
def check_gcc___thread(conf):
|
||||
print('Checking for `__thread` support...', end=" ")
|
||||
result = conf.TryCompile('__thread int foo = 0; int main() { return foo; }', '.cpp')
|
||||
print(supported(result))
|
||||
return bool(result)
|
||||
|
||||
|
||||
def configure(conf):
|
||||
if check_cxx11_thread_local(conf):
|
||||
conf.env.Append(CPPDEFINES=['HAVE_CXX11_THREAD_LOCAL'])
|
||||
else:
|
||||
if conf.env.msvc:
|
||||
if check_declspec_thread(conf):
|
||||
conf.env.Append(CPPDEFINES=['HAVE_DECLSPEC_THREAD'])
|
||||
elif check_gcc___thread(conf):
|
||||
conf.env.Append(CPPDEFINES=['HAVE_GCC___THREAD'])
|
|
@ -0,0 +1,59 @@
|
|||
/*************************************************************************/
|
||||
/* util_macros.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef UTIL_MACROS_H
|
||||
#define UTIL_MACROS_H
|
||||
|
||||
// noreturn
|
||||
|
||||
#undef _NO_RETURN_
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define _NO_RETURN_ __attribute__((noreturn))
|
||||
#elif _MSC_VER
|
||||
#define _NO_RETURN_ __declspec(noreturn)
|
||||
#else
|
||||
#error Platform or compiler not supported
|
||||
#endif
|
||||
|
||||
// unreachable
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define _UNREACHABLE_() __assume(0)
|
||||
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
|
||||
#define _UNREACHABLE_() __builtin_unreachable()
|
||||
#else
|
||||
#define _UNREACHABLE_() \
|
||||
CRASH_NOW(); \
|
||||
do { \
|
||||
} while (true);
|
||||
#endif
|
||||
|
||||
#endif // UTIL_MACROS_H
|
|
@ -0,0 +1,99 @@
|
|||
/*************************************************************************/
|
||||
/* thread_local.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 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 "thread_local.h"
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "core/os/memory.h"
|
||||
#include "core/print_string.h"
|
||||
|
||||
struct ThreadLocalStorage::Impl {
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
DWORD dwFlsIndex;
|
||||
#else
|
||||
pthread_key_t key;
|
||||
#endif
|
||||
|
||||
void *get_value() const {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
return FlsGetValue(dwFlsIndex);
|
||||
#else
|
||||
return pthread_getspecific(key);
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_value(void *p_value) const {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
FlsSetValue(dwFlsIndex, p_value);
|
||||
#else
|
||||
pthread_setspecific(key, p_value);
|
||||
#endif
|
||||
}
|
||||
|
||||
Impl(void (*p_destr_callback_func)(void *)) {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
dwFlsIndex = FlsAlloc(p_destr_callback_func);
|
||||
ERR_FAIL_COND(dwFlsIndex == FLS_OUT_OF_INDEXES);
|
||||
#else
|
||||
pthread_key_create(&key, p_destr_callback_func);
|
||||
#endif
|
||||
}
|
||||
|
||||
~Impl() {
|
||||
#ifdef WINDOWS_ENABLED
|
||||
FlsFree(dwFlsIndex);
|
||||
#else
|
||||
pthread_key_delete(key);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
void *ThreadLocalStorage::get_value() const {
|
||||
return pimpl->get_value();
|
||||
}
|
||||
|
||||
void ThreadLocalStorage::set_value(void *p_value) const {
|
||||
pimpl->set_value(p_value);
|
||||
}
|
||||
|
||||
void ThreadLocalStorage::alloc(void (*p_destr_callback)(void *)) {
|
||||
pimpl = memnew(ThreadLocalStorage::Impl(p_destr_callback));
|
||||
}
|
||||
|
||||
void ThreadLocalStorage::free() {
|
||||
memdelete(pimpl);
|
||||
pimpl = NULL;
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/*************************************************************************/
|
||||
/* thread_local.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef THREAD_LOCAL_H
|
||||
#define THREAD_LOCAL_H
|
||||
|
||||
#ifdef HAVE_CXX11_THREAD_LOCAL
|
||||
#define _THREAD_LOCAL_(m_t) thread_local m_t
|
||||
#else
|
||||
|
||||
#if !defined(__GNUC__) && !defined(_MSC_VER)
|
||||
#error Platform or compiler not supported
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#ifdef HAVE_GCC___THREAD
|
||||
#define _THREAD_LOCAL_(m_t) __thread m_t
|
||||
#else
|
||||
#define USE_CUSTOM_THREAD_LOCAL
|
||||
#endif
|
||||
|
||||
#elif _MSC_VER
|
||||
|
||||
#ifdef HAVE_DECLSPEC_THREAD
|
||||
#define _THREAD_LOCAL_(m_t) __declspec(thread) m_t
|
||||
#else
|
||||
#define USE_CUSTOM_THREAD_LOCAL
|
||||
#endif
|
||||
|
||||
#endif // __GNUC__ _MSC_VER
|
||||
|
||||
#endif // HAVE_CXX11_THREAD_LOCAL
|
||||
|
||||
#ifdef USE_CUSTOM_THREAD_LOCAL
|
||||
#define _THREAD_LOCAL_(m_t) ThreadLocal<m_t>
|
||||
#endif
|
||||
|
||||
#include "core/typedefs.h"
|
||||
|
||||
struct ThreadLocalStorage {
|
||||
|
||||
void *get_value() const;
|
||||
void set_value(void *p_value) const;
|
||||
|
||||
void alloc(void (*p_dest_callback)(void *));
|
||||
void free();
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
Impl *pimpl;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ThreadLocal {
|
||||
|
||||
ThreadLocalStorage storage;
|
||||
|
||||
T init_val;
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
#define _CALLBACK_FUNC_ __stdcall
|
||||
#else
|
||||
#define _CALLBACK_FUNC_
|
||||
#endif
|
||||
|
||||
static void _CALLBACK_FUNC_ destr_callback(void *tls_data) {
|
||||
memdelete(static_cast<T *>(tls_data));
|
||||
}
|
||||
|
||||
#undef _CALLBACK_FUNC_
|
||||
|
||||
T *_tls_get_value() const {
|
||||
void *tls_data = storage.get_value();
|
||||
|
||||
if (tls_data)
|
||||
return static_cast<T *>(tls_data);
|
||||
|
||||
T *data = memnew(T(init_val));
|
||||
|
||||
storage.set_value(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public:
|
||||
ThreadLocal() :
|
||||
ThreadLocal(T()) {}
|
||||
|
||||
ThreadLocal(const T &p_init_val) :
|
||||
init_val(p_init_val) {
|
||||
storage.alloc(&destr_callback);
|
||||
}
|
||||
|
||||
ThreadLocal(const ThreadLocal &other) :
|
||||
ThreadLocal(*other._tls_get_value()) {}
|
||||
|
||||
~ThreadLocal() {
|
||||
storage.free();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *operator&() const {
|
||||
return _tls_get_value();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ operator T &() const {
|
||||
return *_tls_get_value();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ ThreadLocal &operator=(const T &val) {
|
||||
T *ptr = _tls_get_value();
|
||||
*ptr = val;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct FlagScopeGuard {
|
||||
|
||||
FlagScopeGuard(bool &p_flag) :
|
||||
flag(p_flag) {
|
||||
flag = !flag;
|
||||
}
|
||||
|
||||
~FlagScopeGuard() {
|
||||
flag = !flag;
|
||||
}
|
||||
|
||||
private:
|
||||
bool &flag;
|
||||
};
|
||||
|
||||
#define _TLS_RECURSION_GUARD_V_(m_ret) \
|
||||
static _THREAD_LOCAL_(bool) _recursion_flag_ = false; \
|
||||
if (_recursion_flag_) \
|
||||
return m_ret; \
|
||||
FlagScopeGuard _recursion_guard_(_recursion_flag_);
|
||||
|
||||
#define _TLS_RECURSION_GUARD_ \
|
||||
static _THREAD_LOCAL_(bool) _recursion_flag_ = false; \
|
||||
if (_recursion_flag_) \
|
||||
return; \
|
||||
FlagScopeGuard _recursion_guard_(_recursion_flag_);
|
||||
|
||||
#endif // THREAD_LOCAL_H
|
Loading…
Reference in New Issue