16 PyROOT::TMemoryRegulator::ObjectMap_t* PyROOT::TMemoryRegulator::fgObjectTable = 0;
17 PyROOT::TMemoryRegulator::WeakRefMap_t* PyROOT::TMemoryRegulator::fgWeakRefTable = 0;
23 PyMethodDef gObjectEraseMethodDef = {
24 const_cast< char*
>(
"TMemoryRegulator_internal_ObjectEraseCallback" ),
25 (PyCFunction) PyROOT::TMemoryRegulator::ObjectEraseCallback,
31 PyTypeObject PyROOT_NoneType;
35 Py_ssize_t AlwaysNullLength( PyObject* )
42 PyMappingMethods PyROOT_NoneType_mapping = {
49 #if defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ >= 4 && ((__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ >= 1) || (__GNUC_MINOR__ >= 3)))) && !__INTEL_COMPILER
50 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
55 struct InitPyROOT_NoneType_t {
56 InitPyROOT_NoneType_t()
59 memset( &PyROOT_NoneType, 0,
sizeof( PyROOT_NoneType ) );
61 ((PyObject&)PyROOT_NoneType).ob_type = &PyType_Type;
62 ((PyObject&)PyROOT_NoneType).ob_refcnt = 1;
63 ((PyVarObject&)PyROOT_NoneType).ob_size = 0;
65 PyROOT_NoneType.tp_name =
const_cast< char*
>(
"PyROOT_NoneType" );
66 PyROOT_NoneType.tp_flags = Py_TPFLAGS_HAVE_RICHCOMPARE | Py_TPFLAGS_HAVE_GC;
68 PyROOT_NoneType.tp_traverse = (traverseproc) 0;
69 PyROOT_NoneType.tp_clear = (inquiry) 0;
70 PyROOT_NoneType.tp_dealloc = (destructor) &InitPyROOT_NoneType_t::DeAlloc;
71 PyROOT_NoneType.tp_repr = Py_TYPE(Py_None)->tp_repr;
72 PyROOT_NoneType.tp_richcompare = (richcmpfunc) &InitPyROOT_NoneType_t::RichCompare;
73 #if PY_VERSION_HEX < 0x03000000
75 PyROOT_NoneType.tp_compare = (cmpfunc) &InitPyROOT_NoneType_t::Compare;
77 PyROOT_NoneType.tp_hash = (hashfunc) &InitPyROOT_NoneType_t::PtrHash;
79 PyROOT_NoneType.tp_as_mapping = &PyROOT_NoneType_mapping;
81 PyType_Ready( &PyROOT_NoneType );
84 static void DeAlloc( PyObject* obj ) { Py_TYPE(obj)->tp_free( obj ); }
85 static int PtrHash( PyObject* obj ) {
return (
int)Long_t(obj); }
87 static PyObject* RichCompare( PyObject*, PyObject* other,
int opid )
89 return PyObject_RichCompare( other, Py_None, opid );
92 static int Compare( PyObject*, PyObject* other )
94 #if PY_VERSION_HEX < 0x03000000
95 return PyObject_Compare( other, Py_None );
98 return ! PyObject_RichCompareBool( other, Py_None, Py_EQ );
107 PyROOT::TMemoryRegulator::TMemoryRegulator()
110 static InitPyROOT_NoneType_t initPyROOT_NoneType;
112 assert( fgObjectTable == 0 );
113 fgObjectTable =
new ObjectMap_t;
115 assert( fgWeakRefTable == 0 );
116 fgWeakRefTable =
new WeakRefMap_t;
122 PyROOT::TMemoryRegulator::~TMemoryRegulator()
124 delete fgWeakRefTable;
127 delete fgObjectTable;
133 void PyROOT::TMemoryRegulator::RecursiveRemove( TObject*
object )
136 if ( !
object || ! fgObjectTable )
140 ObjectMap_t::iterator ppo = fgObjectTable->find(
object );
142 if ( ppo != fgObjectTable->end() ) {
143 fgWeakRefTable->erase( fgWeakRefTable->find( ppo->second ) );
146 ObjectProxy* pyobj = (ObjectProxy*)PyWeakref_GetObject( ppo->second );
148 fgObjectTable->erase( ppo );
153 Py_DECREF( ppo->second );
156 if ( ObjectProxy_Check( pyobj ) ) {
157 if ( ! PyROOT_NoneType.tp_traverse ) {
159 Py_INCREF( Py_TYPE(pyobj) );
162 PyROOT_NoneType.tp_traverse = Py_TYPE(pyobj)->tp_traverse;
163 PyROOT_NoneType.tp_clear = Py_TYPE(pyobj)->tp_clear;
164 PyROOT_NoneType.tp_free = Py_TYPE(pyobj)->tp_free;
165 }
else if ( PyROOT_NoneType.tp_traverse != Py_TYPE(pyobj)->tp_traverse ) {
166 std::cerr <<
"in PyROOT::TMemoryRegulater, unexpected object of type: "
167 << Py_TYPE(pyobj)->tp_name << std::endl;
174 int refcnt = ((PyObject*)pyobj)->ob_refcnt;
175 ((PyObject*)pyobj)->ob_refcnt = 0;
176 PyObject_ClearWeakRefs( (PyObject*)pyobj );
177 ((PyObject*)pyobj)->ob_refcnt = refcnt;
181 op_dealloc_nofree( pyobj );
184 Py_INCREF( (PyObject*)(
void*)&PyROOT_NoneType );
185 Py_DECREF( Py_TYPE(pyobj) );
186 ((PyObject*)pyobj)->ob_type = &PyROOT_NoneType;
190 fgObjectTable->erase( ppo );
197 void PyROOT::TMemoryRegulator::ClearProxiedObjects()
199 while (!fgObjectTable->empty()) {
200 auto elem = fgObjectTable->begin();
201 auto cppobj = elem->first;
202 auto pyobj = (ObjectProxy*)PyWeakref_GetObject(elem->second);
204 if (pyobj && (pyobj->fFlags & ObjectProxy::kIsOwner)) {
212 UnregisterObject(cppobj);
220 Bool_t PyROOT::TMemoryRegulator::RegisterObject( ObjectProxy* pyobj, TObject*
object )
222 static PyObject* objectEraseCallback = PyCFunction_New(&gObjectEraseMethodDef,
nullptr);
224 if ( ! ( pyobj &&
object ) )
227 ObjectMap_t::iterator ppo = fgObjectTable->find(
object );
228 if ( ppo == fgObjectTable->end() ) {
229 object->SetBit( TObject::kMustCleanup );
230 PyObject* pyref = PyWeakref_NewRef( (PyObject*)pyobj, objectEraseCallback );
231 ObjectMap_t::iterator newppo = fgObjectTable->insert( std::make_pair(
object, pyref ) ).first;
232 (*fgWeakRefTable)[ pyref ] = newppo;
242 Bool_t PyROOT::TMemoryRegulator::UnregisterObject( TObject*
object )
244 ObjectMap_t::iterator ppo = fgObjectTable->find(
object );
246 if ( ppo != fgObjectTable->end() ) {
247 fgWeakRefTable->erase( fgWeakRefTable->find( ppo->second ) );
248 fgObjectTable->erase( ppo );
258 PyObject* PyROOT::TMemoryRegulator::RetrieveObject( TObject*
object, Cppyy::TCppType_t klass )
263 ObjectMap_t::iterator ppo = fgObjectTable->find(
object );
264 if ( ppo != fgObjectTable->end() ) {
265 PyObject* pyobj = PyWeakref_GetObject( ppo->second );
267 if ( pyobj && ((ObjectProxy*)pyobj)->ObjectIsA() != klass ) {
279 PyObject* PyROOT::TMemoryRegulator::ObjectEraseCallback( PyObject*, PyObject* pyref )
282 ObjectProxy* pyobj = (ObjectProxy*)PyWeakref_GetObject( pyref );
284 if ( ObjectProxy_Check( pyobj ) && pyobj->GetObject() != 0 ) {
286 static Cppyy::TCppScope_t sTObjectScope = Cppyy::GetScope(
"TObject" );
287 Cppyy::TCppType_t klass = pyobj->ObjectIsA();
288 if ( Cppyy::IsSubtype( klass, sTObjectScope) ) {
289 void* address = pyobj->GetObject();
290 TObject*
object = (TObject*)((Long_t)address + \
291 Cppyy::GetBaseOffset( klass, sTObjectScope, address, 1 ) );
294 ObjectMap_t::iterator ppo = fgObjectTable->find(
object );
295 if ( ppo != fgObjectTable->end() ) {
297 fgWeakRefTable->erase( fgWeakRefTable->find( ppo->second ) );
298 Py_DECREF( ppo->second );
299 fgObjectTable->erase( ppo );
304 WeakRefMap_t::iterator wri = fgWeakRefTable->find( pyref );
305 if ( wri != fgWeakRefTable->end() ) {
306 fgObjectTable->erase( wri->second );
307 fgWeakRefTable->erase( wri );
312 Py_INCREF( Py_None );