diff --git a/include/pocketpy/frame.h b/include/pocketpy/frame.h index 6696aa52..7dcdc6d2 100644 --- a/include/pocketpy/frame.h +++ b/include/pocketpy/frame.h @@ -84,6 +84,8 @@ struct UnwindTarget{ }; struct Frame { + PK_ALWAYS_PASS_BY_POINTER(Frame) + const Bytecode* _ip; // This is for unwinding only, use `actual_sp_base()` for value stack access PyVar* _sp_base; @@ -129,9 +131,9 @@ struct Frame { void set_unwind_target(PyVar* _sp); UnwindTarget* find_unwind_target(int iblock); - void free_unwind_target(); void _gc_mark(VM* vm) const; + ~Frame(); }; struct LinkedFrame{ @@ -141,8 +143,9 @@ struct LinkedFrame{ LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward(args)...) {} }; + struct CallStack{ - static_assert(sizeof(LinkedFrame) <= 128 && std::is_trivially_destructible_v); + static_assert(sizeof(LinkedFrame) <= 128); LinkedFrame* _tail; int _size; @@ -162,10 +165,26 @@ struct CallStack{ PK_DEBUG_ASSERT(!empty()) LinkedFrame* p = _tail; _tail = p->f_back; + p->~LinkedFrame(); pool128_dealloc(p); --_size; } + LinkedFrame* popx(){ + PK_DEBUG_ASSERT(!empty()) + LinkedFrame* p = _tail; + _tail = p->f_back; + --_size; + p->f_back = nullptr; // unlink + return p; + } + + void pushx(LinkedFrame* p){ + p->f_back = _tail; + _tail = p; + ++_size; + } + Frame& top() const { PK_DEBUG_ASSERT(!empty()) return _tail->frame; @@ -175,6 +194,8 @@ struct CallStack{ void apply(Func&& f){ for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) f(p->frame); } + + ~CallStack(){ clear(); } }; }; // namespace pkpy \ No newline at end of file diff --git a/include/pocketpy/iter.h b/include/pocketpy/iter.h index 8d80a88f..33bf0112 100644 --- a/include/pocketpy/iter.h +++ b/include/pocketpy/iter.h @@ -43,21 +43,29 @@ struct StringIter{ }; struct Generator{ - Frame frame; + LinkedFrame* lf; int state; // 0,1,2 List s_backup; - Generator(Frame&& frame, ArgsView buffer): frame(std::move(frame)), state(0) { + Generator(LinkedFrame* lf, ArgsView buffer): lf(lf), state(0) { for(PyVar obj: buffer) s_backup.push_back(obj); } void _gc_mark(VM* vm) { - frame._gc_mark(vm); + if(lf == nullptr) return; + lf->frame._gc_mark(vm); vm->__stack_gc_mark(s_backup.begin(), s_backup.end()); } PyVar next(VM* vm); static void _register(VM* vm, PyVar mod, PyVar type); + + ~Generator(){ + if(lf){ + lf->~LinkedFrame(); + pool128_dealloc(lf); + } + } }; struct DictItemsIter{ diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 9408658a..67dc05b8 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -479,7 +479,7 @@ public: PyVar __format_object(PyVar, Str); PyVar __run_top_frame(); void __pop_frame(); - PyVar __py_generator(Frame&& frame, ArgsView buffer); + PyVar __py_generator(LinkedFrame* frame, ArgsView buffer); void __op_unpack_sequence(uint16_t arg); void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl_&); void __unpack_as_list(ArgsView args, List& list); diff --git a/src/frame.cpp b/src/frame.cpp index 7c257b02..934ee816 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -91,7 +91,7 @@ namespace pkpy{ return nullptr; } - void Frame::free_unwind_target(){ + Frame::~Frame(){ while(_uw_list != nullptr){ UnwindTarget* p = _uw_list; _uw_list = p->next; diff --git a/src/iter.cpp b/src/iter.cpp index 0c90d707..6eb138b6 100644 --- a/src/iter.cpp +++ b/src/iter.cpp @@ -51,12 +51,12 @@ namespace pkpy{ PyVar Generator::next(VM* vm){ if(state == 2) return vm->StopIteration; // reset frame._sp_base - frame._sp_base = vm->s_data._sp; - frame._locals.a = vm->s_data._sp; + lf->frame._sp_base = vm->s_data._sp; + lf->frame._locals.a = vm->s_data._sp; // restore the context for(PyVar obj: s_backup) vm->s_data.push(obj); // relocate stack objects (their addresses become invalid) - for(PyVar* p=frame.actual_sp_base(); p!=vm->s_data.end(); p++){ + for(PyVar* p=lf->frame.actual_sp_base(); p!=vm->s_data.end(); p++){ if(p->type == VM::tp_stack_memory){ // TODO: refactor this int count = p->as().count; @@ -67,7 +67,8 @@ namespace pkpy{ } } s_backup.clear(); - vm->callstack.emplace(std::move(frame)); + vm->callstack.pushx(lf); + lf = nullptr; PyVar ret; try{ @@ -79,10 +80,16 @@ namespace pkpy{ if(ret == PY_OP_YIELD){ // backup the context - frame = std::move(vm->callstack.top()); + lf = vm->callstack.popx(); ret = vm->s_data.popx(); - for(PyVar obj: frame.stack_view(&vm->s_data)) s_backup.push_back(obj); - vm->__pop_frame(); + for(PyVar obj: lf->frame.stack_view(&vm->s_data)) s_backup.push_back(obj); + vm->s_data.reset(lf->frame._sp_base); +// TODO: should we add this snippet here? +// #if PK_ENABLE_PROFILER +// if(!_next_breakpoint.empty() && callstack.size()<_next_breakpoint.callstack_size){ +// _next_breakpoint = NextBreakpoint(); +// } +// #endif state = 1; if(ret == vm->StopIteration) state = 2; return ret; @@ -116,7 +123,7 @@ namespace pkpy{ }); } -PyVar VM::__py_generator(Frame&& frame, ArgsView buffer){ +PyVar VM::__py_generator(LinkedFrame* frame, ArgsView buffer){ return vm->new_user_object(std::move(frame), buffer); } diff --git a/src/vm.cpp b/src/vm.cpp index 9208b7a7..c492ec39 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -1093,8 +1093,9 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){ case FuncType::GENERATOR: __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl); s_data.reset(p0); + callstack.emplace(nullptr, co, fn._module, callable, nullptr); return __py_generator( - Frame(nullptr, co, fn._module, callable, nullptr), + callstack.popx(), ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals) ); #if PK_DEBUG_EXTRA_CHECK @@ -1644,9 +1645,7 @@ void NextBreakpoint::_step(VM* vm){ #endif void VM::__pop_frame(){ - Frame& frame = callstack.top(); - s_data.reset(frame._sp_base); - frame.free_unwind_target(); + s_data.reset(callstack.top()._sp_base); callstack.pop(); #if PK_ENABLE_PROFILER