frame.h 4.3 KB

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