mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 03:50:16 +00:00
162 lines
4.2 KiB
C++
162 lines
4.2 KiB
C++
#pragma once
|
|
|
|
#include "codeobject.h"
|
|
|
|
namespace pkpy{
|
|
|
|
static THREAD_LOCAL uint64_t kFrameGlobalId = 0;
|
|
|
|
struct Frame {
|
|
std::vector<PyObject*> _data;
|
|
int _ip = -1;
|
|
int _next_ip = 0;
|
|
|
|
const CodeObject* co;
|
|
PyObject* _module;
|
|
NameDict_ _locals;
|
|
NameDict_ _closure;
|
|
const uint64_t id;
|
|
std::vector<std::pair<int, std::vector<PyObject*>>> s_try_block;
|
|
const NameDict* names[5]; // name resolution array, zero terminated
|
|
|
|
NameDict& f_locals() noexcept { return *_locals; }
|
|
NameDict& f_globals() noexcept { return _module->attr(); }
|
|
|
|
Frame(const CodeObject_& co, PyObject* _module, PyObject* builtins, NameDict_ _locals=nullptr, NameDict_ _closure=nullptr)
|
|
: co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) {
|
|
memset(names, 0, sizeof(names));
|
|
int i = 0;
|
|
if(_locals != nullptr) names[i++] = _locals.get();
|
|
if(_closure != nullptr) names[i++] = _closure.get();
|
|
names[i++] = &_module->attr(); // borrowed reference
|
|
if(builtins != nullptr){
|
|
names[i++] = &builtins->attr(); // borrowed reference
|
|
}
|
|
}
|
|
|
|
const Bytecode& next_bytecode() {
|
|
_ip = _next_ip++;
|
|
return co->codes[_ip];
|
|
}
|
|
|
|
Str snapshot(){
|
|
int line = co->codes[_ip].line;
|
|
return co->src->snapshot(line);
|
|
}
|
|
|
|
Str stack_info(){
|
|
StrStream ss;
|
|
ss << "[";
|
|
for(int i=0; i<_data.size(); i++){
|
|
ss << (i64)_data[i];
|
|
if(i != _data.size()-1) ss << ", ";
|
|
}
|
|
ss << "]";
|
|
return ss.str();
|
|
}
|
|
|
|
void pop(){
|
|
#if DEBUG_EXTRA_CHECK
|
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
|
#endif
|
|
_data.pop_back();
|
|
}
|
|
|
|
PyObject* popx(){
|
|
#if DEBUG_EXTRA_CHECK
|
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
|
#endif
|
|
PyObject* ret = _data.back();
|
|
_data.pop_back();
|
|
return ret;
|
|
}
|
|
|
|
PyObject*& top(){
|
|
#if DEBUG_EXTRA_CHECK
|
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
|
#endif
|
|
return _data.back();
|
|
}
|
|
|
|
PyObject*& top_1(){
|
|
#if DEBUG_EXTRA_CHECK
|
|
if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
|
|
#endif
|
|
return _data[_data.size()-2];
|
|
}
|
|
|
|
PyObject*& top_n(int n){
|
|
n += 1;
|
|
#if DEBUG_EXTRA_CHECK
|
|
if(_data.size() < n) throw std::runtime_error("_data.size() < n");
|
|
#endif
|
|
return _data[_data.size()-n];
|
|
}
|
|
|
|
template<typename T>
|
|
void push(T&& obj){ _data.push_back(std::forward<T>(obj)); }
|
|
|
|
void jump_abs(int i){ _next_ip = i; }
|
|
void jump_rel(int i){ _next_ip += i; }
|
|
|
|
void on_try_block_enter(){
|
|
s_try_block.emplace_back(co->codes[_ip].block, _data);
|
|
}
|
|
|
|
void on_try_block_exit(){
|
|
s_try_block.pop_back();
|
|
}
|
|
|
|
bool jump_to_exception_handler(){
|
|
if(s_try_block.empty()) return false;
|
|
PyObject* obj = popx();
|
|
auto& p = s_try_block.back();
|
|
_data = std::move(p.second);
|
|
_data.push_back(obj);
|
|
_next_ip = co->blocks[p.first].end;
|
|
on_try_block_exit();
|
|
return true;
|
|
}
|
|
|
|
int _exit_block(int i){
|
|
if(co->blocks[i].type == FOR_LOOP) pop();
|
|
else if(co->blocks[i].type == TRY_EXCEPT) on_try_block_exit();
|
|
return co->blocks[i].parent;
|
|
}
|
|
|
|
void jump_abs_break(int target){
|
|
const Bytecode& prev = co->codes[_ip];
|
|
int i = prev.block;
|
|
_next_ip = target;
|
|
if(_next_ip >= co->codes.size()){
|
|
while(i>=0) i = _exit_block(i);
|
|
}else{
|
|
const Bytecode& next = co->codes[target];
|
|
while(i>=0 && i!=next.block) i = _exit_block(i);
|
|
if(i!=next.block) throw std::runtime_error("invalid jump");
|
|
}
|
|
}
|
|
|
|
Args popx_n_reversed(int n){
|
|
Args v(n);
|
|
for(int i=n-1; i>=0; i--) v[i] = popx();
|
|
return v;
|
|
}
|
|
|
|
void pop_n(int n){
|
|
_data.resize(_data.size()-n);
|
|
}
|
|
|
|
void _mark() const {
|
|
for(PyObject* obj : _data) OBJ_MARK(obj);
|
|
OBJ_MARK(_module);
|
|
_locals->_mark();
|
|
_closure->_mark();
|
|
for(auto& p : s_try_block){
|
|
for(PyObject* obj : p.second) OBJ_MARK(obj);
|
|
}
|
|
co->_mark();
|
|
}
|
|
};
|
|
|
|
}; // namespace pkpy
|