summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/object.cpp7
-rw-r--r--core/object.h6
-rw-r--r--core/reference.cpp29
-rw-r--r--core/script_language.h2
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp67
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp5
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp5
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp157
-rw-r--r--editor/plugins/texture_region_editor_plugin.h3
-rw-r--r--modules/gdscript/gdscript.cpp26
-rw-r--r--modules/gdscript/gdscript_compiler.cpp9
-rw-r--r--modules/mono/csharp_script.cpp75
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/mono/mono_gc_handle.cpp7
-rw-r--r--modules/mono/mono_gc_handle.h15
-rw-r--r--modules/mono/signal_awaiter_utils.cpp7
-rw-r--r--modules/mono/signal_awaiter_utils.h2
-rw-r--r--modules/regex/regex.cpp6
-rw-r--r--platform/android/export/export.cpp3
19 files changed, 307 insertions, 126 deletions
diff --git a/core/object.cpp b/core/object.cpp
index e83abaece7..24a31930a0 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -1916,7 +1916,11 @@ void *Object::get_script_instance_binding(int p_script_language_index) {
//as it should not really affect performance much (won't be called too often), as in far most caes the condition below will be false afterwards
if (!_script_instance_bindings[p_script_language_index]) {
- _script_instance_bindings[p_script_language_index] = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
+ void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
+ if (script_data) {
+ atomic_increment(&instance_binding_count);
+ _script_instance_bindings[p_script_language_index] = script_data;
+ }
}
return _script_instance_bindings[p_script_language_index];
@@ -1931,6 +1935,7 @@ Object::Object() {
_instance_ID = ObjectDB::add_instance(this);
_can_translate = true;
_is_queued_for_deletion = false;
+ instance_binding_count = 0;
memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
script_instance = NULL;
#ifdef TOOLS_ENABLED
diff --git a/core/object.h b/core/object.h
index d741371306..43e1cf4785 100644
--- a/core/object.h
+++ b/core/object.h
@@ -490,10 +490,12 @@ private:
void _set_indexed_bind(const NodePath &p_name, const Variant &p_value);
Variant _get_indexed_bind(const NodePath &p_name) const;
- void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
-
void property_list_changed_notify();
+ friend class Reference;
+ uint32_t instance_binding_count;
+ void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
+
protected:
virtual void _initialize_classv() { initialize_class(); }
virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; };
diff --git a/core/reference.cpp b/core/reference.cpp
index c33a7c683c..6e1520d81d 100644
--- a/core/reference.cpp
+++ b/core/reference.cpp
@@ -66,8 +66,17 @@ int Reference::reference_get_count() const {
bool Reference::reference() {
bool success = refcount.ref();
- if (success && get_script_instance()) {
- get_script_instance()->refcount_incremented();
+ if (success && refcount.get() <= 2 /* higher is not relevant */) {
+ if (get_script_instance()) {
+ get_script_instance()->refcount_incremented();
+ }
+ if (instance_binding_count > 0) {
+ for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
+ if (_script_instance_bindings[i]) {
+ ScriptServer::get_language(i)->refcount_incremented_instance_binding(this);
+ }
+ }
+ }
}
return success;
@@ -77,9 +86,19 @@ bool Reference::unreference() {
bool die = refcount.unref();
- if (get_script_instance()) {
- bool script_ret = get_script_instance()->refcount_decremented();
- die = die && script_ret;
+ if (refcount.get() <= 1 /* higher is not relevant */) {
+ if (get_script_instance()) {
+ bool script_ret = get_script_instance()->refcount_decremented();
+ die = die && script_ret;
+ }
+ if (instance_binding_count > 0) {
+ for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
+ if (_script_instance_bindings[i]) {
+ bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this);
+ die = die && script_ret;
+ }
+ }
+ }
}
return die;
diff --git a/core/script_language.h b/core/script_language.h
index 71b705e960..573e7b4fa1 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -311,6 +311,8 @@ public:
virtual void *alloc_instance_binding_data(Object *p_object) { return NULL; } //optional, not used by all languages
virtual void free_instance_binding_data(void *p_data) {} //optional, not used by all languages
+ virtual void refcount_incremented_instance_binding(Object *p_object) {} //optional, not used by all languages
+ virtual bool refcount_decremented_instance_binding(Object *p_object) { return true; } //return true if it can die //optional, not used by all languages
virtual void frame();
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index 689f1f462d..45d62e797f 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -331,55 +331,57 @@ bool AudioDriverCoreAudio::try_lock() {
}
void AudioDriverCoreAudio::finish() {
- OSStatus result;
+ if (audio_unit) {
+ OSStatus result;
- lock();
+ lock();
- AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
- result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
- if (result != noErr) {
- ERR_PRINT("AudioUnitSetProperty failed");
- }
-
- if (active) {
- result = AudioOutputUnitStop(audio_unit);
+ AURenderCallbackStruct callback;
+ zeromem(&callback, sizeof(AURenderCallbackStruct));
+ result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
if (result != noErr) {
- ERR_PRINT("AudioOutputUnitStop failed");
+ ERR_PRINT("AudioUnitSetProperty failed");
}
- active = false;
- }
+ if (active) {
+ result = AudioOutputUnitStop(audio_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioOutputUnitStop failed");
+ }
- result = AudioUnitUninitialize(audio_unit);
- if (result != noErr) {
- ERR_PRINT("AudioUnitUninitialize failed");
- }
+ active = false;
+ }
+
+ result = AudioUnitUninitialize(audio_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioUnitUninitialize failed");
+ }
#ifdef OSX_ENABLED
- AudioObjectPropertyAddress prop;
- prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
- prop.mScope = kAudioObjectPropertyScopeGlobal;
- prop.mElement = kAudioObjectPropertyElementMaster;
+ AudioObjectPropertyAddress prop;
+ prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+ prop.mScope = kAudioObjectPropertyScopeGlobal;
+ prop.mElement = kAudioObjectPropertyElementMaster;
- result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
- if (result != noErr) {
- ERR_PRINT("AudioObjectRemovePropertyListener failed");
- }
+ result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
+ if (result != noErr) {
+ ERR_PRINT("AudioObjectRemovePropertyListener failed");
+ }
#endif
- result = AudioComponentInstanceDispose(audio_unit);
- if (result != noErr) {
- ERR_PRINT("AudioComponentInstanceDispose failed");
- }
+ result = AudioComponentInstanceDispose(audio_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioComponentInstanceDispose failed");
+ }
- unlock();
+ unlock();
+ }
if (mutex) {
memdelete(mutex);
mutex = NULL;
}
-};
+}
Error AudioDriverCoreAudio::capture_start() {
@@ -576,6 +578,7 @@ String AudioDriverCoreAudio::capture_get_device() {
#endif
AudioDriverCoreAudio::AudioDriverCoreAudio() {
+ audio_unit = NULL;
active = false;
mutex = NULL;
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index eebdbe9493..88f14890ef 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1008,7 +1008,10 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
light_instance->light = p_light;
light_instance->light_ptr = storage->light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light_instance->light_ptr, RID());
+ if (!light_instance->light_ptr) {
+ memdelete(light_instance);
+ ERR_FAIL_COND_V(!light_instance->light_ptr, RID());
+ }
light_instance->self = light_instance_owner.make_rid(light_instance);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 3697cccef4..0bb0e12b8e 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -6998,7 +6998,10 @@ RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) {
//printf("errnum: %x\n",status);
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
- ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID());
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ memdelete(cls);
+ ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID());
+ }
return canvas_light_shadow_owner.make_rid(cls);
}
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 4a9cbfe535..4390b94ece 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -356,8 +356,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev);
} else if (node_ninepatch) {
- // FIXME: Is this intentional?
- } else if (node_ninepatch) {
undo_redo->add_do_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect());
undo_redo->add_undo_method(node_ninepatch, "set_region_rect", rect_prev);
} else if (obj_styleBox.is_valid()) {
@@ -521,6 +519,10 @@ void TextureRegionEditor::_set_snap_mode(int p_mode) {
else
hb_grid->hide();
+ if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
+ _update_autoslice();
+ }
+
edit_draw->update();
}
@@ -562,7 +564,8 @@ void TextureRegionEditor::_zoom_in() {
}
void TextureRegionEditor::_zoom_reset() {
- if (draw_zoom == 1) return;
+ if (draw_zoom == 1)
+ return;
draw_zoom = 1;
edit_draw->update();
}
@@ -585,25 +588,91 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) {
atlas_tex->set_region(rect);
}
-void TextureRegionEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_PROCESS: {
- if (node_sprite) {
- if (node_sprite->is_region()) {
+void TextureRegionEditor::_update_autoslice() {
+ autoslice_is_dirty = false;
+ autoslice_cache.clear();
- set_process(false);
- EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+ Ref<Texture> texture = NULL;
+ if (node_sprite)
+ texture = node_sprite->get_texture();
+ else if (node_ninepatch)
+ texture = node_ninepatch->get_texture();
+ else if (obj_styleBox.is_valid())
+ texture = obj_styleBox->get_texture();
+ else if (atlas_tex.is_valid())
+ texture = atlas_tex->get_atlas();
+
+ if (texture.is_null()) {
+ return;
+ }
+
+ for (int y = 0; y < texture->get_height(); y++) {
+ for (int x = 0; x < texture->get_width(); x++) {
+ if (texture->is_pixel_opaque(x, y)) {
+ bool found = false;
+ for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) {
+ Rect2 grown = E->get().grow(1.5);
+ if (grown.has_point(Point2(x, y))) {
+ E->get().expand_to(Point2(x, y));
+ E->get().expand_to(Point2(x + 1, y + 1));
+ x = E->get().position.x + E->get().size.x - 1;
+ bool merged = true;
+ while (merged) {
+ merged = false;
+ bool queue_erase = false;
+ for (List<Rect2>::Element *F = autoslice_cache.front(); F; F = F->next()) {
+ if (queue_erase) {
+ autoslice_cache.erase(F->prev());
+ queue_erase = false;
+ }
+ if (F == E)
+ continue;
+ if (E->get().grow(1).intersects(F->get())) {
+ E->get().expand_to(F->get().position);
+ E->get().expand_to(F->get().position + F->get().size);
+ if (F->prev()) {
+ F = F->prev();
+ autoslice_cache.erase(F->next());
+ } else {
+ queue_erase = true;
+ // Can't delete the first rect in the list.
+ }
+ merged = true;
+ }
+ }
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ Rect2 new_rect(x, y, 1, 1);
+ autoslice_cache.push_back(new_rect);
}
- } else {
- set_process(false);
}
- } break;
- case NOTIFICATION_THEME_CHANGED:
+ }
+ }
+ cache_map[texture->get_rid()] = autoslice_cache;
+}
+
+void TextureRegionEditor::_notification(int p_what) {
+ switch (p_what) {
case NOTIFICATION_READY: {
zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons"));
zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons"));
zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons"));
} break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
+ _update_autoslice();
+ }
+ } break;
+ case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ // This happens when the user leaves the Editor and returns,
+ // he/she could have changed the textures, so the cache is cleared
+ cache_map.clear();
+ _edit_region();
+ } break;
}
}
@@ -709,57 +778,15 @@ void TextureRegionEditor::_edit_region() {
return;
}
- autoslice_cache.clear();
- Ref<Image> i;
- i.instance();
- if (i->load(texture->get_path()) == OK) {
- BitMap bm;
- bm.create_from_image_alpha(i);
- for (int y = 0; y < i->get_height(); y++) {
- for (int x = 0; x < i->get_width(); x++) {
- if (bm.get_bit(Point2(x, y))) {
- bool found = false;
- for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) {
- Rect2 grown = E->get().grow(1.5);
- if (grown.has_point(Point2(x, y))) {
- E->get().expand_to(Point2(x, y));
- E->get().expand_to(Point2(x + 1, y + 1));
- x = E->get().position.x + E->get().size.x - 1;
- bool merged = true;
- while (merged) {
- merged = false;
- bool queue_erase = false;
- for (List<Rect2>::Element *F = autoslice_cache.front(); F; F = F->next()) {
- if (queue_erase) {
- autoslice_cache.erase(F->prev());
- queue_erase = false;
- }
- if (F == E)
- continue;
- if (E->get().grow(1).intersects(F->get())) {
- E->get().expand_to(F->get().position);
- E->get().expand_to(F->get().position + F->get().size);
- if (F->prev()) {
- F = F->prev();
- autoslice_cache.erase(F->next());
- } else {
- queue_erase = true;
- //Can't delete the first rect in the list.
- }
- merged = true;
- }
- }
- }
- found = true;
- break;
- }
- }
- if (!found) {
- Rect2 new_rect(x, y, 1, 1);
- autoslice_cache.push_back(new_rect);
- }
- }
- }
+ if (cache_map.has(texture->get_rid())) {
+ autoslice_cache = cache_map[texture->get_rid()];
+ autoslice_is_dirty = false;
+ return;
+ } else {
+ if (is_visible() && snap_mode == SNAP_AUTOSLICE) {
+ _update_autoslice();
+ } else {
+ autoslice_is_dirty = true;
}
}
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index 670cc86bbb..61ef769f89 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -92,7 +92,9 @@ class TextureRegionEditor : public Control {
Rect2 rect_prev;
float prev_margin;
int edited_margin;
+ Map<RID, List<Rect2> > cache_map;
List<Rect2> autoslice_cache;
+ bool autoslice_is_dirty;
bool drag;
bool creating;
@@ -110,6 +112,7 @@ class TextureRegionEditor : public Control {
void _zoom_reset();
void _zoom_out();
void apply_rect(const Rect2 &rect);
+ void _update_autoslice();
protected:
void _notification(int p_what);
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index e05bc7d591..33d9c011f2 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -126,7 +126,10 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
GDScriptLanguage::singleton->lock->unlock();
#endif
- ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing
+ if (r_error.error != Variant::CallError::CALL_OK) {
+ memdelete(instance);
+ ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing
+ }
}
//@TODO make thread safe
@@ -719,22 +722,36 @@ Error GDScript::load_byte_code(const String &p_path) {
FileAccess *fa = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V(!fa, ERR_CANT_OPEN);
+
FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
ERR_FAIL_COND_V(!fae, ERR_CANT_OPEN);
+
Vector<uint8_t> key;
key.resize(32);
for (int i = 0; i < key.size(); i++) {
key.write[i] = script_encryption_key[i];
}
+
Error err = fae->open_and_parse(fa, key, FileAccessEncrypted::MODE_READ);
- ERR_FAIL_COND_V(err, err);
+
+ if (err) {
+ fa->close();
+ memdelete(fa);
+ memdelete(fae);
+
+ ERR_FAIL_COND_V(err, err);
+ }
+
bytecode.resize(fae->get_len());
fae->get_buffer(bytecode.ptrw(), bytecode.size());
+ fae->close();
memdelete(fae);
+
} else {
bytecode = FileAccess::get_file_as_array(p_path);
}
+
ERR_FAIL_COND_V(bytecode.size() == 0, ERR_PARSE_ERROR);
path = p_path;
@@ -2097,7 +2114,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori
Error err = script->load_byte_code(p_path);
if (err != OK) {
-
+ memdelete(script);
ERR_FAIL_COND_V(err != OK, RES());
}
@@ -2105,7 +2122,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori
Error err = script->load_source_code(p_path);
if (err != OK) {
-
+ memdelete(script);
ERR_FAIL_COND_V(err != OK, RES());
}
@@ -2120,6 +2137,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori
return scriptres;
}
+
void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("gd");
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 1403184557..3b494dbae7 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1322,6 +1322,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
int ret = _parse_expression(codegen, op, p_stack_level);
if (ret < 0) {
+ memdelete(id);
+ memdelete(op);
return ERR_PARSE_ERROR;
}
@@ -1341,6 +1343,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
// compile the condition
int ret = _parse_expression(codegen, branch.compiled_pattern, p_stack_level);
if (ret < 0) {
+ memdelete(id);
+ memdelete(op);
return ERR_PARSE_ERROR;
}
@@ -1353,6 +1357,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
Error err = _parse_block(codegen, branch.body, p_stack_level, p_break_addr, continue_addr);
if (err) {
+ memdelete(id);
+ memdelete(op);
return ERR_PARSE_ERROR;
}
@@ -1364,6 +1370,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
codegen.opcodes.write[break_addr + 1] = codegen.opcodes.size();
+ memdelete(id);
+ memdelete(op);
+
} break;
case GDScriptParser::ControlFlowNode::CF_IF: {
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index b8b77924f7..d2a861dbe8 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1013,6 +1013,69 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
#endif
}
+void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
+
+ Reference *ref_owner = Object::cast_to<Reference>(p_object);
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!ref_owner);
+#endif
+
+ void *data = p_object->get_script_instance_binding(get_language_index());
+ if (!data)
+ return;
+ Ref<MonoGCHandle> &gchandle = ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->get();
+
+ if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ // The reference count was increased after the managed side was the only one referencing our owner.
+ // This means the owner is being referenced again by the unmanaged side,
+ // so the owner must hold the managed side alive again to avoid it from being GCed.
+
+ MonoObject *target = gchandle->get_target();
+ if (!target)
+ return; // Called after the managed side was collected, so nothing to do here
+
+ // Release the current weak handle and replace it with a strong handle.
+ uint32_t strong_gchandle = MonoGCHandle::make_strong_handle(target);
+ gchandle->release();
+ gchandle->set_handle(strong_gchandle, MonoGCHandle::STRONG_HANDLE);
+ }
+}
+
+bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
+
+ Reference *ref_owner = Object::cast_to<Reference>(p_object);
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!ref_owner);
+#endif
+
+ int refcount = ref_owner->reference_get_count();
+
+ void *data = p_object->get_script_instance_binding(get_language_index());
+ if (!data)
+ return refcount == 0;
+ Ref<MonoGCHandle> &gchandle = ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->get();
+
+ if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ // If owner owner is no longer referenced by the unmanaged side,
+ // the managed instance takes responsibility of deleting the owner when GCed.
+
+ MonoObject *target = gchandle->get_target();
+ if (!target)
+ return refcount == 0; // Called after the managed side was collected, so nothing to do here
+
+ // Release the current strong handle and replace it with a weak handle.
+ uint32_t weak_gchandle = MonoGCHandle::make_weak_handle(target);
+ gchandle->release();
+ gchandle->set_handle(weak_gchandle, MonoGCHandle::WEAK_HANDLE);
+
+ return false;
+ }
+
+ return refcount == 0;
+}
+
CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle) {
CSharpInstance *instance = memnew(CSharpInstance);
@@ -1303,11 +1366,13 @@ void CSharpInstance::mono_object_disposed() {
void CSharpInstance::refcount_incremented() {
+#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref);
+#endif
Reference *ref_owner = Object::cast_to<Reference>(owner);
- if (ref_owner->reference_get_count() > 1) { // The managed side also holds a reference, hence 1 instead of 0
+ if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
@@ -1315,26 +1380,28 @@ void CSharpInstance::refcount_incremented() {
// Release the current weak handle and replace it with a strong handle.
uint32_t strong_gchandle = MonoGCHandle::make_strong_handle(gchandle->get_target());
gchandle->release();
- gchandle->set_handle(strong_gchandle);
+ gchandle->set_handle(strong_gchandle, MonoGCHandle::STRONG_HANDLE);
}
}
bool CSharpInstance::refcount_decremented() {
+#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref);
+#endif
Reference *ref_owner = Object::cast_to<Reference>(owner);
int refcount = ref_owner->reference_get_count();
- if (refcount == 1) { // The managed side also holds a reference, hence 1 instead of 0
+ if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
// Release the current strong handle and replace it with a weak handle.
uint32_t weak_gchandle = MonoGCHandle::make_weak_handle(gchandle->get_target());
gchandle->release();
- gchandle->set_handle(weak_gchandle);
+ gchandle->set_handle(weak_gchandle, MonoGCHandle::WEAK_HANDLE);
return false;
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 53644eafae..1a5d0c8a69 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -346,6 +346,8 @@ public:
// Don't use these. I'm watching you
virtual void *alloc_instance_binding_data(Object *p_object);
virtual void free_instance_binding_data(void *p_data);
+ virtual void refcount_incremented_instance_binding(Object *p_object);
+ virtual bool refcount_decremented_instance_binding(Object *p_object);
#ifdef DEBUG_ENABLED
Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace);
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index 12109045e0..9f0e933a8c 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -44,12 +44,12 @@ uint32_t MonoGCHandle::make_weak_handle(MonoObject *p_object) {
Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) {
- return memnew(MonoGCHandle(make_strong_handle(p_object)));
+ return memnew(MonoGCHandle(make_strong_handle(p_object), STRONG_HANDLE));
}
Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) {
- return memnew(MonoGCHandle(make_weak_handle(p_object)));
+ return memnew(MonoGCHandle(make_weak_handle(p_object), WEAK_HANDLE));
}
void MonoGCHandle::release() {
@@ -64,9 +64,10 @@ void MonoGCHandle::release() {
}
}
-MonoGCHandle::MonoGCHandle(uint32_t p_handle) {
+MonoGCHandle::MonoGCHandle(uint32_t p_handle, HandleType p_handle_type) {
released = false;
+ weak = p_handle_type == WEAK_HANDLE;
handle = p_handle;
}
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index 9cb3ef0fbb..7eeaba30e0 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -40,24 +40,33 @@ class MonoGCHandle : public Reference {
GDCLASS(MonoGCHandle, Reference)
bool released;
+ bool weak;
uint32_t handle;
public:
+ enum HandleType {
+ STRONG_HANDLE,
+ WEAK_HANDLE
+ };
+
static uint32_t make_strong_handle(MonoObject *p_object);
static uint32_t make_weak_handle(MonoObject *p_object);
static Ref<MonoGCHandle> create_strong(MonoObject *p_object);
static Ref<MonoGCHandle> create_weak(MonoObject *p_object);
+ _FORCE_INLINE_ bool is_weak() { return weak; }
+
_FORCE_INLINE_ MonoObject *get_target() const { return released ? NULL : mono_gchandle_get_target(handle); }
- _FORCE_INLINE_ void set_handle(uint32_t p_handle) {
- handle = p_handle;
+ _FORCE_INLINE_ void set_handle(uint32_t p_handle, HandleType p_handle_type) {
released = false;
+ weak = p_handle_type == WEAK_HANDLE;
+ handle = p_handle;
}
void release();
- MonoGCHandle(uint32_t p_handle);
+ MonoGCHandle(uint32_t p_handle, HandleType p_handle_type);
~MonoGCHandle();
};
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 54720652fa..add1e506ea 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -42,8 +42,7 @@ Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p
ERR_FAIL_NULL_V(p_source, ERR_INVALID_DATA);
ERR_FAIL_NULL_V(p_target, ERR_INVALID_DATA);
- uint32_t awaiter_handle = MonoGCHandle::make_strong_handle(p_awaiter);
- Ref<SignalAwaiterHandle> sa_con = memnew(SignalAwaiterHandle(awaiter_handle));
+ Ref<SignalAwaiterHandle> sa_con = memnew(SignalAwaiterHandle(p_awaiter));
#ifdef DEBUG_ENABLED
sa_con->set_connection_target(p_target);
#endif
@@ -119,8 +118,8 @@ void SignalAwaiterHandle::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &SignalAwaiterHandle::_signal_callback, MethodInfo("_signal_callback"));
}
-SignalAwaiterHandle::SignalAwaiterHandle(uint32_t p_managed_handle) :
- MonoGCHandle(p_managed_handle) {
+SignalAwaiterHandle::SignalAwaiterHandle(MonoObject *p_managed) :
+ MonoGCHandle(MonoGCHandle::make_strong_handle(p_managed), STRONG_HANDLE) {
#ifdef DEBUG_ENABLED
conn_target_id = 0;
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index a6a205ff8d..1920432709 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -64,7 +64,7 @@ public:
}
#endif
- SignalAwaiterHandle(uint32_t p_managed_handle);
+ SignalAwaiterHandle(MonoObject *p_managed);
~SignalAwaiterHandle();
};
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 733f32277b..bdd3e31eb8 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -205,6 +205,8 @@ Error RegEx::compile(const String &p_pattern) {
code = pcre2_compile_16(p, pattern.length(), flags, &err, &offset, cctx);
+ pcre2_compile_context_free_16(cctx);
+
if (!code) {
PCRE2_UCHAR16 buf[256];
pcre2_get_error_message_16(err, buf, 256);
@@ -221,6 +223,8 @@ Error RegEx::compile(const String &p_pattern) {
code = pcre2_compile_32(p, pattern.length(), flags, &err, &offset, cctx);
+ pcre2_compile_context_free_32(cctx);
+
if (!code) {
PCRE2_UCHAR32 buf[256];
pcre2_get_error_message_32(err, buf, 256);
@@ -285,6 +289,8 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end)
if (res < 0) {
pcre2_match_data_free_32(match);
+ pcre2_match_context_free_32(mctx);
+
return NULL;
}
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index b76b0d5dbe..5c8d9e078f 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -1591,8 +1591,11 @@ public:
String apkfname = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
String fullpath = p_path.get_base_dir().plus_file(apkfname);
err = save_pack(p_preset, fullpath);
+
if (err != OK) {
+ unzClose(pkg);
EditorNode::add_io_error("Could not write expansion package file: " + apkfname);
+
return OK;
}