Skip to content

Commit cd7b51b

Browse files
authored
Merge pull request #35102 from ChibiDenDen/reuse_orphaned_subclass
#34161: Keep a weak reference to orphan subclasses to reuse on class reload
2 parents 9986f38 + 86aa12e commit cd7b51b

File tree

3 files changed

+63
-5
lines changed

3 files changed

+63
-5
lines changed

modules/gdscript/gdscript.cpp

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -915,14 +915,43 @@ GDScript::GDScript() :
915915
#endif
916916
}
917917

918+
void GDScript::_save_orphaned_subclasses() {
919+
struct ClassRefWithName {
920+
ObjectID id;
921+
String fully_qualified_name;
922+
};
923+
Vector<ClassRefWithName> weak_subclasses;
924+
// collect subclasses ObjectID and name
925+
for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
926+
E->get()->_owner = NULL; //bye, you are no longer owned cause I died
927+
ClassRefWithName subclass;
928+
subclass.id = E->get()->get_instance_id();
929+
subclass.fully_qualified_name = E->get()->fully_qualified_name;
930+
weak_subclasses.push_back(subclass);
931+
}
932+
933+
// clear subclasses to allow unused subclasses to be deleted
934+
subclasses.clear();
935+
// subclasses are also held by constants, clear those as well
936+
constants.clear();
937+
938+
// keep orphan subclass only for subclasses that are still in use
939+
for (int i = 0; i < weak_subclasses.size(); i++) {
940+
ClassRefWithName subclass = weak_subclasses[i];
941+
Object *obj = ObjectDB::get_instance(subclass.id);
942+
if (!obj)
943+
continue;
944+
// subclass is not released
945+
GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id);
946+
}
947+
}
948+
918949
GDScript::~GDScript() {
919950
for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
920951
memdelete(E->get());
921952
}
922953

923-
for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
924-
E->get()->_owner = NULL; //bye, you are no longer owned cause I died
925-
}
954+
_save_orphaned_subclasses();
926955

927956
#ifdef DEBUG_ENABLED
928957
if (GDScriptLanguage::get_singleton()->lock) {
@@ -2176,6 +2205,22 @@ GDScriptLanguage::~GDScriptLanguage() {
21762205
singleton = NULL;
21772206
}
21782207

2208+
void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) {
2209+
orphan_subclasses[p_qualified_name] = p_subclass;
2210+
}
2211+
2212+
Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) {
2213+
Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
2214+
if (!orphan_subclass_element)
2215+
return Ref<GDScript>();
2216+
ObjectID orphan_subclass = orphan_subclass_element->get();
2217+
Object *obj = ObjectDB::get_instance(orphan_subclass);
2218+
orphan_subclasses.erase(orphan_subclass_element);
2219+
if (!obj)
2220+
return Ref<GDScript>();
2221+
return Ref<GDScript>(Object::cast_to<GDScript>(obj));
2222+
}
2223+
21792224
/*************** RESOURCE ***************/
21802225

21812226
RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) {

modules/gdscript/gdscript.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ class GDScript : public Script {
132132

133133
bool _update_exports();
134134

135+
void _save_orphaned_subclasses();
136+
135137
protected:
136138
bool _get(const StringName &p_name, Variant &r_ret) const;
137139
bool _set(const StringName &p_name, const Variant &p_value);
@@ -355,6 +357,8 @@ class GDScriptLanguage : public ScriptLanguage {
355357
bool profiling;
356358
uint64_t script_frame_time;
357359

360+
Map<String, ObjectID> orphan_subclasses;
361+
358362
public:
359363
int calls;
360364

@@ -506,6 +510,9 @@ class GDScriptLanguage : public ScriptLanguage {
506510
virtual bool handles_global_class_type(const String &p_type) const;
507511
virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const;
508512

513+
void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass);
514+
Ref<GDScript> get_orphan_subclass(const String &p_qualified_name);
515+
509516
GDScriptLanguage();
510517
~GDScriptLanguage();
511518
};

modules/gdscript/gdscript_compiler.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,15 +2123,21 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C
21232123
StringName name = p_class->subclasses[i]->name;
21242124

21252125
Ref<GDScript> subclass;
2126+
String fully_qualified_name = p_script->fully_qualified_name + "::" + name;
21262127

21272128
if (old_subclasses.has(name)) {
21282129
subclass = old_subclasses[name];
21292130
} else {
2130-
subclass.instance();
2131+
Ref<GDScript> orphan_subclass = GDScriptLanguage::get_singleton()->get_orphan_subclass(fully_qualified_name);
2132+
if (orphan_subclass.is_valid()) {
2133+
subclass = orphan_subclass;
2134+
} else {
2135+
subclass.instance();
2136+
}
21312137
}
21322138

21332139
subclass->_owner = p_script;
2134-
subclass->fully_qualified_name = p_script->fully_qualified_name + "::" + name;
2140+
subclass->fully_qualified_name = fully_qualified_name;
21352141
p_script->subclasses.insert(name, subclass);
21362142

21372143
_make_scripts(subclass.ptr(), p_class->subclasses[i], false);

0 commit comments

Comments
 (0)