This commit is contained in:
blueloveTH 2024-05-12 20:34:15 +08:00
parent a37b6043d9
commit 4ab7c10ed1
5 changed files with 54 additions and 54 deletions

View File

@ -1,6 +1,6 @@
--- ---
icon: dot icon: dot
label: 'Interop with PyObject' label: 'Interop with PyVar'
order: 90 order: 90
--- ---

View File

@ -12,7 +12,7 @@ Sometimes you need to use the following code to prevent the gc from collecting o
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->heap.gc_scope_lock();
``` ```
The scope lock is required if you create a PyObject and then try to run python-level bytecodes. The scope lock is required if you create a PyVar and then try to run python-level bytecodes.
For example, you create a temporary object on the stack and then call `vm->py_next`. For example, you create a temporary object on the stack and then call `vm->py_next`.
@ -20,8 +20,8 @@ For example, you create a temporary object on the stack and then call `vm->py_ne
void some_func(VM* vm){ void some_func(VM* vm){
PyVar obj = VAR(List(5)); PyVar obj = VAR(List(5));
// unsafe // unsafe
PyObject iter = vm->py_iter(obj); PyVar iter = vm->py_iter(obj);
PyObject next = vm->py_next(iter); PyVar next = vm->py_next(iter);
} }
``` ```
@ -35,7 +35,7 @@ void some_func(VM* vm){
PyVar obj = VAR(List(5)); PyVar obj = VAR(List(5));
// safe // safe
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->heap.gc_scope_lock();
PyObject iter = vm->py_iter(obj); PyVar iter = vm->py_iter(obj);
PyObject next = vm->py_next(iter); PyVar next = vm->py_next(iter);
} }
``` ```

View File

@ -4,28 +4,28 @@ namespace pkpy
{ {
struct PyDequeIter // Iterator for the deque type struct PyDequeIter // Iterator for the deque type
{ {
PyObject *ref; PyVar ref;
bool is_reversed; bool is_reversed;
std::deque<PyObject *>::iterator begin, end, current; std::deque<PyVar >::iterator begin, end, current;
std::deque<PyObject *>::reverse_iterator rbegin, rend, rcurrent; std::deque<PyVar >::reverse_iterator rbegin, rend, rcurrent;
PyDequeIter(PyObject *ref, std::deque<PyObject *>::iterator begin, std::deque<PyObject *>::iterator end) PyDequeIter(PyVar ref, std::deque<PyVar >::iterator begin, std::deque<PyVar >::iterator end)
: ref(ref), begin(begin), end(end), current(begin) : ref(ref), begin(begin), end(end), current(begin)
{ {
this->is_reversed = false; this->is_reversed = false;
} }
PyDequeIter(PyObject *ref, std::deque<PyObject *>::reverse_iterator rbegin, std::deque<PyObject *>::reverse_iterator rend) PyDequeIter(PyVar ref, std::deque<PyVar >::reverse_iterator rbegin, std::deque<PyVar >::reverse_iterator rend)
: ref(ref), rbegin(rbegin), rend(rend), rcurrent(rbegin) : ref(ref), rbegin(rbegin), rend(rend), rcurrent(rbegin)
{ {
this->is_reversed = true; this->is_reversed = true;
} }
void _gc_mark() const { PK_OBJ_MARK(ref); } void _gc_mark() const { PK_OBJ_MARK(ref); }
static void _register(VM *vm, PyObject *mod, PyObject *type); static void _register(VM *vm, PyVar mod, PyVar type);
}; };
void PyDequeIter::_register(VM *vm, PyObject *mod, PyObject *type) void PyDequeIter::_register(VM *vm, PyVar mod, PyVar type)
{ {
vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject *obj) vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar obj)
{ return obj; }); { return obj; });
vm->bind__next__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject *obj) -> unsigned vm->bind__next__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar obj) -> unsigned
{ {
PyDequeIter& self = _CAST(PyDequeIter&, obj); PyDequeIter& self = _CAST(PyDequeIter&, obj);
if(self.is_reversed){ if(self.is_reversed){
@ -43,26 +43,26 @@ namespace pkpy
} }
struct PyDeque struct PyDeque
{ {
PyDeque(VM *vm, PyObject *iterable, PyObject *maxlen); // constructor PyDeque(VM *vm, PyVar iterable, PyVar maxlen); // constructor
// PyDeque members // PyDeque members
std::deque<PyObject *> dequeItems; std::deque<PyVar > dequeItems;
int maxlen = -1; // -1 means unbounded int maxlen = -1; // -1 means unbounded
bool bounded = false; // if true, maxlen is not -1 bool bounded = false; // if true, maxlen is not -1
void insertObj(bool front, bool back, int index, PyObject *item); // insert at index, used purely for internal purposes: append, appendleft, insert methods void insertObj(bool front, bool back, int index, PyVar item); // insert at index, used purely for internal purposes: append, appendleft, insert methods
PyObject *popObj(bool front, bool back, PyObject *item, VM *vm); // pop at index, used purely for internal purposes: pop, popleft, remove methods PyVar popObj(bool front, bool back, PyVar item, VM *vm); // pop at index, used purely for internal purposes: pop, popleft, remove methods
int findIndex(VM *vm, PyObject *obj, int start, int stop); // find the index of the given object in the deque int findIndex(VM *vm, PyVar obj, int start, int stop); // find the index of the given object in the deque
// Special methods // Special methods
static void _register(VM *vm, PyObject *mod, PyObject *type); // register the type static void _register(VM *vm, PyVar mod, PyVar type); // register the type
void _gc_mark() const; // needed for container types, mark all objects in the deque for gc void _gc_mark() const; // needed for container types, mark all objects in the deque for gc
}; };
void PyDeque::_register(VM *vm, PyObject *mod, PyObject *type) void PyDeque::_register(VM *vm, PyVar mod, PyVar type)
{ {
vm->bind(type, "__new__(cls, iterable=None, maxlen=None)", vm->bind(type, "__new__(cls, iterable=None, maxlen=None)",
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
Type cls_t = PK_OBJ_GET(Type, args[0]); Type cls_t = PK_OBJ_GET(Type, args[0]);
PyObject *iterable = args[1]; PyVar iterable = args[1];
PyObject *maxlen = args[2]; PyVar maxlen = args[2];
return vm->heap.gcnew<PyDeque>(cls_t, vm, iterable, maxlen); return vm->heap.gcnew<PyDeque>(cls_t, vm, iterable, maxlen);
}); });
// gets the item at the given index, if index is negative, it will be treated as index + len(deque) // gets the item at the given index, if index is negative, it will be treated as index + len(deque)
@ -149,8 +149,8 @@ namespace pkpy
{ {
auto _lock = vm->heap.gc_scope_lock(); // locking the heap auto _lock = vm->heap.gc_scope_lock(); // locking the heap
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *it = vm->py_iter(args[1]); // strong ref PyVar it = vm->py_iter(args[1]); // strong ref
PyObject *obj = vm->py_next(it); PyVar obj = vm->py_next(it);
while (obj != vm->StopIteration) while (obj != vm->StopIteration)
{ {
self.insertObj(false, true, -1, obj); self.insertObj(false, true, -1, obj);
@ -163,7 +163,7 @@ namespace pkpy
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *item = args[1]; PyVar item = args[1];
self.insertObj(false, true, -1, item); self.insertObj(false, true, -1, item);
return vm->None; return vm->None;
}); });
@ -172,7 +172,7 @@ namespace pkpy
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *item = args[1]; PyVar item = args[1];
self.insertObj(true, false, -1, item); self.insertObj(true, false, -1, item);
return vm->None; return vm->None;
}); });
@ -206,7 +206,7 @@ namespace pkpy
{ {
auto _lock = vm->heap.gc_scope_lock(); // locking the heap auto _lock = vm->heap.gc_scope_lock(); // locking the heap
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *newDequeObj = vm->new_user_object<PyDeque>(vm, vm->None, vm->None); // create the empty deque PyVar newDequeObj = vm->new_user_object<PyDeque>(vm, vm->None, vm->None); // create the empty deque
PyDeque &newDeque = _CAST(PyDeque &, newDequeObj); // cast it to PyDeque so we can use its methods PyDeque &newDeque = _CAST(PyDeque &, newDequeObj); // cast it to PyDeque so we can use its methods
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it) for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
newDeque.insertObj(false, true, -1, *it); newDeque.insertObj(false, true, -1, *it);
@ -217,7 +217,7 @@ namespace pkpy
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *obj = args[1]; PyVar obj = args[1];
int cnt = 0, sz = self.dequeItems.size(); int cnt = 0, sz = self.dequeItems.size();
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it) for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
{ {
@ -234,8 +234,8 @@ namespace pkpy
{ {
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->heap.gc_scope_lock();
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *it = vm->py_iter(args[1]); // strong ref PyVar it = vm->py_iter(args[1]); // strong ref
PyObject *obj = vm->py_next(it); PyVar obj = vm->py_next(it);
while (obj != vm->StopIteration) while (obj != vm->StopIteration)
{ {
self.insertObj(true, false, -1, obj); self.insertObj(true, false, -1, obj);
@ -249,7 +249,7 @@ namespace pkpy
{ {
// Return the position of x in the deque (at or after index start and before index stop). Returns the first match or raises ValueError if not found. // Return the position of x in the deque (at or after index start and before index stop). Returns the first match or raises ValueError if not found.
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *obj = args[1]; PyVar obj = args[1];
int start = CAST_DEFAULT(int, args[2], 0); int start = CAST_DEFAULT(int, args[2], 0);
int stop = CAST_DEFAULT(int, args[3], self.dequeItems.size()); int stop = CAST_DEFAULT(int, args[3], self.dequeItems.size());
int index = self.findIndex(vm, obj, start, stop); int index = self.findIndex(vm, obj, start, stop);
@ -262,7 +262,7 @@ namespace pkpy
{ {
// Return the position of x in the deque (at or after index start and before index stop). Returns the first match or raises ValueError if not found. // Return the position of x in the deque (at or after index start and before index stop). Returns the first match or raises ValueError if not found.
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *obj = args[1]; PyVar obj = args[1];
int start = 0, stop = self.dequeItems.size(); // default values int start = 0, stop = self.dequeItems.size(); // default values
int index = self.findIndex(vm, obj, start, stop); int index = self.findIndex(vm, obj, start, stop);
if (index != -1) if (index != -1)
@ -275,7 +275,7 @@ namespace pkpy
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
int index = CAST(int, args[1]); int index = CAST(int, args[1]);
PyObject *obj = args[2]; PyVar obj = args[2];
if (self.bounded && self.dequeItems.size() == self.maxlen) if (self.bounded && self.dequeItems.size() == self.maxlen)
vm->IndexError("deque already at its maximum size"); vm->IndexError("deque already at its maximum size");
else else
@ -287,8 +287,8 @@ namespace pkpy
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *obj = args[1]; PyVar obj = args[1];
PyObject *removed = self.popObj(false, false, obj, vm); PyVar removed = self.popObj(false, false, obj, vm);
if (removed == nullptr) if (removed == nullptr)
vm->ValueError(vm->py_repr(obj) + " is not in list"); vm->ValueError(vm->py_repr(obj) + " is not in list");
return vm->None; return vm->None;
@ -303,7 +303,7 @@ namespace pkpy
int sz = self.dequeItems.size(); int sz = self.dequeItems.size();
for (int i = 0; i < sz / 2; i++) for (int i = 0; i < sz / 2; i++)
{ {
PyObject *tmp = self.dequeItems[i]; PyVar tmp = self.dequeItems[i];
self.dequeItems[i] = self.dequeItems[sz - i - 1]; // swapping self.dequeItems[i] = self.dequeItems[sz - i - 1]; // swapping
self.dequeItems[sz - i - 1] = tmp; self.dequeItems[sz - i - 1] = tmp;
} }
@ -318,7 +318,7 @@ namespace pkpy
if (n != 0 && !self.dequeItems.empty()) // trivial case if (n != 0 && !self.dequeItems.empty()) // trivial case
{ {
PyObject *tmp; // holds the object to be rotated PyVar tmp; // holds the object to be rotated
int direction = n > 0 ? 1 : -1; int direction = n > 0 ? 1 : -1;
n = abs(n); n = abs(n);
n = n % self.dequeItems.size(); // make sure n is in range n = n % self.dequeItems.size(); // make sure n is in range
@ -362,7 +362,7 @@ namespace pkpy
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
Tuple ret(2); Tuple ret(2);
List list; List list;
for (PyObject *obj : self.dequeItems) for (PyVar obj : self.dequeItems)
{ {
list.push_back(obj); list.push_back(obj);
} }
@ -375,7 +375,7 @@ namespace pkpy
}); });
} }
/// @brief initializes a new PyDeque object, actual initialization is done in __init__ /// @brief initializes a new PyDeque object, actual initialization is done in __init__
PyDeque::PyDeque(VM *vm, PyObject *iterable, PyObject *maxlen) PyDeque::PyDeque(VM *vm, PyVar iterable, PyVar maxlen)
{ {
if (maxlen != vm->None) // fix the maxlen first if (maxlen != vm->None) // fix the maxlen first
@ -398,8 +398,8 @@ namespace pkpy
{ {
this->dequeItems.clear(); // clear the deque this->dequeItems.clear(); // clear the deque
auto _lock = vm->heap.gc_scope_lock(); // locking the heap auto _lock = vm->heap.gc_scope_lock(); // locking the heap
PyObject *it = vm->py_iter(iterable); // strong ref PyVar it = vm->py_iter(iterable); // strong ref
PyObject *obj = vm->py_next(it); PyVar obj = vm->py_next(it);
while (obj != vm->StopIteration) while (obj != vm->StopIteration)
{ {
this->insertObj(false, true, -1, obj); this->insertObj(false, true, -1, obj);
@ -407,7 +407,7 @@ namespace pkpy
} }
} }
} }
int PyDeque::findIndex(VM *vm, PyObject *obj, int start, int stop) int PyDeque::findIndex(VM *vm, PyVar obj, int start, int stop)
{ {
// the following code is special purpose normalization for this method, taken from CPython: _collectionsmodule.c file // the following code is special purpose normalization for this method, taken from CPython: _collectionsmodule.c file
if (start < 0) if (start < 0)
@ -445,7 +445,7 @@ namespace pkpy
/// @param item if front and back is not set, remove the first occurrence of item from the deque /// @param item if front and back is not set, remove the first occurrence of item from the deque
/// @param vm is needed for the py_eq /// @param vm is needed for the py_eq
/// @return PyVar if front or back is set, this is a pop operation and we return a PyVar, if front and back are not set, this is a remove operation and we return the removed item or nullptr /// @return PyVar if front or back is set, this is a pop operation and we return a PyVar, if front and back are not set, this is a remove operation and we return the removed item or nullptr
PyObject *PyDeque::popObj(bool front, bool back, PyObject *item, VM *vm) PyVar PyDeque::popObj(bool front, bool back, PyVar item, VM *vm)
{ {
// error handling // error handling
if (front && back) if (front && back)
@ -455,7 +455,7 @@ namespace pkpy
// front or back is set, we don't care about item, this is a pop operation and we return a PyVar // front or back is set, we don't care about item, this is a pop operation and we return a PyVar
if (this->dequeItems.empty()) if (this->dequeItems.empty())
throw std::runtime_error("pop from an empty deque"); // shouldn't happen throw std::runtime_error("pop from an empty deque"); // shouldn't happen
PyObject *obj; PyVar obj;
if (front) if (front)
{ {
obj = this->dequeItems.front(); obj = this->dequeItems.front();
@ -479,7 +479,7 @@ namespace pkpy
vm->IndexError("deque mutated during iteration"); vm->IndexError("deque mutated during iteration");
if (found) if (found)
{ {
PyObject *obj = *it; // keep a reference to the object for returning PyVar obj = *it; // keep a reference to the object for returning
this->dequeItems.erase(it); this->dequeItems.erase(it);
return obj; return obj;
} }
@ -493,7 +493,7 @@ namespace pkpy
/// @param index if front and back are not set, insert at the given index /// @param index if front and back are not set, insert at the given index
/// @param item the item to insert /// @param item the item to insert
/// @return true if the item was inserted successfully, false if the deque is bounded and is already at its maximum size /// @return true if the item was inserted successfully, false if the deque is bounded and is already at its maximum size
void PyDeque::insertObj(bool front, bool back, int index, PyObject *item) // assume index is not fixed using the vm->normalized_index void PyDeque::insertObj(bool front, bool back, int index, PyVar item) // assume index is not fixed using the vm->normalized_index
{ {
// error handling // error handling
if (front && back) if (front && back)
@ -534,13 +534,13 @@ namespace pkpy
/// @brief marks the deque items for garbage collection /// @brief marks the deque items for garbage collection
void PyDeque::_gc_mark() const void PyDeque::_gc_mark() const
{ {
for (PyObject *obj : this->dequeItems) for (PyVar obj : this->dequeItems)
PK_OBJ_MARK(obj); PK_OBJ_MARK(obj);
} }
/// @brief registers the PyDeque class /// @brief registers the PyDeque class
void add_module_collections(VM *vm) void add_module_collections(VM *vm)
{ {
PyObject *mod = vm->new_module("collections"); PyVar mod = vm->new_module("collections");
vm->register_user_class<PyDeque>(mod, "deque", VM::tp_object, true); vm->register_user_class<PyDeque>(mod, "deque", VM::tp_object, true);
vm->register_user_class<PyDequeIter>(mod, "_deque_iter"); vm->register_user_class<PyDequeIter>(mod, "_deque_iter");
CodeObject_ code = vm->compile(kPythonLibs_collections, "collections.py", EXEC_MODE); CodeObject_ code = vm->compile(kPythonLibs_collections, "collections.py", EXEC_MODE);

View File

@ -85,7 +85,7 @@ namespace pkpy{
}); });
} }
void DictItemsIter::_register(VM *vm, PyObject *mod, PyObject *type){ void DictItemsIter::_register(VM *vm, PyVar mod, PyVar type){
vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ return _0; }); vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ return _0; });
vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{ vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{
DictItemsIter& self = _CAST(DictItemsIter&, _0); DictItemsIter& self = _CAST(DictItemsIter&, _0);

View File

@ -1139,7 +1139,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
PK_UNREACHABLE() PK_UNREACHABLE()
} }
void VM::delattr(PyObject *_0, StrName _name){ void VM::delattr(PyVar _0, StrName _name){
const PyTypeInfo* ti = _tp_info(_0); const PyTypeInfo* ti = _tp_info(_0);
if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) return; if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) return;
if(is_tagged(_0) || !_0->is_attr_valid()) TypeError("cannot delete attribute"); if(is_tagged(_0) || !_0->is_attr_valid()) TypeError("cannot delete attribute");
@ -1564,7 +1564,7 @@ void VM::bind__len__(Type type, i64 (*f)(VM*, PyVar)){
#undef BIND_BINARY_SPECIAL #undef BIND_BINARY_SPECIAL
void Dict::_probe_0(PyObject *key, bool &ok, int &i) const{ void Dict::_probe_0(PyVar key, bool &ok, int &i) const{
ok = false; ok = false;
i64 hash = vm->py_hash(key); i64 hash = vm->py_hash(key);
i = hash & _mask; i = hash & _mask;
@ -1579,7 +1579,7 @@ void Dict::_probe_0(PyObject *key, bool &ok, int &i) const{
} }
} }
void Dict::_probe_1(PyObject *key, bool &ok, int &i) const{ void Dict::_probe_1(PyVar key, bool &ok, int &i) const{
ok = false; ok = false;
i = vm->py_hash(key) & _mask; i = vm->py_hash(key) & _mask;
while(_items[i].first != nullptr) { while(_items[i].first != nullptr) {