Merge pull request #35102 from ChibiDenDen/reuse_orphaned_subclass
#34161: Keep a weak reference to orphan subclasses to reuse on class reload
This commit is contained in:
commit
cd7b51b943
@ -915,14 +915,43 @@ GDScript::GDScript() :
|
|||||||
#endif
|
#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() {
|
GDScript::~GDScript() {
|
||||||
for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
|
for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
|
||||||
memdelete(E->get());
|
memdelete(E->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
|
_save_orphaned_subclasses();
|
||||||
E->get()->_owner = NULL; //bye, you are no longer owned cause I died
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
if (GDScriptLanguage::get_singleton()->lock) {
|
if (GDScriptLanguage::get_singleton()->lock) {
|
||||||
@ -2176,6 +2205,22 @@ GDScriptLanguage::~GDScriptLanguage() {
|
|||||||
singleton = NULL;
|
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 ***************/
|
/*************** RESOURCE ***************/
|
||||||
|
|
||||||
RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
|
RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
|
||||||
|
@ -132,6 +132,8 @@ class GDScript : public Script {
|
|||||||
|
|
||||||
bool _update_exports();
|
bool _update_exports();
|
||||||
|
|
||||||
|
void _save_orphaned_subclasses();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||||
bool _set(const StringName &p_name, const Variant &p_value);
|
bool _set(const StringName &p_name, const Variant &p_value);
|
||||||
@ -355,6 +357,8 @@ class GDScriptLanguage : public ScriptLanguage {
|
|||||||
bool profiling;
|
bool profiling;
|
||||||
uint64_t script_frame_time;
|
uint64_t script_frame_time;
|
||||||
|
|
||||||
|
Map<String, ObjectID> orphan_subclasses;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int calls;
|
int calls;
|
||||||
|
|
||||||
@ -506,6 +510,9 @@ public:
|
|||||||
virtual bool handles_global_class_type(const String &p_type) const;
|
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;
|
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();
|
||||||
~GDScriptLanguage();
|
~GDScriptLanguage();
|
||||||
};
|
};
|
||||||
|
@ -2123,15 +2123,21 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C
|
|||||||
StringName name = p_class->subclasses[i]->name;
|
StringName name = p_class->subclasses[i]->name;
|
||||||
|
|
||||||
Ref<GDScript> subclass;
|
Ref<GDScript> subclass;
|
||||||
|
String fully_qualified_name = p_script->fully_qualified_name + "::" + name;
|
||||||
|
|
||||||
if (old_subclasses.has(name)) {
|
if (old_subclasses.has(name)) {
|
||||||
subclass = old_subclasses[name];
|
subclass = old_subclasses[name];
|
||||||
} else {
|
} 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->_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);
|
p_script->subclasses.insert(name, subclass);
|
||||||
|
|
||||||
_make_scripts(subclass.ptr(), p_class->subclasses[i], false);
|
_make_scripts(subclass.ptr(), p_class->subclasses[i], false);
|
||||||
|
Loading…
Reference in New Issue
Block a user