1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkObjectBase.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "vtkObjectBase.h"
17 #include "vtkDebug.h"
18 #include "vtkDebugLeaks.h"
19 #include "vtkGarbageCollector.h"
20 #include "vtkWeakPointerBase.h"
21 
22 #include <cassert>
23 #include <sstream>
24 
25 #ifdef VTK_USE_MEMKIND
26 #include <memkind.h>
27 struct memkind* MemkindHandle = nullptr;
28 #endif
29 
30 #define vtkBaseDebugMacro(x)
31 
32 class vtkObjectBaseToGarbageCollectorFriendship
33 {
34 public:
GiveReference(vtkObjectBase * obj)35   static int GiveReference(vtkObjectBase* obj) { return vtkGarbageCollector::GiveReference(obj); }
TakeReference(vtkObjectBase * obj)36   static int TakeReference(vtkObjectBase* obj) { return vtkGarbageCollector::TakeReference(obj); }
37 };
38 
39 class vtkObjectBaseToWeakPointerBaseFriendship
40 {
41 public:
ClearPointer(vtkWeakPointerBase * p)42   static void ClearPointer(vtkWeakPointerBase* p) { p->Object = nullptr; }
43 };
44 
45 //------------------------------------------------------------------------------
vtkCustomMalloc(size_t size)46 void* vtkCustomMalloc(size_t size)
47 {
48 #ifdef VTK_USE_MEMKIND
49   if (MemkindHandle == nullptr)
50   {
51     vtkGenericWarningMacro(<< "memkind_malloc() called before memkind initialized.");
52   }
53   else
54   {
55     return memkind_malloc(MemkindHandle, size);
56   }
57 #else
58   (void)size;
59 #endif
60   return nullptr;
61 }
62 
63 //------------------------------------------------------------------------------
vtkCustomRealloc(void * p,size_t size)64 void* vtkCustomRealloc(void* p, size_t size)
65 {
66 #ifdef VTK_USE_MEMKIND
67   if (MemkindHandle == nullptr)
68   {
69     vtkGenericWarningMacro(<< "memkind_realloc() called before memkind initialized.");
70   }
71   else
72   {
73     return memkind_realloc(MemkindHandle, p, size);
74   }
75 #else
76   (void)p;
77   (void)size;
78 #endif
79   return nullptr;
80 }
81 
82 //------------------------------------------------------------------------------
vtkCustomFree(void * addr)83 void vtkCustomFree(void* addr)
84 {
85 #ifdef VTK_USE_MEMKIND
86   memkind_free(MemkindHandle, addr);
87 #else
88   (void)addr;
89 #endif
90 }
91 
92 #if defined(_WIN32) || defined(VTK_USE_MEMKIND)
93 //------------------------------------------------------------------------------
94 // Take control of allocation to avoid dll boundary problems or to use memkind.
operator new(size_t nSize)95 void* vtkObjectBase::operator new(size_t nSize)
96 {
97 #ifdef VTK_USE_MEMKIND
98   return vtkObjectBase::GetCurrentMallocFunction()(nSize);
99 #else
100   return malloc(nSize);
101 #endif
102 }
103 
104 //------------------------------------------------------------------------------
operator delete(void * p)105 void vtkObjectBase::operator delete(void* p)
106 {
107 #ifdef VTK_USE_MEMKIND
108   if (static_cast<vtkObjectBase*>(p)->GetIsInMemkind())
109   {
110     vtkCustomFree(p);
111   }
112   else
113   {
114     free(p);
115   }
116 #else
117   free(p);
118 #endif
119 }
120 // take control of ... above
121 #endif
122 
123 // ------------------------------------vtkObjectBase----------------------
124 // This operator allows all subclasses of vtkObjectBase to be printed via <<.
125 // It in turn invokes the Print method, which in turn will invoke the
126 // PrintSelf method that all objects should define, if they have anything
127 // interesting to print out.
operator <<(ostream & os,vtkObjectBase & o)128 ostream& operator<<(ostream& os, vtkObjectBase& o)
129 {
130   o.Print(os);
131   return os;
132 }
133 
134 //------------------------------------------------------------------------------
135 // Create an object with Debug turned off and modified time initialized
136 // to zero.
vtkObjectBase()137 vtkObjectBase::vtkObjectBase()
138 {
139   this->ReferenceCount = 1;
140   this->WeakPointers = nullptr;
141 #ifdef VTK_DEBUG_LEAKS
142   vtkDebugLeaks::ConstructingObject(this);
143 #endif
144 #ifdef VTK_USE_MEMKIND
145   this->SetIsInMemkind(vtkObjectBase::GetUsingMemkind());
146 #else
147   this->IsInMemkind = false;
148 #endif
149 }
150 
151 //------------------------------------------------------------------------------
~vtkObjectBase()152 vtkObjectBase::~vtkObjectBase()
153 {
154 #ifdef VTK_DEBUG_LEAKS
155   vtkDebugLeaks::DestructingObject(this);
156 #endif
157 
158   // warn user if reference counting is on and the object is being referenced
159   // by another object
160   if (this->ReferenceCount > 0)
161   {
162     vtkGenericWarningMacro(<< "Trying to delete object with non-zero reference count.");
163   }
164 }
165 
166 //------------------------------------------------------------------------------
InitializeObjectBase()167 void vtkObjectBase::InitializeObjectBase()
168 {
169 #ifdef VTK_DEBUG_LEAKS
170   vtkDebugLeaks::ConstructClass(this);
171 #endif // VTK_DEBUG_LEAKS
172 }
173 
174 //------------------------------------------------------------------------------
175 #ifdef VTK_WORKAROUND_WINDOWS_MANGLE
176 #undef GetClassName
177 // Define possible mangled names.
GetClassNameA() const178 const char* vtkObjectBase::GetClassNameA() const
179 {
180   return this->GetClassNameInternal();
181 }
GetClassNameW() const182 const char* vtkObjectBase::GetClassNameW() const
183 {
184   return this->GetClassNameInternal();
185 }
186 #endif
GetClassName() const187 const char* vtkObjectBase::GetClassName() const
188 {
189   return this->GetClassNameInternal();
190 }
191 
IsTypeOf(const char * name)192 vtkTypeBool vtkObjectBase::IsTypeOf(const char* name)
193 {
194   if (!strcmp("vtkObjectBase", name))
195   {
196     return 1;
197   }
198   return 0;
199 }
200 
IsA(const char * name)201 vtkTypeBool vtkObjectBase::IsA(const char* name)
202 {
203   return this->vtkObjectBase::IsTypeOf(name);
204 }
205 
GetNumberOfGenerationsFromBaseType(const char * name)206 vtkIdType vtkObjectBase::GetNumberOfGenerationsFromBaseType(const char* name)
207 {
208   if (!strcmp("vtkObjectBase", name))
209   {
210     return 0;
211   }
212   // Return the lowest value for vtkIdType. Because of recursion, the returned
213   // value for derived classes will be this value added to the type distance to
214   // vtkObjectBase. This sum will still be a negative (and, therefore, invalid)
215   // value.
216   return VTK_ID_MIN;
217 }
218 
GetNumberOfGenerationsFromBase(const char * name)219 vtkIdType vtkObjectBase::GetNumberOfGenerationsFromBase(const char* name)
220 {
221   return this->vtkObjectBase::GetNumberOfGenerationsFromBaseType(name);
222 }
223 
224 // Delete a vtk object. This method should always be used to delete an object
225 // when the new operator was used to create it. Using the C++ delete method
226 // will not work with reference counting.
Delete()227 void vtkObjectBase::Delete()
228 {
229   this->UnRegister(static_cast<vtkObjectBase*>(nullptr));
230 }
231 
FastDelete()232 void vtkObjectBase::FastDelete()
233 {
234   // Remove the reference without doing a collection check even if
235   // this object normally participates in garbage collection.
236   this->UnRegisterInternal(nullptr, 0);
237 }
238 
Print(ostream & os)239 void vtkObjectBase::Print(ostream& os)
240 {
241   vtkIndent indent;
242 
243   this->PrintHeader(os, vtkIndent(0));
244   this->PrintSelf(os, indent.GetNextIndent());
245   this->PrintTrailer(os, vtkIndent(0));
246 }
247 
PrintHeader(ostream & os,vtkIndent indent)248 void vtkObjectBase::PrintHeader(ostream& os, vtkIndent indent)
249 {
250   os << indent << this->GetClassName() << " (" << this << ")\n";
251 }
252 
253 // Chaining method to print an object's instance variables, as well as
254 // its superclasses.
PrintSelf(ostream & os,vtkIndent indent)255 void vtkObjectBase::PrintSelf(ostream& os, vtkIndent indent)
256 {
257   os << indent << "Reference Count: " << this->ReferenceCount << "\n";
258 }
259 
PrintTrailer(ostream & os,vtkIndent indent)260 void vtkObjectBase::PrintTrailer(ostream& os, vtkIndent indent)
261 {
262   os << indent << "\n";
263 }
264 
265 // Description:
266 // Sets the reference count (use with care)
SetReferenceCount(int ref)267 void vtkObjectBase::SetReferenceCount(int ref)
268 {
269   this->ReferenceCount = ref;
270   vtkBaseDebugMacro(<< "Reference Count set to " << this->ReferenceCount);
271 }
272 
273 //------------------------------------------------------------------------------
Register(vtkObjectBase * o)274 void vtkObjectBase::Register(vtkObjectBase* o)
275 {
276   // Do not participate in garbage collection by default.
277   this->RegisterInternal(o, 0);
278 }
279 
280 //------------------------------------------------------------------------------
UnRegister(vtkObjectBase * o)281 void vtkObjectBase::UnRegister(vtkObjectBase* o)
282 {
283   // Do not participate in garbage collection by default.
284   this->UnRegisterInternal(o, 0);
285 }
286 
287 //------------------------------------------------------------------------------
RegisterInternal(vtkObjectBase *,vtkTypeBool check)288 void vtkObjectBase::RegisterInternal(vtkObjectBase*, vtkTypeBool check)
289 {
290   // If a reference is available from the garbage collector, use it.
291   // Otherwise create a new reference by incrementing the reference
292   // count.
293   if (!(check && vtkObjectBaseToGarbageCollectorFriendship::TakeReference(this)))
294   {
295     this->ReferenceCount++;
296   }
297 }
298 
299 //------------------------------------------------------------------------------
UnRegisterInternal(vtkObjectBase *,vtkTypeBool check)300 void vtkObjectBase::UnRegisterInternal(vtkObjectBase*, vtkTypeBool check)
301 {
302   // If the garbage collector accepts a reference, do not decrement
303   // the count.
304   if (check && this->ReferenceCount > 1 &&
305     vtkObjectBaseToGarbageCollectorFriendship::GiveReference(this))
306   {
307     return;
308   }
309 
310   // Decrement the reference count, delete object if count goes to zero.
311   if (--this->ReferenceCount <= 0)
312   {
313     // Clear all weak pointers to the object before deleting it.
314     if (this->WeakPointers)
315     {
316       vtkWeakPointerBase** p = this->WeakPointers;
317       while (*p)
318       {
319         vtkObjectBaseToWeakPointerBaseFriendship::ClearPointer(*p++);
320       }
321       delete[] this->WeakPointers;
322     }
323 #ifdef VTK_DEBUG_LEAKS
324     vtkDebugLeaks::DestructClass(this);
325 #endif
326     delete this;
327   }
328   else if (check)
329   {
330     // The garbage collector did not accept the reference, but the
331     // object still exists and is participating in garbage collection.
332     // This means either that delayed garbage collection is disabled
333     // or the collector has decided it is time to do a check.
334     vtkGarbageCollector::Collect(this);
335   }
336 }
337 
338 //------------------------------------------------------------------------------
ReportReferences(vtkGarbageCollector *)339 void vtkObjectBase::ReportReferences(vtkGarbageCollector*)
340 {
341   // vtkObjectBase has no references to report.
342 }
343 
344 namespace
345 {
346 #ifdef VTK_HAS_THREADLOCAL
347 #ifdef VTK_USE_MEMKIND
348 thread_local char* MemkindDirectory = nullptr;
349 #endif
350 thread_local bool UsingMemkind = false;
351 thread_local vtkMallocingFunction CurrentMallocFunction = malloc;
352 thread_local vtkReallocingFunction CurrentReallocFunction = realloc;
353 thread_local vtkFreeingFunction CurrentFreeFunction = free;
354 thread_local vtkFreeingFunction AlternateFreeFunction = vtkCustomFree;
355 #else
356 #ifdef VTK_USE_MEMKIND
357 char* MemkindDirectory = nullptr;
358 #endif
359 bool UsingMemkind = false;
360 vtkMallocingFunction CurrentMallocFunction = malloc;
361 vtkReallocingFunction CurrentReallocFunction = realloc;
362 vtkFreeingFunction CurrentFreeFunction = free;
363 vtkFreeingFunction AlternateFreeFunction = vtkCustomFree;
364 #endif
365 }
366 
367 //------------------------------------------------------------------------------
SetMemkindDirectory(const char * directoryname)368 void vtkObjectBase::SetMemkindDirectory(const char* directoryname)
369 {
370 #ifndef VTK_HAS_THREADLOCAL
371   vtkGenericWarningMacro(<< "Warning, memkind features are not thread safe on this platform.");
372 #endif
373 #ifdef VTK_USE_MEMKIND
374   if (MemkindDirectory == nullptr && MemkindHandle == nullptr)
375   {
376     MemkindDirectory = strdup(directoryname);
377     int err = 0;
378     if (!strncmp(directoryname, "ALLOCATOR_ONLY", 14))
379     {
380       // This gives us memkind's managed allocator but without extended memory.
381       // It is useful for comparison and has performance benefits from page fault avoidance.
382       MemkindHandle = MEMKIND_DEFAULT;
383     }
384     else
385     {
386       if (!strncmp(directoryname, "DAX_KMEM", 8))
387       {
388 #if MEMKIND_VERSION_MINOR > 9
389         MemkindHandle = MEMKIND_DAX_KMEM;
390 #else
391         vtkGenericWarningMacro(<< "Warning, DAX_KMEM requires memkind >= 1.10");
392         MemkindHandle = MEMKIND_DEFAULT;
393 #endif
394       }
395       else
396       {
397         err = memkind_create_pmem(MemkindDirectory, 0, &MemkindHandle);
398       }
399     }
400     if (err)
401     {
402       perror("memkind_create_pmem()");
403       free(MemkindDirectory);
404       MemkindDirectory = nullptr;
405     }
406   }
407   else
408   {
409     vtkGenericWarningMacro(<< "Warning, can only initialize memkind once.");
410   }
411 #else
412   (void)directoryname;
413 #endif
414 }
415 
416 //------------------------------------------------------------------------------
GetUsingMemkind()417 bool vtkObjectBase::GetUsingMemkind()
418 {
419   return UsingMemkind;
420 }
421 
422 //------------------------------------------------------------------------------
SetUsingMemkind(bool b)423 void vtkObjectBase::SetUsingMemkind(bool b)
424 {
425 #ifdef VTK_USE_MEMKIND
426   UsingMemkind = b;
427   if (b)
428   {
429     CurrentMallocFunction = vtkCustomMalloc;
430     CurrentReallocFunction = vtkCustomRealloc;
431     CurrentFreeFunction = vtkCustomFree;
432   }
433   else
434   {
435     CurrentMallocFunction = malloc;
436     CurrentReallocFunction = realloc;
437     CurrentFreeFunction = free;
438   }
439 #else
440   // no harm in the above but avoid the cycles if we can
441   (void)b;
442   assert(!b);
443 #endif
444 }
445 
446 //------------------------------------------------------------------------------
GetCurrentMallocFunction()447 vtkMallocingFunction vtkObjectBase::GetCurrentMallocFunction()
448 {
449   return CurrentMallocFunction;
450 }
451 //------------------------------------------------------------------------------
GetCurrentReallocFunction()452 vtkReallocingFunction vtkObjectBase::GetCurrentReallocFunction()
453 {
454   return CurrentReallocFunction;
455 }
456 //------------------------------------------------------------------------------
GetCurrentFreeFunction()457 vtkFreeingFunction vtkObjectBase::GetCurrentFreeFunction()
458 {
459   return CurrentFreeFunction;
460 }
461 //------------------------------------------------------------------------------
GetAlternateFreeFunction()462 vtkFreeingFunction vtkObjectBase::GetAlternateFreeFunction()
463 {
464   return AlternateFreeFunction;
465 }
466 
467 //------------------------------------------------------------------------------
GetIsInMemkind() const468 bool vtkObjectBase::GetIsInMemkind() const
469 {
470   return this->IsInMemkind;
471 }
472 
473 //------------------------------------------------------------------------------
SetIsInMemkind(bool v)474 void vtkObjectBase::SetIsInMemkind(bool v)
475 {
476 #ifdef VTK_USE_MEMKIND
477   this->IsInMemkind = v;
478 #else
479   (void)v;
480   assert(!v);
481 #endif
482 }
483 
484 //------------------------------------------------------------------------------
vtkMemkindRAII(bool newValue)485 vtkObjectBase::vtkMemkindRAII::vtkMemkindRAII(bool newValue)
486 {
487   this->Save(newValue);
488 }
489 
490 //------------------------------------------------------------------------------
~vtkMemkindRAII()491 vtkObjectBase::vtkMemkindRAII::~vtkMemkindRAII()
492 {
493   this->Restore();
494 }
495 
496 //------------------------------------------------------------------------------
Save(bool newValue)497 void vtkObjectBase::vtkMemkindRAII::Save(bool newValue)
498 {
499 #ifdef VTK_USE_MEMKIND
500   this->OriginalValue = vtkObjectBase::GetUsingMemkind();
501   vtkObjectBase::SetUsingMemkind(newValue);
502 #else
503   (void)newValue;
504 #endif
505 }
506 
507 //------------------------------------------------------------------------------
Restore()508 void vtkObjectBase::vtkMemkindRAII::Restore()
509 {
510 #ifdef VTK_USE_MEMKIND
511   vtkObjectBase::SetUsingMemkind(this->OriginalValue);
512 #endif
513 }
514