gc.h 3.0 KB

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