frame.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #pragma once
  2. #include "codeobject.h"
  3. #include "vector.h"
  4. namespace pkpy{
  5. static THREAD_LOCAL uint64_t kFrameGlobalId = 0;
  6. using ValueStack = small_vector<PyObject*, 6>;
  7. struct Frame {
  8. ValueStack _data;
  9. int _ip = -1;
  10. int _next_ip = 0;
  11. const CodeObject* co;
  12. PyObject* _module;
  13. NameDict_ _locals;
  14. NameDict_ _closure;
  15. const uint64_t id;
  16. std::vector<std::pair<int, ValueStack>> s_try_block;
  17. const NameDict* names[5]; // name resolution array, zero terminated
  18. NameDict& f_locals() noexcept { return *_locals; }
  19. NameDict& f_globals() noexcept { return _module->attr(); }
  20. Frame(const CodeObject_& co, PyObject* _module, PyObject* builtins, NameDict_ _locals=nullptr, NameDict_ _closure=nullptr)
  21. : co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) {
  22. memset(names, 0, sizeof(names));
  23. int i = 0;
  24. if(_locals != nullptr) names[i++] = _locals.get();
  25. if(_closure != nullptr) names[i++] = _closure.get();
  26. names[i++] = &_module->attr(); // borrowed reference
  27. if(builtins != nullptr){
  28. names[i++] = &builtins->attr(); // borrowed reference
  29. }
  30. }
  31. const Bytecode& next_bytecode() {
  32. _ip = _next_ip++;
  33. return co->codes[_ip];
  34. }
  35. Str snapshot(){
  36. int line = co->codes[_ip].line;
  37. return co->src->snapshot(line);
  38. }
  39. Str stack_info(){
  40. StrStream ss;
  41. ss << id << " [";
  42. for(int i=0; i<_data.size(); i++){
  43. ss << (i64)_data[i];
  44. if(i != _data.size()-1) ss << ", ";
  45. }
  46. ss << "]";
  47. return ss.str();
  48. }
  49. void pop(){
  50. #if DEBUG_EXTRA_CHECK
  51. if(_data.empty()) throw std::runtime_error("_data.empty() is true");
  52. #endif
  53. _data.pop_back();
  54. }
  55. PyObject* popx(){
  56. #if DEBUG_EXTRA_CHECK
  57. if(_data.empty()) throw std::runtime_error("_data.empty() is true");
  58. #endif
  59. PyObject* ret = _data.back();
  60. _data.pop_back();
  61. return ret;
  62. }
  63. PyObject*& top(){
  64. #if DEBUG_EXTRA_CHECK
  65. if(_data.empty()) throw std::runtime_error("_data.empty() is true");
  66. #endif
  67. return _data.back();
  68. }
  69. PyObject*& top_1(){
  70. #if DEBUG_EXTRA_CHECK
  71. if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
  72. #endif
  73. return _data[_data.size()-2];
  74. }
  75. PyObject*& top_n(int n){
  76. n += 1;
  77. #if DEBUG_EXTRA_CHECK
  78. if(_data.size() < n) throw std::runtime_error("_data.size() < n");
  79. #endif
  80. return _data[_data.size()-n];
  81. }
  82. void push(PyObject* obj){
  83. #if DEBUG_EXTRA_CHECK
  84. if(obj == nullptr) throw std::runtime_error("obj == nullptr");
  85. #endif
  86. _data.push_back(obj);
  87. }
  88. void jump_abs(int i){ _next_ip = i; }
  89. void jump_rel(int i){ _next_ip += i; }
  90. void on_try_block_enter(){
  91. s_try_block.emplace_back(co->codes[_ip].block, _data);
  92. }
  93. void on_try_block_exit(){
  94. s_try_block.pop_back();
  95. }
  96. bool jump_to_exception_handler(){
  97. if(s_try_block.empty()) return false;
  98. PyObject* obj = popx();
  99. auto& p = s_try_block.back();
  100. _data = std::move(p.second);
  101. _data.push_back(obj);
  102. _next_ip = co->blocks[p.first].end;
  103. on_try_block_exit();
  104. return true;
  105. }
  106. int _exit_block(int i){
  107. if(co->blocks[i].type == FOR_LOOP) pop();
  108. else if(co->blocks[i].type == TRY_EXCEPT) on_try_block_exit();
  109. return co->blocks[i].parent;
  110. }
  111. void jump_abs_break(int target){
  112. const Bytecode& prev = co->codes[_ip];
  113. int i = prev.block;
  114. _next_ip = target;
  115. if(_next_ip >= co->codes.size()){
  116. while(i>=0) i = _exit_block(i);
  117. }else{
  118. const Bytecode& next = co->codes[target];
  119. while(i>=0 && i!=next.block) i = _exit_block(i);
  120. if(i!=next.block) throw std::runtime_error("invalid jump");
  121. }
  122. }
  123. Args popx_n_reversed(int n){
  124. Args v(n);
  125. for(int i=n-1; i>=0; i--) v[i] = popx();
  126. return v;
  127. }
  128. void pop_n(int n){
  129. _data.pop_back_n(n);
  130. }
  131. void _mark() const {
  132. for(PyObject* obj : _data) OBJ_MARK(obj);
  133. OBJ_MARK(_module);
  134. _locals->_mark();
  135. _closure->_mark();
  136. for(auto& p : s_try_block){
  137. for(PyObject* obj : p.second) OBJ_MARK(obj);
  138. }
  139. co->_mark();
  140. }
  141. };
  142. }; // namespace pkpy