gc.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #pragma once
  2. #include "common.h"
  3. #include "memory.h"
  4. #include "obj.h"
  5. #include "codeobject.h"
  6. #include "namedict.h"
  7. namespace pkpy {
  8. struct ManagedHeap{
  9. std::vector<PyObject*> _no_gc;
  10. std::vector<PyObject*> gen;
  11. VM* vm;
  12. void (*_gc_on_delete)(VM*, PyObject*) = nullptr;
  13. void (*_gc_marker_ex)(VM*) = nullptr;
  14. ManagedHeap(VM* vm): vm(vm) {}
  15. static const int kMinGCThreshold = 3072;
  16. int gc_threshold = kMinGCThreshold;
  17. int gc_counter = 0;
  18. /********************/
  19. int _gc_lock_counter = 0;
  20. struct ScopeLock{
  21. ManagedHeap* heap;
  22. ScopeLock(ManagedHeap* heap): heap(heap){
  23. heap->_gc_lock_counter++;
  24. }
  25. ~ScopeLock(){
  26. heap->_gc_lock_counter--;
  27. }
  28. };
  29. ScopeLock gc_scope_lock(){
  30. return ScopeLock(this);
  31. }
  32. /********************/
  33. template<typename T>
  34. PyObject* gcnew(Type type, T&& val){
  35. using __T = Py_<std::decay_t<T>>;
  36. PyObject* obj = new(pool64.alloc<__T>()) __T(type, std::forward<T>(val));
  37. gen.push_back(obj);
  38. gc_counter++;
  39. return obj;
  40. }
  41. template<typename T>
  42. PyObject* _new(Type type, T&& val){
  43. using __T = Py_<std::decay_t<T>>;
  44. PyObject* obj = new(pool64.alloc<__T>()) __T(type, std::forward<T>(val));
  45. obj->gc.enabled = false;
  46. _no_gc.push_back(obj);
  47. return obj;
  48. }
  49. #if DEBUG_GC_STATS
  50. inline static std::map<Type, int> deleted;
  51. #endif
  52. int sweep(){
  53. std::vector<PyObject*> alive;
  54. for(PyObject* obj: gen){
  55. if(obj->gc.marked){
  56. obj->gc.marked = false;
  57. alive.push_back(obj);
  58. }else{
  59. #if DEBUG_GC_STATS
  60. deleted[obj->type] += 1;
  61. #endif
  62. if(_gc_on_delete) _gc_on_delete(vm, obj);
  63. obj->~PyObject();
  64. pool64.dealloc(obj);
  65. }
  66. }
  67. // clear _no_gc marked flag
  68. for(PyObject* obj: _no_gc) obj->gc.marked = false;
  69. int freed = gen.size() - alive.size();
  70. // std::cout << "GC: " << alive.size() << "/" << gen.size() << " (" << freed << " freed)" << std::endl;
  71. gen.clear();
  72. gen.swap(alive);
  73. return freed;
  74. }
  75. void _auto_collect(){
  76. #if !DEBUG_NO_AUTO_GC
  77. if(_gc_lock_counter > 0) return;
  78. if(gc_counter < gc_threshold) return;
  79. gc_counter = 0;
  80. collect();
  81. gc_threshold = gen.size() * 2;
  82. if(gc_threshold < kMinGCThreshold) gc_threshold = kMinGCThreshold;
  83. #endif
  84. }
  85. int collect(){
  86. if(_gc_lock_counter > 0) FATAL_ERROR();
  87. mark();
  88. int freed = sweep();
  89. return freed;
  90. }
  91. void mark();
  92. ~ManagedHeap(){
  93. for(PyObject* obj: _no_gc) { obj->~PyObject(); pool64.dealloc(obj); }
  94. for(PyObject* obj: gen) { obj->~PyObject(); pool64.dealloc(obj); }
  95. #if DEBUG_GC_STATS
  96. for(auto& [type, count]: deleted){
  97. std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl;
  98. }
  99. #endif
  100. }
  101. };
  102. inline void FuncDecl::_gc_mark() const{
  103. code->_gc_mark();
  104. for(int i=0; i<kwargs.size(); i++) OBJ_MARK(kwargs[i].value);
  105. }
  106. } // namespace pkpy