Skip to content

Commit

Permalink
Merge pull request godotengine#17020 from neikeq/cs-api-asm-checks
Browse files Browse the repository at this point in the history
Mono: Better versioning and gracefully unloading of Godot API assemblies
  • Loading branch information
akien-mga authored Feb 25, 2018
2 parents 125fc8c + f37090c commit 7568a45
Show file tree
Hide file tree
Showing 15 changed files with 428 additions and 87 deletions.
30 changes: 30 additions & 0 deletions core/ustring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,36 @@ String String::num_int64(int64_t p_num, int base, bool capitalize_hex) {
return s;
}

String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) {

uint64_t n = p_num;

int chars = 0;
do {
n /= base;
chars++;
} while (n);

String s;
s.resize(chars + 1);
CharType *c = s.ptrw();
c[chars] = 0;
n = p_num;
do {
int mod = ABS(n % base);
if (mod >= 10) {
char a = (capitalize_hex ? 'A' : 'a');
c[--chars] = a + (mod - 10);
} else {
c[--chars] = '0' + mod;
}

n /= base;
} while (n);

return s;
}

String String::num_real(double p_num) {

String s;
Expand Down
1 change: 1 addition & 0 deletions core/ustring.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class String : public Vector<CharType> {
static String num_scientific(double p_num);
static String num_real(double p_num);
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false);
static String chr(CharType p_char);
static String md5(const uint8_t *p_md5);
static String hex_encode_buffer(const uint8_t *p_buffer, int p_len);
Expand Down
23 changes: 15 additions & 8 deletions modules/mono/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,18 @@ def make_cs_files_header(src, dst):
if i > 0:
header.write(', ')
header.write(byte_to_str(buf[buf_idx]))
inserted_files += '\tr_files.insert(\"' + file + '\", ' \
inserted_files += '\tr_files.insert("' + file + '", ' \
'CompressedFile(_cs_' + name + '_compressed_size, ' \
'_cs_' + name + '_uncompressed_size, ' \
'_cs_' + name + '_compressed));\n'
header.write(' };\n')
version_file = os.path.join(src, 'VERSION.txt')
with open(version_file, 'r') as content_file:
try:
glue_version = int(content_file.read()) # make sure the format is valid
header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
except ValueError:
raise ValueError('Invalid C# glue version in: ' + version_file)
header.write('\nstruct CompressedFile\n' '{\n'
'\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n'
'\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n'
Expand Down Expand Up @@ -80,23 +87,23 @@ def find_msbuild_unix(filename):
import sys

hint_dirs = ['/opt/novell/mono/bin']
if sys.platform == "darwin":
if sys.platform == 'darwin':
hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin'] + hint_dirs

for hint_dir in hint_dirs:
hint_path = os.path.join(hint_dir, filename)
if os.path.isfile(hint_path):
return hint_path
elif os.path.isfile(hint_path + ".exe"):
return hint_path + ".exe"
elif os.path.isfile(hint_path + '.exe'):
return hint_path + '.exe'

for hint_dir in os.environ["PATH"].split(os.pathsep):
for hint_dir in os.environ['PATH'].split(os.pathsep):
hint_dir = hint_dir.strip('"')
hint_path = os.path.join(hint_dir, filename)
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
return hint_path + ".exe"
if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
return hint_path + '.exe'

return None

Expand Down Expand Up @@ -152,7 +159,7 @@ def mono_build_solution(source, target, env):
xbuild_fallback = env['xbuild_fallback']

if xbuild_fallback and os.name == 'nt':
print("Option 'xbuild_fallback' not supported on Windows")
print('Option \'xbuild_fallback\' not supported on Windows')
xbuild_fallback = False

if xbuild_fallback:
Expand Down
2 changes: 1 addition & 1 deletion modules/mono/csharp_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ 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

if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_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>();

MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr());
Expand Down
78 changes: 55 additions & 23 deletions modules/mono/editor/bindings_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@

#define LOCAL_RET "ret"

#define CS_CLASS_NATIVECALLS "NativeCalls"
#define CS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls"
#define CS_FIELD_MEMORYOWN "memoryOwn"
#define CS_PARAM_METHODBIND "method"
#define CS_PARAM_INSTANCE "ptr"
Expand Down Expand Up @@ -105,6 +103,8 @@
#define C_METHOD_MANAGED_TO_DICT C_NS_MONOMARSHAL "::mono_object_to_Dictionary"
#define C_METHOD_MANAGED_FROM_DICT C_NS_MONOMARSHAL "::Dictionary_to_mono_object"

#define BINDINGS_GENERATOR_VERSION UINT32_C(1)

const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
bool BindingsGenerator::verbose_output = false;
Expand Down Expand Up @@ -529,7 +529,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
"using System.Collections.Generic;\n"
"\n");
cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
cs_icalls_content.push_back(INDENT1 "internal static class " CS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);
cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);

cs_icalls_content.push_back(INDENT2 "internal static ulong godot_api_hash = ");
cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n");
cs_icalls_content.push_back(INDENT2 "internal static uint bindings_version = ");
cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
cs_icalls_content.push_back(INDENT2 "internal static uint cs_glue_version = ");
cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n");
cs_icalls_content.push_back("\n");

#define ADD_INTERNAL_CALL(m_icall) \
if (!m_icall.editor_only) { \
Expand All @@ -551,7 +559,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo

cs_icalls_content.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);

