frame.h 4.3 KB

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