diff options
-rw-r--r-- | core/object.cpp | 7 | ||||
-rw-r--r-- | core/object.h | 6 | ||||
-rw-r--r-- | core/reference.cpp | 29 | ||||
-rw-r--r-- | core/script_language.h | 2 | ||||
-rw-r--r-- | drivers/coreaudio/audio_driver_coreaudio.cpp | 67 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_scene_gles3.cpp | 5 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.cpp | 5 | ||||
-rw-r--r-- | editor/plugins/texture_region_editor_plugin.cpp | 157 | ||||
-rw-r--r-- | editor/plugins/texture_region_editor_plugin.h | 3 | ||||
-rw-r--r-- | modules/gdscript/gdscript.cpp | 26 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 9 | ||||
-rw-r--r-- | modules/mono/csharp_script.cpp | 75 | ||||
-rw-r--r-- | modules/mono/csharp_script.h | 2 | ||||
-rw-r--r-- | modules/mono/mono_gc_handle.cpp | 7 | ||||
-rw-r--r-- | modules/mono/mono_gc_handle.h | 15 | ||||
-rw-r--r-- | modules/mono/signal_awaiter_utils.cpp | 7 | ||||
-rw-r--r-- | modules/mono/signal_awaiter_utils.h | 2 | ||||
-rw-r--r-- | modules/regex/regex.cpp | 6 | ||||
-rw-r--r-- | platform/android/export/export.cpp | 3 |
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; } |