frame.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #include "pocketpy/frame.h"
  2. namespace pkpy{
  3. PyVar* FastLocals::try_get_name(StrName name){
  4. int index = co->varnames_inv.try_get(name);
  5. if(index == -1) return nullptr;
  6. return &a[index];
  7. }
  8. NameDict_ FastLocals::to_namedict(){
  9. NameDict_ dict = std::make_shared<NameDict>();
  10. co->varnames_inv.apply([&](StrName name, int index){
  11. PyVar value = a[index];
  12. if(value != PY_NULL) dict->set(name, value);
  13. });
  14. return dict;
  15. }
  16. PyVar Frame::f_closure_try_get(StrName name){
  17. if(_callable == nullptr) return nullptr;
  18. Function& fn = PK_OBJ_GET(Function, _callable);
  19. if(fn._closure == nullptr) return nullptr;
  20. return fn._closure->try_get(name);
  21. }
  22. int Frame::prepare_jump_exception_handler(ValueStack* _s){
  23. // try to find a parent try block
  24. int i = co->lines[ip()].iblock;
  25. while(i >= 0){
  26. if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
  27. i = co->blocks[i].parent;
  28. }
  29. if(i < 0) return -1;
  30. PyVar obj = _s->popx(); // pop exception object
  31. UnwindTarget* uw = find_unwind_target(i);
  32. _s->reset(actual_sp_base() + uw->offset); // unwind the stack
  33. _s->push(obj); // push it back
  34. return co->blocks[i].end;
  35. }
  36. int Frame::_exit_block(ValueStack* _s, int i){
  37. auto type = co->blocks[i].type;
  38. if(type == CodeBlockType::FOR_LOOP){
  39. _s->pop(); // pop the iterator
  40. // pop possible stack memory slots
  41. if(_s->top().type == kTpStackMemoryIndex){
  42. int count = _s->top().as<StackMemory>().count;
  43. PK_DEBUG_ASSERT(count < 0);
  44. _s->_sp += count;
  45. _s->_sp -= 2; // pop header and tail
  46. }
  47. }else if(type==CodeBlockType::CONTEXT_MANAGER){
  48. _s->pop();
  49. }
  50. return co->blocks[i].parent;
  51. }
  52. void Frame::prepare_jump_break(ValueStack* _s, int target){
  53. int i = co->lines[ip()].iblock;
  54. if(target >= co->codes.size()){
  55. while(i>=0) i = _exit_block(_s, i);
  56. }else{
  57. // BUG (solved)
  58. // for i in range(4):
  59. // _ = 0
  60. // # if there is no op here, the block check will fail
  61. // while i: --i
  62. int next_block = co->lines[target].iblock;
  63. while(i>=0 && i!=next_block) i = _exit_block(_s, i);
  64. if(i!=next_block) throw std::runtime_error("invalid jump");
  65. }
  66. }
  67. void Frame::set_unwind_target(PyVar* _sp){
  68. int iblock = co->lines[ip()].iblock;
  69. UnwindTarget* existing = find_unwind_target(iblock);
  70. if(existing){
  71. existing->offset = _sp - actual_sp_base();
  72. }else{
  73. UnwindTarget* prev = _uw_list;
  74. _uw_list = new UnwindTarget(iblock, _sp - actual_sp_base());
  75. _uw_list->next = prev;
  76. }
  77. }
  78. UnwindTarget* Frame::find_unwind_target(int iblock){
  79. UnwindTarget* p;
  80. for(p=_uw_list; p!=nullptr; p=p->next){
  81. if(p->iblock == iblock) return p;
  82. }
  83. return nullptr;
  84. }
  85. void Frame::free_unwind_target(){
  86. while(_uw_list != nullptr){
  87. UnwindTarget* p = _uw_list;
  88. _uw_list = p->next;
  89. delete p;
  90. }
  91. }
  92. } // namespace pkpy