String internal_methods_file = path_join(core_dir, CS_CLASS_NATIVECALLS ".cs");
String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs");

Error err = _save_file(internal_methods_file, cs_icalls_content);
if (err != OK)
Expand Down Expand Up @@ -626,7 +634,15 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
"using System.Collections.Generic;\n"
"\n");
cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
cs_icalls_content.push_back(INDENT1 "internal static class " CS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);
cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);

cs_icalls_content.push_back(INDENT2 "internal static ulong godot_api_hash = ");
cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + ";\n");
cs_icalls_content.push_back(INDENT2 "internal static uint bindings_version = ");
cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
cs_icalls_content.push_back(INDENT2 "internal static uint cs_glue_version = ");
cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n");
cs_icalls_content.push_back("\n");

#define ADD_INTERNAL_CALL(m_icall) \
if (m_icall.editor_only) { \
Expand All @@ -648,7 +664,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,

cs_icalls_content.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);

String internal_methods_file = path_join(core_dir, CS_CLASS_NATIVECALLS_EDITOR ".cs");
String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs");

Error err = _save_file(internal_methods_file, cs_icalls_content);
if (err != OK)
Expand Down Expand Up @@ -882,7 +898,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.push_back("\";\n");

output.push_back(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
output.push_back(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
output.push_back("." ICALL_PREFIX);
output.push_back(itype.name);
output.push_back(SINGLETON_ICALL_SUFFIX "();\n");
Expand Down Expand Up @@ -912,7 +928,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// The engine will initialize the pointer field of the managed side before calling the constructor
// This is why we only allocate a new native object from the constructor if the pointer field is not set
output.push_back(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
output.push_back(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
output.push_back("." + ctor_method);
output.push_back("(this);\n" CLOSE_BLOCK_L2);
} else {
Expand Down Expand Up @@ -956,7 +972,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
"if (disposed) return;\n" INDENT3
"if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3
"if (" CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L4 CS_FIELD_MEMORYOWN
" = false;\n" INDENT5 CS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
" = false;\n" INDENT5 BINDINGS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
"(this, " BINDINGS_PTR_FIELD ");\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3
"this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" INDENT3
"GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
Expand Down Expand Up @@ -1229,7 +1245,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
{
if (p_itype.is_object_type && !p_imethod.is_virtual && !p_imethod.requires_object_call) {
p_output.push_back(MEMBER_BEGIN "private static IntPtr ");
p_output.push_back(method_bind_field + " = " CS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
p_output.push_back(method_bind_field + " = " BINDINGS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
p_output.push_back(p_imethod.name);
p_output.push_back("\");\n");
}
Expand Down Expand Up @@ -1310,7 +1326,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf

const InternalCall *im_icall = match->value();

String im_call = im_icall->editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS;
String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS;
im_call += "." + im_icall->name + "(" + icall_params + ");\n";

if (p_imethod.arguments.size())
Expand Down Expand Up @@ -1400,25 +1416,33 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
}

output.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK);

output.push_back("uint64_t get_core_api_hash() { return ");
output.push_back(itos(GDMono::get_singleton()->get_api_core_hash()) + "; }\n");
output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + "; }\n");

output.push_back("#ifdef TOOLS_ENABLED\n"
"uint64_t get_editor_api_hash() { return ");
output.push_back(itos(GDMono::get_singleton()->get_api_editor_hash()) +
output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) +
"; }\n#endif // TOOLS_ENABLED\n");

output.push_back("uint32_t get_bindings_version() { return ");
output.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + "; }\n");
output.push_back("uint32_t get_cs_glue_version() { return ");
output.push_back(String::num_uint64(CS_GLUE_VERSION) + "; }\n");

output.push_back("void register_generated_icalls() " OPEN_BLOCK);
output.push_back("\tgodot_register_header_icalls();");

#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
{ \
output.push_back("\tmono_add_internal_call("); \
output.push_back("\"" BINDINGS_NAMESPACE "."); \
output.push_back(m_icall.editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS); \
output.push_back("::"); \
output.push_back(m_icall.name); \
output.push_back("\", (void*)"); \
output.push_back(m_icall.name); \
output.push_back(");\n"); \
#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
{ \
output.push_back("\tmono_add_internal_call("); \
output.push_back("\"" BINDINGS_NAMESPACE "."); \
output.push_back(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
output.push_back("::"); \
output.push_back(m_icall.name); \
output.push_back("\", (void*)"); \
output.push_back(m_icall.name); \
output.push_back(");\n"); \
}

bool tools_sequence = false;
Expand Down Expand Up @@ -1486,6 +1510,14 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
return OK;
}

uint32_t BindingsGenerator::get_version() {
return BINDINGS_GENERATOR_VERSION;
}

uint32_t BindingsGenerator::get_cs_glue_version() {
return CS_GLUE_VERSION;
}

Error BindingsGenerator::_save_file(const String &p_path, const List<String> &p_content) {

FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
Expand Down
3 changes: 3 additions & 0 deletions modules/mono/editor/bindings_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,9 @@ class BindingsGenerator {
Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true);
Error generate_glue(const String &p_output_dir);

static uint32_t get_version();
static uint32_t get_cs_glue_version();

void initialize();

_FORCE_INLINE_ static BindingsGenerator *get_singleton() {
Expand Down
Loading

0 comments on commit 7568a45

Please sign in to comment.