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()
|
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):
|
def make_cs_files_header(src, dst):
|
||||||
|
from compat import byte_to_str
|
||||||
|
|
||||||
with open(dst, 'w') as header:
|
with open(dst, 'w') as header:
|
||||||
header.write('/* This is an automatically generated file; DO NOT EDIT! OK THX */\n')
|
header.write('/* This is an automatically generated file; DO NOT EDIT! OK THX */\n')
|
||||||
header.write('#ifndef _CS_FILES_DATA_H\n')
|
header.write('#ifndef _CS_FILES_DATA_H\n')
|
||||||
|
@ -75,6 +77,13 @@ else:
|
||||||
if ARGUMENTS.get('yolo_copy', False):
|
if ARGUMENTS.get('yolo_copy', False):
|
||||||
env_mono.Append(CPPDEFINES=['YOLO_COPY'])
|
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
|
# Build GodotSharpTools solution
|
||||||
|
|
||||||
|
@ -127,6 +136,21 @@ def find_msbuild_windows():
|
||||||
if not mono_root:
|
if not mono_root:
|
||||||
raise RuntimeError('Cannot find mono root directory')
|
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()
|
msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
|
||||||
|
|
||||||
if msbuild_tools_path:
|
if msbuild_tools_path:
|
||||||
|
|
|
@ -5,6 +5,8 @@ import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from SCons.Script import BoolVariable, Dir, Environment, PathVariable, Variables
|
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')
|
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):
|
def can_build(platform):
|
||||||
if platform in ["javascript"]:
|
if platform in ['javascript']:
|
||||||
return False # Not yet supported
|
return False # Not yet supported
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -30,6 +32,27 @@ def is_enabled():
|
||||||
return False
|
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):
|
def copy_file(src_dir, dst_dir, name):
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
|
||||||
|
@ -44,7 +67,7 @@ def copy_file(src_dir, dst_dir, name):
|
||||||
|
|
||||||
def configure(env):
|
def configure(env):
|
||||||
env.use_ptrcall = True
|
env.use_ptrcall = True
|
||||||
env.add_module_version_string("mono")
|
env.add_module_version_string('mono')
|
||||||
|
|
||||||
envvars = Variables()
|
envvars = Variables()
|
||||||
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
|
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
|
||||||
|
@ -73,6 +96,9 @@ def configure(env):
|
||||||
if not mono_root:
|
if not mono_root:
|
||||||
raise RuntimeError('Mono installation directory not found')
|
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')
|
mono_lib_path = os.path.join(mono_root, 'lib')
|
||||||
|
|
||||||
env.Append(LIBPATH=mono_lib_path)
|
env.Append(LIBPATH=mono_lib_path)
|
||||||
|
@ -135,7 +161,17 @@ def configure(env):
|
||||||
if os.getenv('MONO64_PREFIX'):
|
if os.getenv('MONO64_PREFIX'):
|
||||||
mono_root = 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:
|
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')
|
mono_lib_path = os.path.join(mono_root, 'lib')
|
||||||
|
|
||||||
env.Append(LIBPATH=mono_lib_path)
|
env.Append(LIBPATH=mono_lib_path)
|
||||||
|
@ -151,18 +187,18 @@ def configure(env):
|
||||||
if mono_static:
|
if mono_static:
|
||||||
mono_lib_file = os.path.join(mono_lib_path, 'lib' + mono_lib + '.a')
|
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])
|
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'])
|
env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('mono-static: Not supported on this platform')
|
raise RuntimeError('mono-static: Not supported on this platform')
|
||||||
else:
|
else:
|
||||||
env.Append(LIBS=[mono_lib])
|
env.Append(LIBS=[mono_lib])
|
||||||
|
|
||||||
if sys.platform == "darwin":
|
if sys.platform == 'darwin':
|
||||||
env.Append(LIBS=['iconv', 'pthread'])
|
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'])
|
env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
|
||||||
|
|
||||||
if not mono_static:
|
if not mono_static:
|
||||||
|
@ -178,11 +214,14 @@ def configure(env):
|
||||||
if mono_static:
|
if mono_static:
|
||||||
raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually')
|
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')
|
env.ParseConfig('pkg-config monosgen-2 --cflags --libs')
|
||||||
|
|
||||||
mono_lib_path = ''
|
mono_lib_path = ''
|
||||||
mono_so_name = ''
|
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 = Environment()
|
||||||
tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
|
tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
|
||||||
|
@ -204,13 +243,41 @@ def configure(env):
|
||||||
env.Append(LINKFLAGS='-rdynamic')
|
env.Append(LINKFLAGS='-rdynamic')
|
||||||
|
|
||||||
|
|
||||||
def get_doc_classes():
|
def configure_for_mono_version(env, mono_version):
|
||||||
return [
|
if mono_version is None:
|
||||||
"@C#",
|
raise RuntimeError('Mono JIT compiler version not found')
|
||||||
"CSharpScript",
|
print('Mono JIT compiler version: ' + str(mono_version))
|
||||||
"GodotSharp",
|
if mono_version >= LooseVersion("5.12.0"):
|
||||||
]
|
env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS'])
|
||||||
|
|
||||||
|
|
||||||
def get_doc_path():
|
def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
|
||||||
return "doc_classes"
|
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_class.h"
|
||||||
#include "mono_gd/gd_mono_marshal.h"
|
#include "mono_gd/gd_mono_marshal.h"
|
||||||
#include "signal_awaiter_utils.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)
|
#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() {
|
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#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)
|
if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated)
|
||||||
return Vector<StackInfo>();
|
return Vector<StackInfo>();
|
||||||
|
@ -500,15 +502,15 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
|
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);
|
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) {
|
if (exc) {
|
||||||
GDMonoUtils::print_unhandled_exception(exc, true /* fail silently to avoid endless recursion */);
|
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||||
return Vector<StackInfo>();
|
return Vector<StackInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,10 +531,10 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
|
||||||
MonoString *file_name;
|
MonoString *file_name;
|
||||||
int file_line_num;
|
int file_line_num;
|
||||||
MonoString *method_decl;
|
MonoString *method_decl;
|
||||||
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) {
|
if (exc) {
|
||||||
GDMonoUtils::print_unhandled_exception(exc, true /* fail silently to avoid endless recursion */);
|
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||||
return Vector<StackInfo>();
|
return Vector<StackInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,12 +563,12 @@ void CSharpLanguage::frame() {
|
||||||
|
|
||||||
ERR_FAIL_NULL(thunk);
|
ERR_FAIL_NULL(thunk);
|
||||||
|
|
||||||
MonoObject *ex;
|
MonoException *exc = NULL;
|
||||||
thunk(task_scheduler, &ex);
|
thunk(task_scheduler, (MonoObject **)&exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
ERR_FAIL();
|
_UNREACHABLE_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1077,11 +1079,11 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
|
||||||
GDMonoProperty *property = top->get_property(p_name);
|
GDMonoProperty *property = top->get_property(p_name);
|
||||||
|
|
||||||
if (property) {
|
if (property) {
|
||||||
MonoObject *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *value = property->get_value(mono_object, &exc);
|
MonoObject *value = property->get_value(mono_object, &exc);
|
||||||
if (exc) {
|
if (exc) {
|
||||||
r_ret = Variant();
|
r_ret = Variant();
|
||||||
GDMonoUtils::print_unhandled_exception(exc);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
} else {
|
} else {
|
||||||
r_ret = GDMonoMarshal::mono_object_to_variant(value);
|
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
|
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);
|
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
ctor->invoke(tmp_object, NULL, &ex);
|
ctor->invoke(tmp_object, NULL, &exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
ERR_PRINT("Exception thrown from constructor of temporary MonoObject:");
|
ERR_PRINT("Exception thrown from constructor of temporary MonoObject:");
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||||
tmp_object = NULL;
|
tmp_object = NULL;
|
||||||
ERR_FAIL_V(false);
|
ERR_FAIL_V(false);
|
||||||
}
|
}
|
||||||
|
@ -1537,11 +1539,11 @@ bool CSharpScript::_update_exports() {
|
||||||
exported_members_cache.push_front(prop_info);
|
exported_members_cache.push_front(prop_info);
|
||||||
|
|
||||||
if (tmp_object) {
|
if (tmp_object) {
|
||||||
MonoObject *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = property->get_value(tmp_object, &exc);
|
MonoObject *ret = property->get_value(tmp_object, &exc);
|
||||||
if (exc) {
|
if (exc) {
|
||||||
exported_members_defval_cache[name] = Variant();
|
exported_members_defval_cache[name] = Variant();
|
||||||
GDMonoUtils::print_unhandled_exception(exc);
|
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||||
} else {
|
} else {
|
||||||
exported_members_defval_cache[name] = GDMonoMarshal::mono_object_to_variant(ret);
|
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
|
// Construct
|
||||||
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
|
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
|
// Tie managed to unmanaged
|
||||||
instance->gchandle = MonoGCHandle::create_strong(mono_object);
|
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 dir = p_dir;
|
||||||
Variant compile_items = p_files;
|
Variant compile_items = p_files;
|
||||||
const Variant *args[2] = { &dir, &compile_items };
|
const Variant *args[2] = { &dir, &compile_items };
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &ex);
|
MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
ERR_FAIL_V(String());
|
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 core_dll_path = p_core_dll_path;
|
||||||
Variant compile_items = p_files;
|
Variant compile_items = p_files;
|
||||||
const Variant *args[3] = { &dir, &core_dll_path, &compile_items };
|
const Variant *args[3] = { &dir, &core_dll_path, &compile_items };
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &ex);
|
MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
ERR_FAIL_V(String());
|
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 name = p_name;
|
||||||
Variant compile_items = p_files;
|
Variant compile_items = p_files;
|
||||||
const Variant *args[3] = { &dir, &name, &compile_items };
|
const Variant *args[3] = { &dir, &name, &compile_items };
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &ex);
|
MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
ERR_FAIL_V(String());
|
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 item_type = p_item_type;
|
||||||
Variant include = p_include;
|
Variant include = p_include;
|
||||||
const Variant *args[3] = { &project_path, &item_type, &include };
|
const Variant *args[3] = { &project_path, &item_type, &include };
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &ex);
|
klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -513,14 +513,14 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
|
||||||
|
|
||||||
const Variant *ctor_args[2] = { &solution, &config };
|
const Variant *ctor_args[2] = { &solution, &config };
|
||||||
|
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
GDMonoMethod *ctor = klass->get_method(".ctor", 2);
|
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;
|
exited = true;
|
||||||
GDMonoUtils::print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
|
String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(exc);
|
||||||
build_tab->on_build_exec_failed(message);
|
build_tab->on_build_exec_failed(message);
|
||||||
ERR_EXPLAIN(message);
|
ERR_EXPLAIN(message);
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
|
@ -535,14 +535,14 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
|
||||||
|
|
||||||
const Variant *args[3] = { &logger_assembly, &logger_output_dir, &custom_props };
|
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);
|
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;
|
exited = true;
|
||||||
GDMonoUtils::print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
|
String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(exc);
|
||||||
build_tab->on_build_exec_failed(message);
|
build_tab->on_build_exec_failed(message);
|
||||||
ERR_EXPLAIN(message);
|
ERR_EXPLAIN(message);
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
|
|
|
@ -40,14 +40,14 @@ void MonoDevelopInstance::execute(const Vector<String> &p_files) {
|
||||||
ERR_FAIL_NULL(execute_method);
|
ERR_FAIL_NULL(execute_method);
|
||||||
ERR_FAIL_COND(gc_handle.is_null());
|
ERR_FAIL_COND(gc_handle.is_null());
|
||||||
|
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
|
|
||||||
Variant files = p_files;
|
Variant files = p_files;
|
||||||
const Variant *args[1] = { &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) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,14 +68,14 @@ MonoDevelopInstance::MonoDevelopInstance(const String &p_solution) {
|
||||||
MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_mono_ptr());
|
MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_mono_ptr());
|
||||||
|
|
||||||
GDMonoMethod *ctor = klass->get_method(".ctor", 1);
|
GDMonoMethod *ctor = klass->get_method(".ctor", 1);
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
|
|
||||||
Variant solution = p_solution;
|
Variant solution = p_solution;
|
||||||
const Variant *args[1] = { &solution };
|
const Variant *args[1] = { &solution };
|
||||||
ctor->invoke(obj, args, &ex);
|
ctor->invoke(obj, args, &exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,15 +34,12 @@
|
||||||
|
|
||||||
uint32_t MonoGCHandle::make_strong_handle(MonoObject *p_object) {
|
uint32_t MonoGCHandle::make_strong_handle(MonoObject *p_object) {
|
||||||
|
|
||||||
return mono_gchandle_new(
|
return mono_gchandle_new(p_object, /* pinned: */ false);
|
||||||
p_object,
|
|
||||||
false /* do not pin the object */
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MonoGCHandle::make_weak_handle(MonoObject *p_object) {
|
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) {
|
Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) {
|
||||||
|
|
|
@ -53,14 +53,6 @@
|
||||||
#include "main/main.h"
|
#include "main/main.h"
|
||||||
#endif
|
#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
|
#ifdef MONO_PRINT_HANDLER_ENABLED
|
||||||
void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) {
|
void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) {
|
||||||
|
|
||||||
|
@ -197,6 +189,8 @@ void GDMono::initialize() {
|
||||||
|
|
||||||
mono_config_parse(NULL);
|
mono_config_parse(NULL);
|
||||||
|
|
||||||
|
mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
|
||||||
|
|
||||||
root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
|
root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
|
||||||
|
|
||||||
ERR_EXPLAIN("Mono: Failed to initialize runtime");
|
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");
|
OS::get_singleton()->print("Mono: Glue disabled, ignoring script assemblies\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mono_install_unhandled_exception_hook(gdmono_unhandled_exception_hook, NULL);
|
|
||||||
|
|
||||||
OS::get_singleton()->print("Mono: INITIALIZED\n");
|
OS::get_singleton()->print("Mono: INITIALIZED\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,12 +644,12 @@ Error GDMono::_unload_scripts_domain() {
|
||||||
|
|
||||||
_GodotSharp::get_singleton()->_dispose_callback();
|
_GodotSharp::get_singleton()->_dispose_callback();
|
||||||
|
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
mono_domain_try_unload(domain, &ex);
|
mono_domain_try_unload(domain, (MonoObject **)&exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
ERR_PRINT("Exception thrown when unloading scripts domain:");
|
ERR_PRINT("Exception thrown when unloading scripts domain");
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,12 +755,12 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
|
||||||
|
|
||||||
_domain_assemblies_cleanup(mono_domain_get_id(p_domain));
|
_domain_assemblies_cleanup(mono_domain_get_id(p_domain));
|
||||||
|
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
mono_domain_try_unload(p_domain, &ex);
|
mono_domain_try_unload(p_domain, (MonoObject **)&exc);
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`:");
|
ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`");
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::debug_unhandled_exception(exc);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,6 +803,21 @@ void GDMono::_domain_assemblies_cleanup(uint32_t p_domain_id) {
|
||||||
assemblies.erase(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() {
|
GDMono::GDMono() {
|
||||||
|
|
||||||
singleton = this;
|
singleton = this;
|
||||||
|
|
|
@ -164,6 +164,8 @@ public:
|
||||||
|
|
||||||
static GDMono *get_singleton() { return singleton; }
|
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
|
// Do not use these, unless you know what you're doing
|
||||||
void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
|
void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
|
||||||
GDMonoAssembly **get_loaded_assembly(const String &p_name);
|
GDMonoAssembly **get_loaded_assembly(const String &p_name);
|
||||||
|
|
|
@ -32,8 +32,12 @@
|
||||||
|
|
||||||
#include "../csharp_script.h"
|
#include "../csharp_script.h"
|
||||||
#include "../mono_gc_handle.h"
|
#include "../mono_gc_handle.h"
|
||||||
|
#include "../utils/macros.h"
|
||||||
|
#include "../utils/thread_local.h"
|
||||||
#include "gd_mono_utils.h"
|
#include "gd_mono_utils.h"
|
||||||
|
|
||||||
|
#include <mono/metadata/exception.h>
|
||||||
|
|
||||||
namespace GDMonoInternals {
|
namespace GDMonoInternals {
|
||||||
|
|
||||||
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
||||||
|
@ -64,4 +68,11 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unhandled_exception(MonoException *p_exc) {
|
||||||
|
mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well
|
||||||
|
abort();
|
||||||
|
_UNREACHABLE_();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace GDMonoInternals
|
} // namespace GDMonoInternals
|
||||||
|
|
|
@ -33,11 +33,20 @@
|
||||||
|
|
||||||
#include <mono/jit/jit.h>
|
#include <mono/jit/jit.h>
|
||||||
|
|
||||||
|
#include "../utils/macros.h"
|
||||||
|
|
||||||
#include "core/object.h"
|
#include "core/object.h"
|
||||||
|
|
||||||
namespace GDMonoInternals {
|
namespace GDMonoInternals {
|
||||||
|
|
||||||
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
|
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
|
#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);
|
GDMonoUtils::MarshalUtils_ArraysToDict arrays_to_dict = CACHED_METHOD_THUNK(MarshalUtils, ArraysToDictionary);
|
||||||
|
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = arrays_to_dict(keys, values, &ex);
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
MonoObject *ret = arrays_to_dict(keys, values, (MonoObject **)&exc);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
ERR_FAIL_V(NULL);
|
ERR_FAIL_V(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,11 +860,13 @@ Dictionary mono_object_to_Dictionary(MonoObject *p_dict) {
|
||||||
|
|
||||||
MonoArray *keys = NULL;
|
MonoArray *keys = NULL;
|
||||||
MonoArray *values = NULL;
|
MonoArray *values = NULL;
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
dict_to_arrays(p_dict, &keys, &values, &ex);
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
dict_to_arrays(p_dict, &keys, &values, (MonoObject **)&exc);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
ERR_FAIL_V(Dictionary());
|
ERR_FAIL_V(Dictionary());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ void *GDMonoMethod::get_thunk() {
|
||||||
return mono_method_get_unmanaged_thunk(mono_method);
|
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) {
|
if (get_return_type().type_encoding != MONO_TYPE_VOID || get_parameters_count() > 0) {
|
||||||
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
|
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
|
||||||
|
|
||||||
|
@ -104,28 +104,32 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
|
||||||
mono_array_set(params, MonoObject *, i, boxed_param);
|
mono_array_set(params, MonoObject *, i, boxed_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoObject *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = mono_runtime_invoke_array(mono_method, p_object, params, &exc);
|
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) {
|
if (exc) {
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
if (r_exc) {
|
if (r_exc) {
|
||||||
*r_exc = exc;
|
*r_exc = exc;
|
||||||
} else {
|
} else {
|
||||||
GDMonoUtils::print_unhandled_exception(exc);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
MonoObject *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
mono_runtime_invoke(mono_method, p_object, NULL, &exc);
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
mono_runtime_invoke(mono_method, p_object, NULL, (MonoObject **)&exc);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
|
||||||
if (exc) {
|
if (exc) {
|
||||||
if (r_exc) {
|
if (r_exc) {
|
||||||
*r_exc = exc;
|
*r_exc = exc;
|
||||||
} else {
|
} 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);
|
ERR_FAIL_COND_V(get_parameters_count() > 0, NULL);
|
||||||
return invoke_raw(p_object, NULL, r_exc);
|
return invoke_raw(p_object, NULL, r_exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoObject **r_exc) {
|
MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) {
|
||||||
MonoObject *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = mono_runtime_invoke(mono_method, p_object, p_params, &exc);
|
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) {
|
if (exc) {
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
if (r_exc) {
|
if (r_exc) {
|
||||||
*r_exc = exc;
|
*r_exc = exc;
|
||||||
} else {
|
} else {
|
||||||
GDMonoUtils::print_unhandled_exception(exc);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,9 @@ public:
|
||||||
|
|
||||||
void *get_thunk();
|
void *get_thunk();
|
||||||
|
|
||||||
MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoObject **r_exc = NULL);
|
MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = NULL);
|
||||||
MonoObject *invoke(MonoObject *p_object, MonoObject **r_exc = NULL);
|
MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = NULL);
|
||||||
MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoObject **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(bool p_signature = false) const;
|
||||||
String get_full_name_no_class() 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;
|
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);
|
MonoMethod *prop_method = mono_property_get_set_method(mono_property);
|
||||||
|
|
||||||
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
|
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
|
||||||
mono_array_set(params, MonoObject *, 0, p_value);
|
mono_array_set(params, MonoObject *, 0, p_value);
|
||||||
|
|
||||||
MonoObject *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
mono_runtime_invoke_array(prop_method, p_object, params, &exc);
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
mono_runtime_invoke_array(prop_method, p_object, params, (MonoObject **)&exc);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
|
||||||
if (exc) {
|
if (exc) {
|
||||||
if (r_exc) {
|
if (r_exc) {
|
||||||
*r_exc = exc;
|
*r_exc = exc;
|
||||||
} else {
|
} else {
|
||||||
GDMonoUtils::print_unhandled_exception(exc);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoObject **r_exc) {
|
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
|
||||||
MonoObject *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
mono_property_set_value(mono_property, p_object, p_params, &exc);
|
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 (exc) {
|
||||||
if (r_exc) {
|
if (r_exc) {
|
||||||
*r_exc = exc;
|
*r_exc = exc;
|
||||||
} else {
|
} else {
|
||||||
GDMonoUtils::print_unhandled_exception(exc);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoObject **r_exc) {
|
MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoException **r_exc) {
|
||||||
MonoObject *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = mono_property_get_value(mono_property, p_object, NULL, &exc);
|
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) {
|
if (exc) {
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
if (r_exc) {
|
if (r_exc) {
|
||||||
*r_exc = exc;
|
*r_exc = exc;
|
||||||
} else {
|
} else {
|
||||||
GDMonoUtils::print_unhandled_exception(exc);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,9 @@ public:
|
||||||
|
|
||||||
_FORCE_INLINE_ ManagedType get_type() const { return type; }
|
_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, MonoObject *p_value, MonoException **r_exc = NULL);
|
||||||
void set_value(MonoObject *p_object, void **p_params, MonoObject **r_exc = NULL);
|
void set_value(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL);
|
||||||
MonoObject *get_value(MonoObject *p_object, MonoObject **r_exc = NULL);
|
MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = NULL);
|
||||||
|
|
||||||
bool get_bool_value(MonoObject *p_object);
|
bool get_bool_value(MonoObject *p_object);
|
||||||
int get_int_value(MonoObject *p_object);
|
int get_int_value(MonoObject *p_object);
|
||||||
|
|
|
@ -30,12 +30,15 @@
|
||||||
|
|
||||||
#include "gd_mono_utils.h"
|
#include "gd_mono_utils.h"
|
||||||
|
|
||||||
|
#include <mono/metadata/exception.h>
|
||||||
|
|
||||||
#include "os/dir_access.h"
|
#include "os/dir_access.h"
|
||||||
#include "os/os.h"
|
#include "os/os.h"
|
||||||
#include "project_settings.h"
|
#include "project_settings.h"
|
||||||
#include "reference.h"
|
#include "reference.h"
|
||||||
|
|
||||||
#include "../csharp_script.h"
|
#include "../csharp_script.h"
|
||||||
|
#include "../utils/macros.h"
|
||||||
#include "gd_mono.h"
|
#include "gd_mono.h"
|
||||||
#include "gd_mono_class.h"
|
#include "gd_mono_class.h"
|
||||||
#include "gd_mono_marshal.h"
|
#include "gd_mono_marshal.h"
|
||||||
|
@ -391,10 +394,10 @@ MonoDomain *create_domain(const String &p_friendly_name) {
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get_exception_name_and_message(MonoObject *p_ex) {
|
String get_exception_name_and_message(MonoException *p_ex) {
|
||||||
String res;
|
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);
|
MonoType *type = mono_class_get_type(klass);
|
||||||
|
|
||||||
char *full_name = mono_type_full_name(type);
|
char *full_name = mono_type_full_name(type);
|
||||||
|
@ -404,29 +407,31 @@ String get_exception_name_and_message(MonoObject *p_ex) {
|
||||||
res += ": ";
|
res += ": ";
|
||||||
|
|
||||||
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
|
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);
|
res += GDMonoMarshal::mono_string_to_godot(msg);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_unhandled_exception(MonoObject *p_exc) {
|
void debug_print_unhandled_exception(MonoException *p_exc) {
|
||||||
print_unhandled_exception(p_exc, false);
|
print_unhandled_exception(p_exc);
|
||||||
|
debug_send_unhandled_exception_error(p_exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) {
|
void debug_send_unhandled_exception_error(MonoException *p_exc) {
|
||||||
mono_print_unhandled_exception(p_exc);
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
if (!ScriptDebugger::get_singleton())
|
if (!ScriptDebugger::get_singleton())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_TLS_RECURSION_GUARD_;
|
||||||
|
|
||||||
ScriptLanguage::StackInfo separator;
|
ScriptLanguage::StackInfo separator;
|
||||||
separator.file = "";
|
separator.file = String();
|
||||||
separator.func = "--- " + RTR("End of inner exception stack trace") + " ---";
|
separator.func = "--- " + RTR("End of inner exception stack trace") + " ---";
|
||||||
separator.line = 0;
|
separator.line = 0;
|
||||||
|
|
||||||
Vector<ScriptLanguage::StackInfo> si;
|
Vector<ScriptLanguage::StackInfo> si;
|
||||||
String exc_msg = "";
|
String exc_msg;
|
||||||
|
|
||||||
while (p_exc != NULL) {
|
while (p_exc != NULL) {
|
||||||
GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace);
|
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;
|
MonoBoolean need_file_info = true;
|
||||||
void *ctor_args[2] = { p_exc, &need_file_info };
|
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);
|
CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc);
|
||||||
|
|
||||||
if (unexpected_exc != NULL) {
|
if (unexpected_exc) {
|
||||||
mono_print_unhandled_exception(unexpected_exc);
|
GDMonoInternals::unhandled_exception(unexpected_exc);
|
||||||
|
_UNREACHABLE_();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<ScriptLanguage::StackInfo> _si;
|
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);
|
_si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace);
|
||||||
for (int i = _si.size() - 1; i >= 0; i--)
|
for (int i = _si.size() - 1; i >= 0; i--)
|
||||||
si.insert(0, _si[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);
|
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");
|
GDMonoClass *exc_class = GDMono::get_singleton()->get_class(mono_get_exception_class());
|
||||||
p_exc = p_prop != NULL ? p_prop->get_value(p_exc) : NULL;
|
GDMonoProperty *inner_exc_prop = exc_class->get_property("InnerException");
|
||||||
if (p_exc != NULL)
|
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);
|
si.insert(0, separator);
|
||||||
|
|
||||||
|
p_exc = (MonoException *)inner_exc;
|
||||||
}
|
}
|
||||||
|
|
||||||
String file = si.size() ? si[0].file : __FILE__;
|
String file = si.size() ? si[0].file : __FILE__;
|
||||||
|
@ -475,4 +477,38 @@ void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) {
|
||||||
#endif
|
#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
|
} // namespace GDMonoUtils
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include <mono/metadata/threads.h>
|
#include <mono/metadata/threads.h>
|
||||||
|
|
||||||
#include "../mono_gc_handle.h"
|
#include "../mono_gc_handle.h"
|
||||||
|
#include "../utils/macros.h"
|
||||||
|
#include "../utils/thread_local.h"
|
||||||
#include "gd_mono_header.h"
|
#include "gd_mono_header.h"
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
@ -181,10 +183,28 @@ MonoObject *create_managed_from(const RID &p_from);
|
||||||
|
|
||||||
MonoDomain *create_domain(const String &p_friendly_name);
|
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 debug_print_unhandled_exception(MonoException *p_exc);
|
||||||
void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution);
|
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
|
} // 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)
|
#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float)
|
||||||
#endif
|
#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
|
#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);
|
GDMonoUtils::SignalAwaiter_SignalCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback);
|
||||||
|
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
thunk(get_target(), signal_args, &ex);
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
thunk(get_target(), signal_args, (MonoObject **)&exc);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
ERR_FAIL_V(Variant());
|
ERR_FAIL_V(Variant());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,11 +135,13 @@ SignalAwaiterHandle::~SignalAwaiterHandle() {
|
||||||
MonoObject *awaiter = get_target();
|
MonoObject *awaiter = get_target();
|
||||||
|
|
||||||
if (awaiter) {
|
if (awaiter) {
|
||||||
MonoObject *ex = NULL;
|
MonoException *exc = NULL;
|
||||||
thunk(awaiter, &ex);
|
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||||
|
thunk(awaiter, (MonoObject **)&exc);
|
||||||
|
GD_MONO_END_RUNTIME_INVOKE;
|
||||||
|
|
||||||
if (ex) {
|
if (exc) {
|
||||||
mono_print_unhandled_exception(ex);
|
GDMonoUtils::set_pending_exception(exc);
|
||||||
ERR_FAIL_V();
|
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