2024-02-17 22:32:30 +08:00

138 lines
4.5 KiB
C++

#pragma once
#include "codeobject.h"
#include "common.h"
#include "memory.h"
#include "obj.h"
#include "vector.h"
namespace pkpy{
// weak reference fast locals
struct FastLocals{
// this is a weak reference
const NameDictInt* varnames_inv;
PyObject** a;
int size() const{ return varnames_inv->size();}
PyObject*& operator[](int i){ return a[i]; }
PyObject* operator[](int i) const { return a[i]; }
FastLocals(const CodeObject* co, PyObject** a): varnames_inv(&co->varnames_inv), a(a) {}
FastLocals(const FastLocals& other): varnames_inv(other.varnames_inv), a(other.a) {}
PyObject** try_get_name(StrName name);
NameDict_ to_namedict();
PyObject** begin() const { return a; }
PyObject** end() const { return a + size(); }
};
template<size_t MAX_SIZE>
struct ValueStackImpl {
// We allocate extra MAX_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
PyObject* _begin[MAX_SIZE + MAX_SIZE/128];
PyObject** _sp;
PyObject** _max_end;
static constexpr size_t max_size() { return MAX_SIZE; }
ValueStackImpl(): _sp(_begin), _max_end(_begin + MAX_SIZE) {}
PyObject*& top(){ return _sp[-1]; }
PyObject* top() const { return _sp[-1]; }
PyObject*& second(){ return _sp[-2]; }
PyObject* second() const { return _sp[-2]; }
PyObject*& third(){ return _sp[-3]; }
PyObject* third() const { return _sp[-3]; }
PyObject*& peek(int n){ return _sp[-n]; }
PyObject* peek(int n) const { return _sp[-n]; }
void push(PyObject* v){ *_sp++ = v; }
void pop(){ --_sp; }
PyObject* popx(){ return *--_sp; }
ArgsView view(int n){ return ArgsView(_sp-n, _sp); }
void shrink(int n){ _sp -= n; }
int size() const { return _sp - _begin; }
bool empty() const { return _sp == _begin; }
PyObject** begin() { return _begin; }
PyObject** end() { return _sp; }
void reset(PyObject** sp) {
#if PK_DEBUG_EXTRA_CHECK
if(sp < _begin || sp > _begin + MAX_SIZE) PK_FATAL_ERROR();
#endif
_sp = sp;
}
void clear() { _sp = _begin; }
bool is_overflow() const { return _sp >= _max_end; }
PyObject* operator[](int i) const { return _begin[i]; }
PyObject*& operator[](int i) { return _begin[i]; }
ValueStackImpl(const ValueStackImpl&) = delete;
ValueStackImpl(ValueStackImpl&&) = delete;
ValueStackImpl& operator=(const ValueStackImpl&) = delete;
ValueStackImpl& operator=(ValueStackImpl&&) = delete;
};
using ValueStack = ValueStackImpl<PK_VM_STACK_SIZE>;
struct Frame {
int _ip = -1;
int _next_ip = 0;
ValueStack* _s;
// This is for unwinding only, use `actual_sp_base()` for value stack access
PyObject** _sp_base;
const CodeObject* co;
PyObject* _module;
PyObject* _callable; // weak ref
FastLocals _locals;
NameDict& f_globals() noexcept { return _module->attr(); }
PyObject* f_closure_try_get(StrName name);
Frame(ValueStack* _s, PyObject** p0, const CodeObject* co, PyObject* _module, PyObject* _callable)
: _s(_s), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, p0) { }
Frame(ValueStack* _s, PyObject** p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals)
: _s(_s), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals) { }
Frame(ValueStack* _s, PyObject** p0, const CodeObject_& co, PyObject* _module)
: _s(_s), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0) {}
Bytecode next_bytecode() {
_ip = _next_ip++;
#if PK_DEBUG_EXTRA_CHECK
if(_ip >= co->codes.size()) PK_FATAL_ERROR();
#endif
return co->codes[_ip];
}
PyObject** actual_sp_base() const { return _locals.a; }
int stack_size() const { return _s->_sp - actual_sp_base(); }
ArgsView stack_view() const { return ArgsView(actual_sp_base(), _s->_sp); }
void jump_abs(int i){ _next_ip = i; }
bool jump_to_exception_handler();
int _exit_block(int i);
void jump_abs_break(int target);
void _gc_mark() const {
PK_OBJ_MARK(_module);
co->_gc_mark();
// Frame could be stored in a generator, so mark _callable for safety
if(_callable != nullptr) PK_OBJ_MARK(_callable);
}
};
struct FrameId{
std::vector<pkpy::Frame>* data;
int index;
FrameId(std::vector<pkpy::Frame>* data, int index) : data(data), index(index) {}
Frame* operator->() const { return &data->operator[](index); }
Frame* get() const { return &data->operator[](index); }
};
}; // namespace pkpy