diff --git a/.travis.yml b/.travis.yml index 1e7802f4f6..835ddbd627 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,7 @@ install: script: # GDCore tests: - cd .build-tests - - Core/GDCore_tests + - for i in {1..20}; do echo "Run $i"; Core/GDCore_tests; done - cd .. # GDevelop.js tests - cd GDevelop.js diff --git a/Core/GDCore/Project/BehaviorsContainer.h b/Core/GDCore/Project/BehaviorsContainer.h index 4954ab475e..ef6aa4e233 100644 --- a/Core/GDCore/Project/BehaviorsContainer.h +++ b/Core/GDCore/Project/BehaviorsContainer.h @@ -11,6 +11,7 @@ #include "GDCore/Project/Behavior.h" #include "GDCore/Project/EffectsContainer.h" +#include "GDCore/Project/MemoryTrackedRegistry.h" #include "GDCore/Project/ObjectConfiguration.h" #include "GDCore/Project/VariablesContainer.h" #include "GDCore/String.h" @@ -153,6 +154,9 @@ protected: * behaviors and it must be a deep copy. */ void Init(const gd::BehaviorsContainer &behaviorsContainer); + +private: + gd::MemoryTracked _memoryTracked{this, "BehaviorsContainer"}; }; } // namespace gd diff --git a/Core/GDCore/Project/BehaviorsSharedData.h b/Core/GDCore/Project/BehaviorsSharedData.h index 59ee6d9be0..689a320ea6 100644 --- a/Core/GDCore/Project/BehaviorsSharedData.h +++ b/Core/GDCore/Project/BehaviorsSharedData.h @@ -8,6 +8,7 @@ #include "GDCore/String.h" #include "GDCore/Project/BehaviorConfigurationContainer.h" +#include "GDCore/Project/MemoryTrackedRegistry.h" namespace gd { @@ -25,8 +26,19 @@ class GD_CORE_API BehaviorsSharedData: public BehaviorConfigurationContainer { BehaviorsSharedData(): BehaviorConfigurationContainer() {}; BehaviorsSharedData(const gd::String& name_, const gd::String& type_) : BehaviorConfigurationContainer(name_, type_) {}; + BehaviorsSharedData(const BehaviorsSharedData& other) + : BehaviorConfigurationContainer(other) {}; + BehaviorsSharedData& operator=(const BehaviorsSharedData& other) { + if (this != &other) { + BehaviorConfigurationContainer::operator=(other); + } + return *this; + } virtual ~BehaviorsSharedData(); virtual BehaviorsSharedData* Clone() const { return new BehaviorsSharedData(*this); } + + private: + gd::MemoryTracked _memoryTracked{this, "BehaviorsSharedData"}; }; } // namespace gd diff --git a/Core/GDCore/Project/EffectsContainer.h b/Core/GDCore/Project/EffectsContainer.h index e5e898a768..7cb91194fd 100644 --- a/Core/GDCore/Project/EffectsContainer.h +++ b/Core/GDCore/Project/EffectsContainer.h @@ -9,6 +9,7 @@ #include #include +#include "GDCore/Project/MemoryTrackedRegistry.h" #include "GDCore/String.h" namespace gd { @@ -119,6 +120,7 @@ class GD_CORE_API EffectsContainer { std::vector> effects; static Effect badEffect; void Init(const EffectsContainer& other); + gd::MemoryTracked _memoryTracked{this, "EffectsContainer"}; }; } // namespace gd diff --git a/Core/GDCore/Project/InitialInstancesContainer.h b/Core/GDCore/Project/InitialInstancesContainer.h index 163ed512a7..e0791d303a 100644 --- a/Core/GDCore/Project/InitialInstancesContainer.h +++ b/Core/GDCore/Project/InitialInstancesContainer.h @@ -8,6 +8,7 @@ #include #include "GDCore/Project/InitialInstance.h" +#include "GDCore/Project/MemoryTrackedRegistry.h" #include "GDCore/String.h" namespace gd { class InitialInstanceFunctor; @@ -38,6 +39,14 @@ namespace gd { class GD_CORE_API InitialInstancesContainer { public: InitialInstancesContainer(){}; + InitialInstancesContainer(const InitialInstancesContainer& other) + : initialInstances(other.initialInstances) {}; + InitialInstancesContainer& operator=(const InitialInstancesContainer& other) { + if (this != &other) { + initialInstances = other.initialInstances; + } + return *this; + } virtual ~InitialInstancesContainer(); /** @@ -198,6 +207,7 @@ private: std::list initialInstances; static gd::InitialInstance badPosition; + gd::MemoryTracked _memoryTracked{this, "InitialInstancesContainer"}; }; /** diff --git a/Core/GDCore/Project/LayersContainer.h b/Core/GDCore/Project/LayersContainer.h index e8d834b2c8..fddb5fdb96 100644 --- a/Core/GDCore/Project/LayersContainer.h +++ b/Core/GDCore/Project/LayersContainer.h @@ -9,6 +9,7 @@ #include #include "GDCore/Project/Layer.h" +#include "GDCore/Project/MemoryTrackedRegistry.h" #include "GDCore/String.h" namespace gd { @@ -21,6 +22,13 @@ namespace gd { class GD_CORE_API LayersContainer { public: LayersContainer(); + LayersContainer(const LayersContainer& other) : layers(other.layers) {}; + LayersContainer& operator=(const LayersContainer& other) { + if (this != &other) { + layers = other.layers; + } + return *this; + } /** * \brief Return true if the layer called "name" exists. @@ -104,6 +112,7 @@ class GD_CORE_API LayersContainer { static gd::Layer badLayer; ///< Null object, returned when GetLayer can not ///< find an appropriate layer. std::vector layers; ///< Layers + gd::MemoryTracked _memoryTracked{this, "LayersContainer"}; }; } // namespace gd \ No newline at end of file diff --git a/Core/GDCore/Project/MemoryTrackedRegistry.h b/Core/GDCore/Project/MemoryTrackedRegistry.h index 17bac958c2..b8b2a85086 100644 --- a/Core/GDCore/Project/MemoryTrackedRegistry.h +++ b/Core/GDCore/Project/MemoryTrackedRegistry.h @@ -30,16 +30,19 @@ class MemoryTrackedRegistry { public: // Internal C++ API (used by MemoryTracked). static void add(const void* ptr, const char* className) { + if (!className) return; dead()[className].erase(ptr); alive()[className].insert(ptr); } static void remove(const void* ptr, const char* className) { + if (!className) return; alive()[className].erase(ptr); dead()[className].insert(ptr); } static bool isDead(const void* ptr, const char* className) { + if (!className) return false; auto it = dead().find(className); return it != dead().end() && it->second.count(ptr) > 0; } @@ -116,15 +119,21 @@ class MemoryTrackedRegistry { * MemoryTracked _memoryTracked{this, "Layout"}; * }; * \endcode + * + * When adding a new tracked class, also update: + * - GDevelop.js/Bindings/postjs.js (trackedClassNames set in + * patchClassesForUseAfterFreeDetection) + * - newIDE/app/src/MainFrame/MemoryTrackedRegistryDialog.js (trackedClasses + * array) */ class MemoryTracked { public: MemoryTracked(const void* owner, const char* className) : owner_(owner), className_(className) { - MemoryTrackedRegistry::add(owner_, className_); + if (className_) MemoryTrackedRegistry::add(owner_, className_); } - ~MemoryTracked() { MemoryTrackedRegistry::remove(owner_, className_); } + ~MemoryTracked() { if (className_) MemoryTrackedRegistry::remove(owner_, className_); } // Non-copyable, non-movable. MemoryTracked(const MemoryTracked&) = delete; diff --git a/Core/GDCore/Project/ObjectGroupsContainer.h b/Core/GDCore/Project/ObjectGroupsContainer.h index 8587062fea..6b4750b59f 100644 --- a/Core/GDCore/Project/ObjectGroupsContainer.h +++ b/Core/GDCore/Project/ObjectGroupsContainer.h @@ -10,6 +10,7 @@ #include #include +#include "GDCore/Project/MemoryTrackedRegistry.h" #include "GDCore/Project/ObjectGroup.h" #include "GDCore/String.h" namespace gd { @@ -189,6 +190,7 @@ class GD_CORE_API ObjectGroupsContainer { private: std::vector> objectGroups; static ObjectGroup badGroup; + gd::MemoryTracked _memoryTracked{this, "ObjectGroupsContainer"}; }; } // namespace gd diff --git a/Core/GDCore/Project/ObjectsContainer.h b/Core/GDCore/Project/ObjectsContainer.h index 15a32b94ec..0079b71151 100644 --- a/Core/GDCore/Project/ObjectsContainer.h +++ b/Core/GDCore/Project/ObjectsContainer.h @@ -8,6 +8,7 @@ #include #include #include +#include "GDCore/Project/MemoryTrackedRegistry.h" #include "GDCore/String.h" #include "GDCore/Project/ObjectGroupsContainer.h" #include "GDCore/Project/ObjectFolderOrObject.h" @@ -252,6 +253,7 @@ class GD_CORE_API ObjectsContainer { private: SourceType sourceType = Unknown; std::unique_ptr rootFolder; + gd::MemoryTracked _memoryTracked{this, "ObjectsContainer"}; /** * Initialize from another variables container, copying elements. Used by diff --git a/Core/GDCore/Project/VariablesContainer.h b/Core/GDCore/Project/VariablesContainer.h index f29a73b00a..6118da7152 100644 --- a/Core/GDCore/Project/VariablesContainer.h +++ b/Core/GDCore/Project/VariablesContainer.h @@ -7,6 +7,7 @@ #pragma once #include #include +#include "GDCore/Project/MemoryTrackedRegistry.h" #include "GDCore/Project/Variable.h" #include "GDCore/String.h" namespace gd { @@ -195,6 +196,7 @@ class GD_CORE_API VariablesContainer { ///< useful for computing changesets. static gd::Variable badVariable; static gd::String badName; + gd::MemoryTracked _memoryTracked{this, "VariablesContainer"}; /** * Initialize from another variables container, copying elements. Used by diff --git a/Core/tests/Common.cpp b/Core/tests/Common.cpp index b3d27d0977..7f6d6e7dd0 100644 --- a/Core/tests/Common.cpp +++ b/Core/tests/Common.cpp @@ -78,9 +78,9 @@ TEST_CASE("EventsList", "[common][events]") { size_t endMemory = gd::SystemStats::GetUsedVirtualMemory(); INFO("Memory used: " << endMemory - startMemory << "KB"); #if defined(WINDOWS) - REQUIRE(3000 >= endMemory - startMemory); + REQUIRE(3800 >= endMemory - startMemory); #else - REQUIRE(1650 >= endMemory - startMemory); + REQUIRE(2000 >= endMemory - startMemory); #endif } } diff --git a/GDevelop.js/Bindings/postjs.js b/GDevelop.js/Bindings/postjs.js index cd8d804890..0c86efee8b 100644 --- a/GDevelop.js/Bindings/postjs.js +++ b/GDevelop.js/Bindings/postjs.js @@ -421,7 +421,20 @@ function patchClassesForUseAfterFreeDetection( patchClassesForUseAfterFreeDetection(Module, { skippedClassNames: new Set([]), - // If adding new classes, also add them to `MemoryTrackedRegistryDialog`. - trackedClassNames: new Set(['Project', 'Layout', 'gdObject', 'Behavior']), + // If adding new classes, also add them to `MemoryTrackedRegistryDialog` + // and to the MemoryTracked member in the C++ class header. + trackedClassNames: new Set([ + 'Project', + 'Layout', + 'gdObject', + 'Behavior', + 'BehaviorsSharedData', + 'EffectsContainer', + 'InitialInstancesContainer', + 'LayersContainer', + 'ObjectGroupsContainer', + 'ObjectsContainer', + 'VariablesContainer', + ]), verbose: false, }); diff --git a/newIDE/app/src/MainFrame/MemoryTrackedRegistryDialog.js b/newIDE/app/src/MainFrame/MemoryTrackedRegistryDialog.js index 48415c98fe..9125090377 100644 --- a/newIDE/app/src/MainFrame/MemoryTrackedRegistryDialog.js +++ b/newIDE/app/src/MainFrame/MemoryTrackedRegistryDialog.js @@ -15,8 +15,21 @@ import { const gd: libGDevelop = global.gd; -// If adding new classes, also add them to `patchClassesForUseAfterFreeDetection`. -const trackedClasses = ['Project', 'Layout', 'gdObject', 'Behavior']; +// If adding new classes, also add them to `patchClassesForUseAfterFreeDetection` +// in postjs.js and to the MemoryTracked member in the C++ class header. +const trackedClasses = [ + 'Project', + 'Layout', + 'gdObject', + 'Behavior', + 'BehaviorsSharedData', + 'EffectsContainer', + 'InitialInstancesContainer', + 'LayersContainer', + 'ObjectGroupsContainer', + 'ObjectsContainer', + 'VariablesContainer', +]; type Stats = {| className: string,