summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChibiDenDen <pdaniq@gmail.com>2020-01-14 01:19:37 +0200
committerChibiDenDen <pdaniq@gmail.com>2020-01-15 22:54:01 +0200
commit86aa12e806515e68514d4e8f97342a144fd8610f (patch)
treeb020074f0d37a246c4098f3e42595e5fbdd0095e
parent3d88a7bb22825025ee505b281fd92eb2c7d3cd2f (diff)
Keep a weak reference to orphan subclasses to reuse on class reload
-rw-r--r--modules/gdscript/gdscript.cpp51
-rw-r--r--modules/gdscript/gdscript.h7
-rw-r--r--modules/gdscript/gdscript_compiler.cpp10
3 files changed, 63 insertions, 5 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 8abf2ee7ca..8030837cd4 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -915,14 +915,43 @@ GDScript::GDScript() :
#endif
}
+void GDScript::_save_orphaned_subclasses() {
+ struct ClassRefWithName {
+ ObjectID id;
+ String fully_qualified_name;
+ };
+ Vector<ClassRefWithName> weak_subclasses;
+ // collect subclasses ObjectID and name
+ for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
+ E->get()->_owner = NULL; //bye, you are no longer owned cause I died
+ ClassRefWithName subclass;
+ subclass.id = E->get()->get_instance_id();
+ subclass.fully_qualified_name = E->get()->fully_qualified_name;
+ weak_subclasses.push_back(subclass);
+ }
+
+ // clear subclasses to allow unused subclasses to be deleted
+ subclasses.clear();
+ // subclasses are also held by constants, clear those as well
+ constants.clear();
+
+ // keep orphan subclass only for subclasses that are still in use
+ for (int i = 0; i < weak_subclasses.size(); i++) {
+ ClassRefWithName subclass = weak_subclasses[i];
+ Object *obj = ObjectDB::get_instance(subclass.id);
+ if (!obj)
+ continue;
+ // subclass is not released
+ GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id);
+ }
+}
+
GDScript::~GDScript() {
for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
memdelete(E->get());
}
- for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
- E->get()->_owner = NULL; //bye, you are no longer owned cause I died
- }
+ _save_orphaned_subclasses();
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->lock) {
@@ -2176,6 +2205,22 @@ GDScriptLanguage::~GDScriptLanguage() {
singleton = NULL;
}
+void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) {
+ orphan_subclasses[p_qualified_name] = p_subclass;
+}
+
+Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) {
+ Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
+ if (!orphan_subclass_element)
+ return Ref<GDScript>();
+ ObjectID orphan_subclass = orphan_subclass_element->get();
+ Object *obj = ObjectDB::get_instance(orphan_subclass);
+ orphan_subclasses.erase(orphan_subclass_element);
+ if (!obj)
+ return Ref<GDScript>();
+ return Ref<GDScript>(Object::cast_to<GDScript>(obj));
+}
+
/*************** RESOURCE ***************/
RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 0e2b812a22..4ae52238ce 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -132,6 +132,8 @@ class GDScript : public Script {
bool _update_exports();
+ void _save_orphaned_subclasses();
+
protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
bool _set(const StringName &p_name, const Variant &p_value);
@@ -355,6 +357,8 @@ class GDScriptLanguage : public ScriptLanguage {
bool profiling;
uint64_t script_frame_time;
+ Map<String, ObjectID> orphan_subclasses;
+
public:
int calls;
@@ -506,6 +510,9 @@ public:
virtual bool handles_global_class_type(const String &p_type) const;
virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const;
+ void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass);
+ Ref<GDScript> get_orphan_subclass(const String &p_qualified_name);
+
GDScriptLanguage();
~GDScriptLanguage();
};
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 711fa54d0b..fba1b992ec 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -2123,15 +2123,21 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C
StringName name = p_class->subclasses[i]->name;
Ref<GDScript> subclass;
+ String fully_qualified_name = p_script->fully_qualified_name + "::" + name;
if (old_subclasses.has(name)) {
subclass = old_subclasses[name];
} else {
- subclass.instance();
+ Ref<GDScript> orphan_subclass = GDScriptLanguage::get_singleton()->get_orphan_subclass(fully_qualified_name);
+ if (orphan_subclass.is_valid()) {
+ subclass = orphan_subclass;
+ } else {
+ subclass.instance();
+ }
}
subclass->_owner = p_script;
- subclass->fully_qualified_name = p_script->fully_qualified_name + "::" + name;
+ subclass->fully_qualified_name = fully_qualified_name;
p_script->subclasses.insert(name, subclass);
_make_scripts(subclass.ptr(), p_class->subclasses[i], false);