From e993bbcb677e87bb0ae417cfc37b792796baa519 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 9 May 2011 13:48:54 +0400 Subject: [PATCH] Implement class name caching and optimized equality check. --- library/DFProcess-linux-SHM.cpp | 2 +- library/DFProcess-linux-wine.cpp | 4 ++-- library/DFProcess-linux.cpp | 4 ++-- library/DFProcess-windows-SHM.cpp | 2 +- library/DFProcess-windows.cpp | 4 ++-- library/include/dfhack/DFProcess.h | 29 ++++++++++++++++++++++++++++- library/modules/Items.cpp | 16 ++++------------ library/private/SHMProcess.h | 2 +- 8 files changed, 41 insertions(+), 22 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 73addd2c5..d87ebb8bc 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -383,7 +383,7 @@ void SHMProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet) } -string SHMProcess::readClassName (uint32_t vptr) +string SHMProcess::doReadClassName (uint32_t vptr) { if(!d->locked) throw Error::MemoryAccessDenied(vptr); diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp index f18083f14..58c309173 100644 --- a/library/DFProcess-linux-wine.cpp +++ b/library/DFProcess-linux-wine.cpp @@ -73,7 +73,7 @@ namespace { size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); size_t writeSTLString(const uint32_t address, const std::string writeString); // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); + std::string doReadClassName(uint32_t vptr); }; } @@ -168,7 +168,7 @@ const string WineProcess::readSTLString (uint32_t offset) return stl.readSTLString(offset); } -string WineProcess::readClassName (uint32_t vptr) +string WineProcess::doReadClassName (uint32_t vptr) { return stl.readClassName(vptr); } diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index e525648e0..6926d229e 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -73,7 +73,7 @@ namespace { size_t writeSTLString(const uint32_t address, const std::string writeString); size_t copySTLString(const uint32_t address, const uint32_t target); // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); + std::string doReadClassName(uint32_t vptr); }; } @@ -217,7 +217,7 @@ size_t NormalProcess::copySTLString (uint32_t offset, uint32_t target) return header._M_length; } -string NormalProcess::readClassName (uint32_t vptr) +string NormalProcess::doReadClassName (uint32_t vptr) { int typeinfo = Process::readDWord(vptr - 0x4); int typestring = Process::readDWord(typeinfo + 0x4); diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 1e516d26e..9ce4fa2cf 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -394,7 +394,7 @@ void SHMProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet) read(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet); } -string SHMProcess::readClassName (uint32_t vptr) +string SHMProcess::doReadClassName (uint32_t vptr) { int rtti = Process::readDWord(vptr - 0x4); int typeinfo = Process::readDWord(rtti + 0xC); diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index f625a2b64..10a5d1459 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -89,7 +89,7 @@ namespace size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); size_t writeSTLString(const uint32_t address, const std::string writeString); // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); + std::string doReadClassName(uint32_t vptr); const std::string readCString (uint32_t offset); @@ -590,7 +590,7 @@ size_t NormalProcess::writeSTLString (uint32_t address, string str) return stl.writeSTLString(address, str); } -string NormalProcess::readClassName (uint32_t vptr) +string NormalProcess::doReadClassName (uint32_t vptr) { return stl.readClassName(vptr); } diff --git a/library/include/dfhack/DFProcess.h b/library/include/dfhack/DFProcess.h index c47c9bc3b..32c24b554 100644 --- a/library/include/dfhack/DFProcess.h +++ b/library/include/dfhack/DFProcess.h @@ -30,6 +30,7 @@ distribution. #include "DFPragma.h" #include "DFExport.h" #include +#include namespace DFHack { @@ -93,12 +94,16 @@ namespace DFHack uint32_t end; uint32_t alloc_end; }; + /** * Allows low-level access to the memory of an OS process. OS processes can be enumerated by \ref ProcessEnumerator * \ingroup grp_context */ class DFHACK_EXPORT Process { + protected: + std::map classNameCache; + public: /// this is the single most important destructor ever. ~px virtual ~Process(){}; @@ -178,7 +183,14 @@ namespace DFHack /// read a STL vector virtual void readSTLVector(const uint32_t address, t_vecTriplet & triplet) = 0; /// get class name of an object with rtti/type info - virtual std::string readClassName(uint32_t vptr) = 0; + virtual std::string doReadClassName(uint32_t vptr) = 0; + + std::string readClassName(uint32_t vptr) { + std::map::iterator it = classNameCache.find(vptr); + if (it != classNameCache.end()) + return it->second; + return classNameCache[vptr] = doReadClassName(vptr); + } /// read a null-terminated C string virtual const std::string readCString (uint32_t offset) = 0; @@ -211,5 +223,20 @@ namespace DFHack virtual bool SetAndWait (uint32_t state) = 0; }; + class DFHACK_EXPORT ClassNameCheck { + std::string name; + uint32_t vptr; + public: + ClassNameCheck() : vptr(0) {} + ClassNameCheck(std::string _name) : name(_name), vptr(0) {} + ClassNameCheck &operator= (const ClassNameCheck &b) { + name = b.name; vptr = b.vptr; return *this; + } + bool operator() (Process *p, uint32_t ptr) { + if (vptr == 0 && p->readClassName(ptr) == name) + vptr = ptr; + return (vptr && vptr == ptr); + } + }; } #endif diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 05b8c34aa..20108c32e 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -419,7 +419,7 @@ class Items::Private std::map descVTable; uint32_t refVectorOffset; uint32_t refIDOffset; - uint32_t ownerRefVTable; + ClassNameCheck isOwnerRefClass; }; Items::Items(DFContextShared * d_) @@ -427,7 +427,8 @@ Items::Items(DFContextShared * d_) d = new Private; d->d = d_; d->owner = d_->p; - d->ownerRefVTable = d->refVectorOffset = d->refIDOffset = 0; + d->refVectorOffset = d->refIDOffset = 0; + d->isOwnerRefClass = ClassNameCheck("general_ref_unit_itemownerst"); } bool Items::Start() @@ -508,16 +509,7 @@ int32_t Items::getItemOwnerID(const DFHack::dfh_item &item) uint32_t curRef = p_refs[i]; uint32_t vtbl = d->owner->readDWord(curRef); - if (!d->ownerRefVTable) - { - std::string className = d->owner->readClassName(vtbl); - if (className == "general_ref_unit_itemownerst") - d->ownerRefVTable = vtbl; - else - continue; - } - else if (d->ownerRefVTable != vtbl) - continue; + if (!d->isOwnerRefClass(d->owner, vtbl)) continue; return d->owner->readDWord(curRef + d->refIDOffset); } diff --git a/library/private/SHMProcess.h b/library/private/SHMProcess.h index 9a1936c44..560a259e5 100644 --- a/library/private/SHMProcess.h +++ b/library/private/SHMProcess.h @@ -74,7 +74,7 @@ namespace DFHack void readSTLVector(const uint32_t address, t_vecTriplet & triplet); // get class name of an object with rtti/type info - std::string readClassName(uint32_t vptr); + std::string doReadClassName(uint32_t vptr); const std::string readCString (uint32_t offset);