kernel.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #pragma once
  2. #include <array>
  3. #include <vector>
  4. #include <string>
  5. #include <cstdlib>
  6. #include <cstring>
  7. #include <cassert>
  8. #include <optional>
  9. #include <typeindex>
  10. #include <stdexcept>
  11. #include <unordered_map>
  12. #include "pocketpy.h"
  13. #include "type_traits.h"
  14. namespace pkbind {
  15. class handle;
  16. struct action {
  17. using function = void (*)();
  18. inline static std::vector<function> starts;
  19. static void initialize() noexcept {
  20. for(auto func: starts) {
  21. func();
  22. }
  23. }
  24. // register a function to be called at the start of the vm.
  25. static void register_start(function func) { starts.push_back(func); }
  26. };
  27. /// hold the object long time.
  28. struct object_pool {
  29. inline static int cache = -1;
  30. inline static py_Ref pool = nullptr;
  31. inline static std::vector<int>* indices_ = nullptr;
  32. struct object_ref {
  33. py_Ref data;
  34. int index;
  35. };
  36. static void initialize(int size) noexcept {
  37. // use 8th register.
  38. pool = py_getreg(7);
  39. py_newtuple(pool, size);
  40. indices_ = new std::vector<int>(size, 0);
  41. }
  42. static void finalize() noexcept {
  43. delete indices_;
  44. indices_ = nullptr;
  45. }
  46. /// alloc an object from pool, note that the object is uninitialized.
  47. static object_ref alloc() {
  48. if(!indices_) { initialize(1024); }
  49. auto& indices = *indices_;
  50. if(cache != -1) {
  51. auto index = cache;
  52. cache = -1;
  53. indices[index] = 1;
  54. return {py_tuple_getitem(pool, index), index};
  55. }
  56. for(int i = 0; i < indices.size(); ++i) {
  57. if(indices[i] == 0) {
  58. indices[i] = 1;
  59. return {py_tuple_getitem(pool, i), i};
  60. }
  61. }
  62. throw std::runtime_error("object pool is full");
  63. }
  64. /// alloc an object from pool, the object is initialized with ref.
  65. static object_ref realloc(py_Ref ref) {
  66. auto result = alloc();
  67. py_assign(result.data, ref);
  68. return result;
  69. }
  70. static void inc_ref(object_ref ref) {
  71. if(!indices_) { return; }
  72. if(ref.data == py_tuple_getitem(pool, ref.index)) {
  73. auto& indices = *indices_;
  74. indices[ref.index] += 1;
  75. } else {
  76. throw std::runtime_error("object_ref is invalid");
  77. }
  78. }
  79. static void dec_ref(object_ref ref) {
  80. if(!indices_) { return; }
  81. if(ref.data == py_tuple_getitem(pool, ref.index)) {
  82. auto& indices = *indices_;
  83. indices[ref.index] -= 1;
  84. assert(indices[ref.index] >= 0 && "ref count is negative");
  85. if(indices[ref.index] == 0) { cache = ref.index; }
  86. } else {
  87. throw std::runtime_error("object_ref is invalid");
  88. }
  89. }
  90. };
  91. template <typename T>
  92. class lazy {
  93. public:
  94. lazy(void (*init)(T&)) : init(init) {}
  95. operator T& () {
  96. if(!initialized) {
  97. if(init) { init(value); }
  98. initialized = true;
  99. }
  100. return value;
  101. }
  102. T& operator* () { return static_cast<T&>(*this); }
  103. void reset() { initialized = false; }
  104. private:
  105. T value;
  106. bool initialized = false;
  107. void (*init)(T&) = nullptr;
  108. };
  109. } // namespace pkbind