1616
1717#include < ios>
1818#include < sstream>
19+ #include < unordered_map>
1920
2021#include " core/function.h"
2122#include " core/log.h"
2425#include " scripting/script_engine.h"
2526
2627namespace counterstrikesharp {
27- std::vector<ValveFunction*> m_managed_ptrs;
28+
29+ template <class T > inline void hash_combine (std::size_t & seed, const T& v)
30+ {
31+ std::hash<T> hasher;
32+ seed ^= hasher (v) + 0x9e3779b9 + (seed << 6 ) + (seed >> 2 );
33+ }
34+
35+ struct VirtualFunctionCacheKey
36+ {
37+ void * functionAddr;
38+ Convention_t callingConvention;
39+ std::vector<DataType_t> args;
40+ DataType_t returnType;
41+ int vtableOffset;
42+
43+ bool operator ==(const VirtualFunctionCacheKey& other) const
44+ {
45+ return functionAddr == other.functionAddr && callingConvention == other.callingConvention && args == other.args &&
46+ returnType == other.returnType && vtableOffset == other.vtableOffset ;
47+ }
48+ };
49+
50+ struct VirtualFunctionCacheKeyHash
51+ {
52+ std::size_t operator ()(const VirtualFunctionCacheKey& key) const
53+ {
54+ std::size_t hash = 0 ;
55+
56+ hash_combine (hash, std::hash<void *>{}(key.functionAddr ));
57+ hash_combine (hash, std::hash<int >{}(static_cast <int >(key.callingConvention )));
58+ hash_combine (hash, std::hash<int >{}(static_cast <int >(key.returnType )));
59+ hash_combine (hash, std::hash<int >{}(key.vtableOffset ));
60+
61+ for (const auto & arg : key.args )
62+ {
63+ hash_combine (hash, std::hash<int >{}(static_cast <int >(arg)));
64+ }
65+
66+ return hash;
67+ }
68+ };
69+
70+ std::unordered_map<VirtualFunctionCacheKey, ValveFunction*, VirtualFunctionCacheKeyHash> m_virtualFunctionCache;
71+
72+ size_t GetVirtualFunctionCacheSize () { return m_virtualFunctionCache.size (); }
2873
2974void * FindSignatureNative (ScriptContext& scriptContext)
3075{
@@ -64,12 +109,28 @@ ValveFunction* CreateVirtualFunctionBySignature(ScriptContext& script_context)
64109 args.push_back (script_context.GetArgument <DataType_t>(5 + i));
65110 }
66111
112+ VirtualFunctionCacheKey cacheKey;
113+ cacheKey.functionAddr = function_addr;
114+ cacheKey.callingConvention = CONV_CDECL;
115+ cacheKey.args = args;
116+ cacheKey.returnType = return_type;
117+ cacheKey.vtableOffset = -1 ;
118+
119+ auto it = m_virtualFunctionCache.find (cacheKey);
120+ if (it != m_virtualFunctionCache.end ())
121+ {
122+ CSSHARP_CORE_TRACE (" Virtual function found in cache, reusing existing instance at {}, signature {}" , function_addr,
123+ signature_hex_string);
124+ return it->second ;
125+ }
126+
67127 auto function = new ValveFunction (function_addr, CONV_CDECL, args, return_type);
68128 function->SetSignature (signature_hex_string);
69129
70- CSSHARP_CORE_TRACE (" Created virtual function, pointer found at {}, signature {}" , function_addr, signature_hex_string);
130+ m_virtualFunctionCache[cacheKey] = function;
131+
132+ CSSHARP_CORE_TRACE (" Created new virtual function, pointer found at {}, signature {}" , function_addr, signature_hex_string);
71133
72- m_managed_ptrs.push_back (function);
73134 return function;
74135}
75136
@@ -95,10 +156,27 @@ ValveFunction* CreateVirtualFunction(ScriptContext& script_context)
95156 args.push_back (script_context.GetArgument <DataType_t>(4 + i));
96157 }
97158
159+ VirtualFunctionCacheKey cacheKey;
160+ cacheKey.functionAddr = function_addr;
161+ cacheKey.callingConvention = CONV_THISCALL;
162+ cacheKey.args = args;
163+ cacheKey.returnType = return_type;
164+ cacheKey.vtableOffset = vtable_offset;
165+
166+ auto it = m_virtualFunctionCache.find (cacheKey);
167+ if (it != m_virtualFunctionCache.end ())
168+ {
169+ CSSHARP_CORE_TRACE (" Virtual function found in cache, reusing existing instance at {}, offset {}" , function_addr, vtable_offset);
170+ return it->second ;
171+ }
172+
98173 auto function = new ValveFunction (function_addr, CONV_THISCALL, args, return_type);
99174 function->SetOffset (vtable_offset);
100175
101- m_managed_ptrs.push_back (function);
176+ m_virtualFunctionCache[cacheKey] = function;
177+
178+ CSSHARP_CORE_TRACE (" Created new virtual function at {}, offset {}" , function_addr, vtable_offset);
179+
102180 return function;
103181}
104182
0 commit comments