From aad7ec8e8f7f9bf1c8214a8f56a8bf46add223de Mon Sep 17 00:00:00 2001 From: Jacqueline Deans Date: Fri, 21 Jul 2023 19:34:14 -0500 Subject: [PATCH] Clean up memory manager (#26) --- .../include/MemoryManagement/AllocInfo.hpp | 14 +- .../MemoryManagement/MemoryManager.hpp | 197 ++++++---- DataTypes/src/MemoryManagement/AllocInfo.cpp | 45 +-- .../src/MemoryManagement/MemoryManager.cpp | 278 ++++--------- DataTypes/test/CMakeLists.txt | 1 + DataTypes/test/MemoryManagerTest.cpp | 365 ++++++++++++++++++ 6 files changed, 574 insertions(+), 326 deletions(-) create mode 100644 DataTypes/test/MemoryManagerTest.cpp diff --git a/DataTypes/include/MemoryManagement/AllocInfo.hpp b/DataTypes/include/MemoryManagement/AllocInfo.hpp index 6a6570b..5098992 100644 --- a/DataTypes/include/MemoryManagement/AllocInfo.hpp +++ b/DataTypes/include/MemoryManagement/AllocInfo.hpp @@ -34,10 +34,14 @@ class AllocInfo { public: AllocInfo( const std::string& varName, const DataType * type, - void* suppliedAllocation = 0) ; + void* suppliedAllocation = 0) ; + + // Delete the copy constructor. + AllocInfo(const AllocInfo& other) = delete; /** AllocInfo destructor. + @note This also deletes the underlying allocation if it was allocated locally. */ ~AllocInfo(); @@ -84,29 +88,27 @@ class AllocInfo { /** @return the DataType for the allocation. - Tested in: AllocInfoTest::getters1, AllocInfoTest::getters2. */ const DataType * getDataType() const; /** - @return the size of the nth dimension. - Tested in: AllocInfoTest::getters1, AllocInfoTest::getters2. + @return Get */ StorageClass::e getStorageClass() const; /** - Clear the every element of the allocation to 0. + @brief Clear the every element of the allocation to 0. Tested in: AllocInfoTest::clear. */ void clear() const; + /** */ // void* resize( size_t newElementCount ); /** @return true, if the allocation contains the given address. Otherwise return false. - Tested in: FIXME */ bool contains(void* address) const; diff --git a/DataTypes/include/MemoryManagement/MemoryManager.hpp b/DataTypes/include/MemoryManagement/MemoryManager.hpp index 444bcad..f20568a 100644 --- a/DataTypes/include/MemoryManagement/MemoryManager.hpp +++ b/DataTypes/include/MemoryManagement/MemoryManager.hpp @@ -11,110 +11,163 @@ #include "CheckpointAgent/NewCheckpointAgentBase.hpp" - +/** + * @brief Keep track of allocations and their type. + * + */ class MemoryManager { public: - MemoryManager(); - MemoryManager (DataTypeInator * dictionary); - - void* declare_var( const std::string& typeSpecName, const std::string& varName, unsigned int DimensionsCount, int *Dimensions, void* suppliedAllocation = 0); - void* declare_var( const std::string& declaration, void* suppliedAllocation = 0); - void* declare_var( const std::string& typeSpecName, int n, void* suppliedAllocation = 0); - void* declare_var( const std::string& typeSpecName, const std::string& varName, int n, void* suppliedAllocation = 0); - -// void* declare_extern_var( void* address, const char * declaration); -// void* declare_extern_var( void* address, const char *element_definition, int n_elems); -// void* declare_extern_var( void* address, TRICK_TYPE type, std::string class_name, int n_stars, std::string var_name, int n_cdims, int *cdims); + /** + * @brief Construct a new Memory Manager + * + * @param dataTypeInator type resolver machine + */ + MemoryManager (DataTypeInator * dataTypeInator); - void* resize_var( void* address, size_t newElementCount); - void* resize_var( const std::string& name, size_t newElementCount); - -// char* mm_strdup( const char* s); + ~MemoryManager (); + // no copying + MemoryManager(const MemoryManager& other) = delete; + + /** + * @brief Declare a new allocation of given type with the memory manager + * + * @param declaration string representation of the type of this allocation + * @param suppliedAllocation pre-existing allocation. If not given, the memory manager will allocate one + * @return void* address of the allocation (same as suppliedAllocation if one was given). NULL if something goes wrong + */ + void* declare_var( const std::string& declaration, void* suppliedAllocation = NULL); + + + + /** + * @brief Check if a variable is registered with the memory manager + * + * @param var_name variable to look for + * @return true if var exists, false otherwise + */ bool var_exists( const std::string& var_name); -// size_t sizeof_type( const char* declaration); -// int is_alloced( void* address); -// void set_debug_level( int level); -// void set_reduced_checkpoint(bool flag); -// void set_hexfloat_checkpoint(bool flag); + + /** + * @brief Clear the value at the given address, if it is registered with the memorymanager + * + * @param address address of variable to clear + */ void clear_var( void* address); - void clear_var( const std::string& var_name); - void clear_all_vars(); -// int delete_var(void* address, bool destroy = true); -// int delete_var(const char* var_name); -// int delete_extern_var(void* address); -// int delete_extern_var(const char* var_name); + /** + * @brief Clear the variable with the given name, if it is registered with the memorymanager + * + * @param var_name name of variable to clear + */ + void clear_var( const std::string& var_name); -// void write_var( std::ostream& out_s, const char* var_name ); -// void write_var( std::ostream& out_s, void* address ); + /** + * @brief Clear all variables registered with the memory manager. + * + */ + void clear_all_vars(); - // Various entry points + /** + * @brief Delete the variable + * + * @param address address of variable to delete + */ + void delete_var(void* address); + + /** + * @brief Delete the variable + * + * @param var_name name of variable to delete + */ + void delete_var(std::string var_name); + + /** + * @brief Write checkpoint to an output stream + * + * @param out_s stream to write to + */ void write_checkpoint( std::ostream& out_s); - void write_checkpoint( const std::string& filename); - void write_checkpoint( std::ostream& out_s, const std::string& variableName ); - void write_checkpoint( const std::string& filename, const std::string& variableName); - void write_checkpoint( std::ostream& out_s, std::vector& variableNameList); - void write_checkpoint( const std::string& filename, std::vector& variableNameList); - - // The actual checkpoint - void write_checkpoint(std::ostream& outStream, std::vector& dependencies); + /** + * @brief Open a file and then write a checkpoint to it + * + * @param filename name of file to write to + */ + void write_checkpoint( const std::string& filename); - // Various entry points + /** + * @brief Restore a checkpoint from file with given name + * + * @param filename name of file to read from + */ void restore_checkpoint(const std::string& filename); - // The actual checkpoint + + /** + * @brief Restore a checkpoint from the given input stream + * + * @param in_s stream to restore from + */ void restore_checkpoint( std::istream& in_s); -// int init_from_checkpoint( const char* filename); - -// void reset_memory(); - -// int add_attr_info(std::string& type_name , ATTRIBUTES* attr , const char * file_name = "None" , unsigned int line_num = 0 ) ; -// int add_template_name_trans(std::string template_name , std::string attr_name) ; -// void* add_var( TRICK_TYPE type, const char* class_name, VAR_DECLARE* var_declare, char* units); -// int add_vars( TRICK_TYPE type, const char* class_name, VAR_LIST* var_list, char* units); -// int ref_allocate( REF2* R, int num ) ; -// REF2 *ref_attributes( const char* name); -// int ref_assignment( REF2* R, V_TREE* V); -// int ref_var( REF2* R, char* name); -// int ref_dim( REF2* R, V_DATA* V); -// int ref_name(REF2 * R, char *name); -// int get_enumerated(const char* name, V_DATA* v_data); (see Type/EnumDictionary.hpp) -// int get_size(char *ptr); -// int get_truncated_size(char *ptr); -// int io_get_fixed_truncated_size(char *ptr, ATTRIBUTES * A, char *str, int dims, ATTRIBUTES * left_type); + /** + * @brief Get the AllocInfo that contains the given address + * + * @param address address to search for + * @return AllocInfo* Alloc info that contains this address, or NULL if not found + */ AllocInfo* getAllocInfoOf( void* address ); + + /** + * @brief Get the AllocInfo that starts at the given address + * + * @param address address to search for + * @return AllocInfo* Alloc info that starts at this address, or NULL if not found + */ AllocInfo* getAllocInfoAt( void* address ); + + /** + * @brief Get the AllocInfo with the given name + * + * @param name name to search for + * @return AllocInfo* AllocInfo with the given name, or NULL if not found + */ AllocInfo* getAllocInfoNamed( const std::string& name ); - const DataType* getDataType(std::string typeName); -// int add_shared_library_symbols( const char * file_name ); - CheckpointAgentBase * get_CheckPointAgent(); - void set_CheckPointAgent( CheckpointAgentBase* agent); -// void reset_CheckPointAgent(); -// void write_class( std::ostream& out_s, char *address, ATTRIBUTES * A); -// void write_arrayed_class( std::ostream& out_s, char* address, ATTRIBUTES* A, int curr_dim, int offset); -// size_t io_src_sizeof_user_type(const char* user_type_name); + + /** + * @brief Get the DataType of the given variable + * + * @param name variable name to search for + * @return const DataType* type of variable, or NULL if not found + */ + const DataType* getDataTypeOf(const std::string& name); + + /** + * @brief Set the CheckPointAgent + * + * @param agent new CheckpointAgent object to use + */ + void setCheckPointAgent( CheckpointAgentBase* agent); private: + + void do_write_checkpoint(std::ostream& outStream, std::vector& dependencies); void* do_declare_var(const std::string& abstract_declarator, const std::string& variable_name, void * supplied_allocation); + void delete_allocation(AllocInfo * allocInfo); + unsigned int debugLevel; - // CheckpointAgent* currentCheckPointAgent; - // ClassicChkPtAgent* defaultCheckPointAgent; CheckpointAgentBase * checkpointAgent; - // bool reducedCheckpoint; - // bool hexfloatCheckpoint; - // bool compactArraysCheckpoint; - DataTypeInator* dataTypeInator; + // TODO: Let's think about this. + // I would like to switch to c++ threading instead using pthreads directly pthread_mutex_t allocInfoMapMutex; std::map allocInfoByAddressMap; diff --git a/DataTypes/src/MemoryManagement/AllocInfo.cpp b/DataTypes/src/MemoryManagement/AllocInfo.cpp index de2cbfa..e04e605 100644 --- a/DataTypes/src/MemoryManagement/AllocInfo.cpp +++ b/DataTypes/src/MemoryManagement/AllocInfo.cpp @@ -46,10 +46,11 @@ AllocInfo::AllocInfo( const std::string& varName, initialize(varName, type, suppliedAllocation); } - -// DESTRUCTOR AllocInfo::~AllocInfo() { - // FIXME: what about the allocation? + // Only destroy the underlying allocation if it is was allocated by us. + if (storageClass == StorageClass::LOCAL) { + dataType->deleteInstance(start); + } } // PUBLIC MEMBER FUNCTION @@ -103,43 +104,7 @@ void AllocInfo::clear() const { DataTypeAlgorithm::clearValue(dataType, start); } -// // PUBLIC MEMBER FUNCTION -// void* AllocInfo::resize( size_t newElementCount ) { - -// // We should not attempt to resize memory objects that were supplied -// // to us. We should only attempt to resize objects that we created. -// if ( storageClass != StorageClass::LOCAL ) { -// // ERROR CONDITION -// return NULL; -// } -// ArrayDataType* oldType = ownDataType; -// void * oldMemoryObject = start; -// size_t oldByteCount = oldType->getSize(); - -// ArrayDataType* newType = new ArrayDataType( *oldType, newElementCount ); -// void * newMemoryObject = newType->createInstance(1); -// size_t newByteCount = newType->getSize(); - -// size_t minByteCount; -// if ( oldByteCount < newByteCount ) { -// minByteCount = oldByteCount; -// } else { -// minByteCount = newByteCount; -// } - -// if (minByteCount > 0) { -// memcpy( newMemoryObject, oldMemoryObject, minByteCount); -// } - -// delete oldType; -// oldType->deleteInstance( oldMemoryObject ); -// start = newMemoryObject; -// end = (char*)start + newType->getSize(); -// ownDataType = newType; -// dataType = newType; -// dimensions[0] = newElementCount; -// return start; -// } + // PUBLIC MEMBER FUNCTION bool AllocInfo::contains(void* address) const { diff --git a/DataTypes/src/MemoryManagement/MemoryManager.cpp b/DataTypes/src/MemoryManagement/MemoryManager.cpp index 2a0ed1d..456a253 100644 --- a/DataTypes/src/MemoryManagement/MemoryManager.cpp +++ b/DataTypes/src/MemoryManagement/MemoryManager.cpp @@ -13,69 +13,53 @@ // Constructor -MemoryManager::MemoryManager() : MemoryManager(new DataTypeInator()) {} - MemoryManager::MemoryManager (DataTypeInator * dictionary) : dataTypeInator(dictionary) { debugLevel = 0; checkpointAgent = new J_CheckpointAgent(dataTypeInator); + pthread_mutex_init(&allocInfoMapMutex, NULL); +} + +MemoryManager::~MemoryManager () { + delete checkpointAgent; + + // Delete all the AllocInfos + for (auto it : allocInfoByAddressMap) { + delete it.second; + } + + // Both maps have the same thing, just indexed in different ways, so we only need to delete out of one of them. } void* MemoryManager::do_declare_var(const std::string& abstract_declarator, const std::string& variable_name, void * supplied_allocation) { + // Don't redeclare if ( var_exists( variable_name )) { std::cerr << "ERROR: Variable " << variable_name << " already declared." << std::endl; return ((void*)NULL); } - AllocInfo* newAllocInfo; - void* actualAllocation; - try { - // FIXME: MUTEX LOCK to protect AllocInfo static variables - const DataType * type = dataTypeInator->resolve(abstract_declarator); - if (type == NULL) { - std::cerr << "ERROR: Unable to resolve type string \"" << abstract_declarator << "\" for variable \"" << variable_name << "\", cannot declare." << std::endl; - return ((void*)NULL); - } + // Look up the type + const DataType * type = dataTypeInator->resolve(abstract_declarator); + if (type == NULL) { + std::cerr << "ERROR: Unable to resolve type string \"" << abstract_declarator << "\" for variable \"" << variable_name << "\", cannot declare." << std::endl; + return ((void*)NULL); + } - newAllocInfo = new AllocInfo(variable_name, type, supplied_allocation); + // Make the AllocInfo + AllocInfo* newAllocInfo = new AllocInfo(variable_name, type, supplied_allocation); - // Set the address and insert in the maps - actualAllocation = newAllocInfo->getStart(); + // Set the address and insert in the maps + void * actualAllocation = newAllocInfo->getStart(); - allocInfoByAddressMap[actualAllocation] = newAllocInfo; - allocInfoByNameMap[variable_name] = newAllocInfo; + allocInfoByAddressMap[actualAllocation] = newAllocInfo; + allocInfoByNameMap[variable_name] = newAllocInfo; - } catch ( std::logic_error& e ) { - // FIXME: MUTEX UNLOCK - std::cerr << e.what(); - newAllocInfo = (AllocInfo*)NULL; - actualAllocation = (void*)NULL; - } - if ( debugLevel ) { - if ( newAllocInfo == (AllocInfo*)NULL ) { - std::cout << "Allocation Failed." << std::endl; - } else { - std::cout << newAllocInfo->toString() << std::endl; - } - } return( actualAllocation ); } -// MEMBER FUNCTION -void* MemoryManager::declare_var( const std::string& typeSpecifier, - const std::string& variableName, - unsigned int dimensionsCount, - int* dimensions, - void* suppliedAllocation ) { - - std::vector dims(dimensions, dimensions + dimensionsCount); - MutableDeclaration decl (typeSpecifier, dims); - return do_declare_var(decl.getAbstractDeclarator(), variableName, suppliedAllocation); -} - // MEMBER FUNCTION void* MemoryManager::declare_var( const std::string& declaration, void* suppliedAllocation ) { @@ -87,64 +71,6 @@ void* MemoryManager::declare_var( const std::string& declaration, return do_declare_var( abstractDeclarator, variableName, suppliedAllocation ); } -// MEMBER FUNCTION -void* MemoryManager::declare_var( const std::string& typeSpecName, - const std::string& variableName, - int n, - void* suppliedAllocation) { - - MutableDeclaration decl = MutableDeclaration( typeSpecName); - decl.pushDimension(n); - - std::string abstractDeclarator = decl.getAbstractDeclarator(); - - return do_declare_var( abstractDeclarator, variableName, suppliedAllocation ); -} - -// MEMBER FUNCTION -void* MemoryManager::declare_var( const std::string& typeSpecName, - int n, - void* suppliedAllocation ) { - - MutableDeclaration decl = MutableDeclaration( typeSpecName); - decl.pushDimension(n); - - std::string abstractDeclarator = decl.getAbstractDeclarator(); - std::string variableName = decl.getVariableName(); - - return do_declare_var( abstractDeclarator, variableName, suppliedAllocation ); -} - -// // MEMBER FUNCTION -// void* MemoryManager::resize_var( void* address, size_t newElementCount) { -// void* newAddress; -// AllocInfo* allocInfo = getAllocInfoOf(address); -// if (allocInfo != NULL) { -// newAddress = allocInfo->resize( newElementCount ); -// } else { -// std::cerr << __FUNCTION__ << " failed. Address (" << address << ") not in Trick managed memory." << std::endl; -// newAddress = NULL; -// } -// return newAddress; -// } - -// // MEMBER FUNCTION -// void* MemoryManager::resize_var( const std::string& name, size_t newElementCount) { -// void* newAddress; -// AllocInfo* allocInfo = getAllocInfoNamed(name); -// if (allocInfo != NULL) { -// newAddress = allocInfo->resize( newElementCount ); -// } else { -// std::cerr << __FUNCTION__ << " failed. Name \"" << name << "\" not in Trick managed memory." << std::endl; -// newAddress = NULL; -// } -// return newAddress; -// } - -// MEMBER FUNCTION -// void* resize_var( const char* name, int num); - - // MEMBER FUNCTION bool MemoryManager::var_exists( const std::string& variableName) { @@ -164,84 +90,65 @@ void MemoryManager::clear_var( void* address) { if ((allocInfo = getAllocInfoOf( address)) != NULL) { allocInfo->clear(); } else { - std::stringstream ss; - ss << "Cannot clear the variable at address "; - ss << address; - ss << " because memory manager knows nothing about it."; - ss << std::endl; - std::cerr << ss.str(); + std::cerr << "Cannot clear the variable at address " << address << " because memory manager knows nothing about it." << std::endl; } } // MEMBER FUNCTION void MemoryManager::clear_var( const std::string& variableName) { - AllocInfo* allocInfo; - if ((allocInfo = getAllocInfoNamed( variableName )) != NULL) { + AllocInfo* allocInfo = getAllocInfoNamed( variableName ); + if (allocInfo != NULL) { allocInfo->clear(); } else { - std::stringstream ss; - ss << "Cannot clear the variable named "; - ss << variableName; - ss << " because memory manager knows nothing about it."; - ss << std::endl; - std::cerr << ss.str(); + std::cerr << "Cannot clear the variable named " << variableName << " because memory manager knows nothing about it." << std::endl; } } // MEMBER FUNCTION void MemoryManager::clear_all_vars() { + for (auto it : allocInfoByAddressMap) { + it.second->clear(); + } } -// MEMBER FUNCTION -void MemoryManager::write_checkpoint( std::ostream& out_s) { +void MemoryManager::delete_var(void* address) { + AllocInfo* allocInfo = getAllocInfoAt( address); - AllocInfo* allocInfo; - std::vector allocInfoList; - std::map::iterator pos; - - pthread_mutex_lock(&allocInfoMapMutex); - - for ( pos = allocInfoByAddressMap.begin() ; pos != allocInfoByAddressMap.end() ; pos++ ) { - allocInfo = pos->second; - allocInfoList.push_back(allocInfo); + if (allocInfo != NULL) { + delete_allocation(allocInfo); + } else { + std::cerr << "Cannot delete the variable at address " << address << " because memory manager knows nothing about it." << std::endl; } - write_checkpoint( out_s, allocInfoList); - - pthread_mutex_unlock(&allocInfoMapMutex); } -// MEMBER FUNCTION -void MemoryManager::write_checkpoint( const std::string& filename) { +void MemoryManager::delete_var(std::string var_name) { + AllocInfo* allocInfo = getAllocInfoNamed( var_name); - std::ofstream out_s( filename.c_str(), std::ios::out); - if (out_s.is_open()) { - write_checkpoint( out_s ); + if (allocInfo != NULL) { + delete_allocation(allocInfo); } else { - std::cerr << "ERROR: Couldn't open \""<< filename <<"\"." << std::endl; - std::cerr.flush(); + std::cerr << "Cannot delete the variable named " << var_name << " because memory manager knows nothing about it." << std::endl; } } -// MEMBER FUNCTION -void MemoryManager::write_checkpoint( std::ostream& out_s, const std::string& variableName) { - - std::vector dependencies; +void MemoryManager::delete_allocation(AllocInfo * allocInfo) { pthread_mutex_lock(&allocInfoMapMutex); - AllocInfo * allocInfo = getAllocInfoNamed( variableName ); - // if ( allocInfo != NULL ) { - // allocInfo->appendDependencies( this, dependencies ); - // } + allocInfoByAddressMap.erase(allocInfo->getStart()); + allocInfoByNameMap.erase(allocInfo->getName()); pthread_mutex_unlock(&allocInfoMapMutex); - write_checkpoint( out_s, dependencies); + + // This will properly handle the extern vs local deletion + delete allocInfo; } + // MEMBER FUNCTION -void MemoryManager::write_checkpoint(const std::string& filename, const std::string& variableName) { +void MemoryManager::write_checkpoint( const std::string& filename) { std::ofstream out_s( filename.c_str(), std::ios::out); if (out_s.is_open()) { - write_checkpoint( out_s, variableName); + write_checkpoint( out_s ); } else { std::cerr << "ERROR: Couldn't open \""<< filename <<"\"." << std::endl; std::cerr.flush(); @@ -249,56 +156,25 @@ void MemoryManager::write_checkpoint(const std::string& filename, const std::str } // MEMBER FUNCTION -void MemoryManager::write_checkpoint( std::ostream& out_s, std::vector& variableNameList) { - - std::vector dependencies; - const char* variableName; - int nameCount; - nameCount = variableNameList.size(); - for (int ii=0; ii< nameCount; ii++) { - variableName = variableNameList[ii]; - pthread_mutex_lock(&allocInfoMapMutex); - // AllocInfo* allocInfo = getAllocInfoNamed( variableName ); - // if ( allocInfo != NULL ) { - // allocInfo->appendDependencies( this, dependencies ); - // } - pthread_mutex_unlock(&allocInfoMapMutex); - } - write_checkpoint( out_s, dependencies); -} +void MemoryManager::write_checkpoint( std::ostream& out_s) { -// MEMBER FUNCTION -void MemoryManager::write_checkpoint(const std::string& filename, std::vector& variableNameList) { + AllocInfo* allocInfo; + std::vector allocInfoList; - std::ofstream out_s( filename.c_str(), std::ios::out); - if (out_s.is_open()) { - write_checkpoint( out_s, variableNameList ); - } else { - std::cerr << "ERROR: Couldn't open \""<< filename <<"\"." << std::endl; - std::cerr.flush(); - } -} + pthread_mutex_lock(&allocInfoMapMutex); -// STATIC FUNCTION -static bool allocInfoCompare( AllocInfo* lhs, AllocInfo* rhs ) { - bool result; - StorageClass::e lhsStorageClass = lhs->getStorageClass(); - StorageClass::e rhsStorageClass = rhs->getStorageClass(); - unsigned int lhsSerialNumber = lhs->getSerialNumber(); - unsigned int rhsSerialNumber = rhs->getSerialNumber(); - - if ( lhsStorageClass == rhsStorageClass ) { - result = ( lhsSerialNumber < rhsSerialNumber ); - } else if ( lhsStorageClass == StorageClass:: EXTERN ) { - result = true; - } else { - result = false; + for ( auto pos = allocInfoByAddressMap.begin() ; pos != allocInfoByAddressMap.end() ; pos++ ) { + allocInfo = pos->second; + allocInfoList.push_back(allocInfo); } - return result; + do_write_checkpoint( out_s, allocInfoList); + + pthread_mutex_unlock(&allocInfoMapMutex); } + // PRIVATE MEMBER FUNCTION -void MemoryManager::write_checkpoint(std::ostream& outStream, std::vector& allocInfoList) { +void MemoryManager::do_write_checkpoint(std::ostream& outStream, std::vector& allocInfoList) { checkpointAgent->dump(outStream, allocInfoList); } @@ -346,11 +222,8 @@ void MemoryManager::restore_checkpoint( std::istream& in_s) { // We did it! } -CheckpointAgentBase * MemoryManager::get_CheckPointAgent() { - return checkpointAgent; -} -void MemoryManager::set_CheckPointAgent( CheckpointAgentBase* agent) { +void MemoryManager::setCheckPointAgent( CheckpointAgentBase* agent) { delete checkpointAgent; checkpointAgent = agent; } @@ -392,22 +265,11 @@ AllocInfo* MemoryManager::getAllocInfoNamed( const std::string& name ) { // MEMBER FUNCTION -const DataType* MemoryManager::getDataType( std::string typeName ) { - return dataTypeInator->resolve(typeName); -} - -#if NEWSTUFF -void * MemoryManager::getVarAccessInfo( const std::string& variableName, VarAccessInfo& varAccessInfo ) { - - std::string varName = variableName; - // Get identifier at beginnning of the string and the remiander. - // Find the AllocInfoByName ( identifier ); - - AllocInfo* allocInfo = getAllocInfoNamed (variableName); - if (allocInfo != NULL) { +const DataType* MemoryManager::getDataTypeOf( const std::string& varname ) { + AllocInfo * allocInfo = getAllocInfoNamed(varname); + if (allocInfo == NULL) { + return NULL; } - returnAddress = alloc->getVarAccessInfo( varName, varAccessInfo ); - return returnAddress; + return allocInfo->getDataType(); } -#endif diff --git a/DataTypes/test/CMakeLists.txt b/DataTypes/test/CMakeLists.txt index 561b711..4ef6280 100644 --- a/DataTypes/test/CMakeLists.txt +++ b/DataTypes/test/CMakeLists.txt @@ -26,6 +26,7 @@ add_datatype_test(J_CheckpointAgentTest DataTypeTestSupport.cpp) add_datatype_test(LexicalAnalyzerTest) add_datatype_test(LookupAddressAndTypeByNameTest DataTypeTestSupport.cpp) add_datatype_test(LookupNameByAddressAndTypeTest DataTypeTestSupport.cpp) +add_datatype_test(MemoryManagerTest) add_datatype_test(MutableDeclarationTest) add_datatype_test(MutableVariableNameTest) add_datatype_test(ParsedAssignmentTest) diff --git a/DataTypes/test/MemoryManagerTest.cpp b/DataTypes/test/MemoryManagerTest.cpp new file mode 100644 index 0000000..b7e5ebc --- /dev/null +++ b/DataTypes/test/MemoryManagerTest.cpp @@ -0,0 +1,365 @@ +#include +#include + +#include "Type/CompositeDataType.hpp" + +// Class Under Test +#include "MemoryManagement/MemoryManager.hpp" + +// Framework +class MemoryManagerTest : public ::testing::Test { + protected: + DataTypeInator dataTypeInator; + MemoryManager memoryManager; + + MemoryManagerTest() : memoryManager(&dataTypeInator) { } + ~MemoryManagerTest() { } + void SetUp() {} + void TearDown() {} +}; + +TEST_F(MemoryManagerTest, declare_var_local) { + // ARRANGE + + // ACT + int * my_val = (int *) memoryManager.declare_var("int x"); + + // ASSERT + ASSERT_TRUE(my_val != NULL); + + +} + +TEST_F(MemoryManagerTest, var_exists) { + // ARRANGE + int * my_val = (int *) memoryManager.declare_var("int x"); + + // ACT + bool result = memoryManager.var_exists("x"); + + // ASSERT + ASSERT_EQ(true, result); +} + +TEST_F(MemoryManagerTest, var_does_not_exist) { + // ARRANGE + int * my_val = (int *) memoryManager.declare_var("int x"); + + // ACT + bool result = memoryManager.var_exists("no_such_var"); + + // ASSERT + ASSERT_EQ(false, result); +} + +TEST_F(MemoryManagerTest, redeclare_existing_var_fails) { + // ARRANGE + int * my_val = (int *) memoryManager.declare_var("int x"); + + // ACT + int * same_val = (int *) memoryManager.declare_var("int x"); + + // ASSERT + ASSERT_EQ(NULL, same_val); +} + +TEST_F(MemoryManagerTest, non_existent_type) { + // ARRANGE + + // ACT + int * val = (int *) memoryManager.declare_var("no_such_type x"); + + // ASSERT + ASSERT_EQ(NULL, val); +} + +TEST_F(MemoryManagerTest, getDataTypeOf) { + // ARRANGE + int * val = (int *) memoryManager.declare_var("int *x[5]"); + + // ACT + const DataType * type = memoryManager.getDataTypeOf("x"); + + // ASSERT + std::string expected_typename = "int*[5]"; + ASSERT_EQ(expected_typename, type->toString()); +} + +TEST_F(MemoryManagerTest, getAllocInfoAt) { + // ARRANGE + int * val = (int *) memoryManager.declare_var("int *x[5]"); + + // ACT + AllocInfo * alloc = memoryManager.getAllocInfoAt(val); + + // ASSERT + ASSERT_TRUE(alloc != NULL); + ASSERT_EQ(std::string("x"), alloc->getName()); +} + +TEST_F(MemoryManagerTest, getAllocInfoAt_not_found) { + // ARRANGE + int * val = (int *) memoryManager.declare_var("int *x[5]"); + + // ACT + AllocInfo * alloc = memoryManager.getAllocInfoAt((void *) 0xdeadbeef); + + // ASSERT + ASSERT_TRUE(alloc == NULL); +} + +TEST_F(MemoryManagerTest, getAllocInfoOf) { + // ARRANGE + int * val = (int *) memoryManager.declare_var("int x[5]"); + + // ACT + AllocInfo * alloc = memoryManager.getAllocInfoOf(&val[1]); + + // ASSERT + ASSERT_TRUE(alloc != NULL); + ASSERT_EQ(std::string("x"), alloc->getName()); +} + +TEST_F(MemoryManagerTest, getAllocInfoOf_not_found) { + // ARRANGE + int * val = (int *) memoryManager.declare_var("int x[5]"); + + // ACT + AllocInfo * alloc = memoryManager.getAllocInfoOf((void *) 0xdeadbeef); + + // ASSERT + ASSERT_TRUE(alloc == NULL); +} + +TEST_F(MemoryManagerTest, clear_value) { + // ARRANGE + int val[5]; + for (int i = 0; i < 5; i++) { + val[i] = i+5; + } + memoryManager.declare_var("int val[5]", &val); + + // ACT + memoryManager.clear_var(&val); + + // ASSERT + for (int i = 0; i < 5; i++) { + ASSERT_EQ(0, val[i]); + } +} + +TEST_F(MemoryManagerTest, clear_value_not_found) { + // ARRANGE + int val[5]; + for (int i = 0; i < 5; i++) { + val[i] = i+5; + } + memoryManager.declare_var("int val[5]", &val); + + // ACT + memoryManager.clear_var((void*) 0xdeadbeef); + + // ASSERT + for (int i = 0; i < 5; i++) { + ASSERT_EQ(i+5, val[i]); + } +} + + +TEST_F(MemoryManagerTest, clear_value_by_name) { + // ARRANGE + int val[5]; + for (int i = 0; i < 5; i++) { + val[i] = i+5; + } + memoryManager.declare_var("int val[5]", &val); + + // ACT + memoryManager.clear_var("val"); + + // ASSERT + for (int i = 0; i < 5; i++) { + ASSERT_EQ(0, val[i]); + } +} + +TEST_F(MemoryManagerTest, clear_value_by_name_not_found) { + // ARRANGE + int val[5]; + for (int i = 0; i < 5; i++) { + val[i] = i+5; + } + memoryManager.declare_var("int val[5]", &val); + + // ACT + memoryManager.clear_var("no_such_variable"); + + // ASSERT + for (int i = 0; i < 5; i++) { + ASSERT_EQ(i+5, val[i]); + } +} + +TEST_F(MemoryManagerTest, clear_all_values) { + // ARRANGE + int val[5] = {5, 6, 7, 8, 9}; + std::string s = "Hello world"; + double d = 42.42; + + memoryManager.declare_var("int val[5]", &val); + memoryManager.declare_var("std::string s", &s); + memoryManager.declare_var("double d", &d); + + // ACT + memoryManager.clear_all_vars(); + + // ASSERT + for (int i = 0; i < 5; i++) { + EXPECT_EQ(0, val[i]); + } + EXPECT_EQ(std::string(""), s); + EXPECT_EQ(0.0, d); +} + +TEST_F(MemoryManagerTest, delete_var_by_name) { + // ARRANGE + double * val = (double *) memoryManager.declare_var("double val"); + ASSERT_EQ(true, memoryManager.var_exists("val")); + + // ACT + memoryManager.delete_var("val"); + + // ASSERT + ASSERT_EQ(false, memoryManager.var_exists("val")); +} + +TEST_F(MemoryManagerTest, delete_var_by_name_not_found) { + // ARRANGE + double * val = (double *) memoryManager.declare_var("double val"); + ASSERT_EQ(true, memoryManager.var_exists("val")); + + // ACT + memoryManager.delete_var("no_such_var"); + + // ASSERT + ASSERT_EQ(true, memoryManager.var_exists("val")); +} + +TEST_F(MemoryManagerTest, delete_var_by_addr) { + // ARRANGE + double * val = (double *) memoryManager.declare_var("double val"); + ASSERT_EQ(true, memoryManager.var_exists("val")); + + // ACT + memoryManager.delete_var(val); + + // ASSERT + ASSERT_EQ(false, memoryManager.var_exists("val")); +} + +TEST_F(MemoryManagerTest, delete_var_by_addr_not_found) { + // ARRANGE + double * val = (double *) memoryManager.declare_var("double val"); + ASSERT_EQ(true, memoryManager.var_exists("val")); + + // ACT + memoryManager.delete_var((void *) 0xdeadbeef); + + // ASSERT + ASSERT_EQ(true, memoryManager.var_exists("val")); +} + +bool constructor_called = false; +bool destructor_called = false; + +class MyClass { + public: + MyClass () { constructor_called = true; } + ~MyClass () { destructor_called = true; } +}; + +void * MyClassAllocator (int n) { + return new MyClass; +} + +void MyClassDeallocator (void * addr) { + MyClass * temp = (MyClass *) addr; + delete temp; +} + +TEST_F (MemoryManagerTest, declare_calls_constructor_of_local) { + // ARRANGE + constructor_called = false; + destructor_called = false; + + CompositeDataType * type = new CompositeDataType("MyClass", sizeof(MyClass), MyClassAllocator, MyClassDeallocator); + type->validate(&dataTypeInator); + + dataTypeInator.addToDictionary("MyClass", type); + + // ACT + MyClass * my_class_instance = (MyClass *) memoryManager.declare_var("MyClass my_class_instance"); + + // ASSERT + ASSERT_EQ(true, constructor_called); + ASSERT_EQ(true, memoryManager.var_exists("my_class_instance")); +} + +TEST_F (MemoryManagerTest, declare_does_not_call_constructor_of_extern) { + // ARRANGE + CompositeDataType * type = new CompositeDataType("MyClass", sizeof(MyClass), MyClassAllocator, MyClassDeallocator); + dataTypeInator.addToDictionary("MyClass", type); + + MyClass my_class_instance; + + constructor_called = false; + destructor_called = false; + + // ACT + memoryManager.declare_var("MyClass my_class_instance", &my_class_instance); + + // ASSERT + ASSERT_EQ(false, constructor_called); + ASSERT_EQ(true, memoryManager.var_exists("my_class_instance")); + +} + + +TEST_F (MemoryManagerTest, delete_calls_destructor_of_local) { + // ARRANGE + constructor_called = false; + destructor_called = false; + + CompositeDataType * type = new CompositeDataType("MyClass", sizeof(MyClass), MyClassAllocator, MyClassDeallocator); + dataTypeInator.addToDictionary("MyClass", type); + + MyClass * my_class_instance = (MyClass *) memoryManager.declare_var("MyClass my_class_instance"); + + // ACT + memoryManager.delete_var("my_class_instance"); + + // ASSERT + ASSERT_EQ(true, destructor_called); + ASSERT_EQ(false, memoryManager.var_exists("my_class_instance")); + +} + +TEST_F (MemoryManagerTest, delete_does_not_call_destructor_of_extern) { + // ARRANGE + constructor_called = false; + destructor_called = false; + + CompositeDataType * type = new CompositeDataType("MyClass", sizeof(MyClass), MyClassAllocator, MyClassDeallocator); + dataTypeInator.addToDictionary("MyClass", type); + + MyClass my_class_instance; + memoryManager.declare_var("MyClass my_class_instance", &my_class_instance); + + // ACT + memoryManager.delete_var("my_class_instance"); + + // ASSERT + ASSERT_EQ(false, destructor_called); + ASSERT_EQ(false, memoryManager.var_exists("my_class_instance")); + +} \ No newline at end of file