move gc.h

This commit is contained in:
blueloveTH 2024-06-19 13:39:37 +08:00
parent f06f7e21c9
commit e1e3e208cb
17 changed files with 365 additions and 223 deletions

View File

@ -9,7 +9,7 @@ order: 0
Sometimes you need to use the following code to prevent the gc from collecting objects. Sometimes you need to use the following code to prevent the gc from collecting objects.
```cpp ```cpp
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->gc_scope_lock();
``` ```
The scope lock is required if you create a PyVar 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.
@ -34,7 +34,7 @@ The scope lock prevents this from happening.
void some_func(VM* vm){ 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->gc_scope_lock();
PyVar iter = vm->py_iter(obj); PyVar iter = vm->py_iter(obj);
PyVar next = vm->py_next(iter); PyVar next = vm->py_next(iter);
} }

View File

@ -111,7 +111,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
}; };
_1 = new_object<NativeFunc>(tp_native_func, fset, 2, field); _1 = new_object<NativeFunc>(tp_native_func, fset, 2, field);
} }
PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1); PyObject* prop = new_object<Property>(tp_property, _0, _1).get();
obj->attr().set(StrName(name_sv), prop); obj->attr().set(StrName(name_sv), prop);
return prop; return prop;
} }

View File

@ -0,0 +1,40 @@
#include "pocketpy/objects/object.h"
#include "pocketpy/objects/public.h"
#include "pocketpy/common/config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct pk_ManagedHeap{
c11_vector no_gc;
c11_vector gen;
int gc_threshold;
int gc_counter;
int gc_lock_counter;
pkpy_VM* vm;
void (*_gc_on_delete)(pkpy_VM*, PyObject*);
void (*_gc_marker_ex)(pkpy_VM*);
} pk_ManagedHeap;
void pk_ManagedHeap__ctor(pk_ManagedHeap* self, pkpy_VM* vm);
void pk_ManagedHeap__dtor(pk_ManagedHeap* self);
void pk_ManagedHeap__push_lock(pk_ManagedHeap* self);
void pk_ManagedHeap__pop_lock(pk_ManagedHeap* self);
void pk_ManagedHeap__collect_if_needed(pk_ManagedHeap* self);
int pk_ManagedHeap__collect(pk_ManagedHeap* self);
int pk_ManagedHeap__sweep(pk_ManagedHeap* self);
PyObject* pk_ManagedHeap__new(pk_ManagedHeap* self, pkpy_Type type, int size, bool gc);
// external implementation
void pk_ManagedHeap__mark(pk_ManagedHeap* self);
void pk_ManagedHeap__delete_obj(pk_ManagedHeap* self, PyObject* obj);
#ifdef __cplusplus
}
#endif

View File

@ -1,92 +0,0 @@
#pragma once
#include "pocketpy/common/config.h"
#include "pocketpy/common/vector.hpp"
#include "pocketpy/common/utils.h"
#include "pocketpy/objects/object.hpp"
#include "pocketpy/objects/namedict.hpp"
namespace pkpy {
struct ManagedHeap {
vector<PyObject*> _no_gc;
vector<PyObject*> gen;
VM* vm;
void (*_gc_on_delete)(VM*, PyObject*) = nullptr;
void (*_gc_marker_ex)(VM*) = nullptr;
ManagedHeap(VM* vm) : vm(vm) {}
int gc_threshold = PK_GC_MIN_THRESHOLD;
int gc_counter = 0;
/********************/
int _gc_lock_counter = 0;
struct ScopeLock {
PK_ALWAYS_PASS_BY_POINTER(ScopeLock)
ManagedHeap* heap;
ScopeLock(ManagedHeap* heap) : heap(heap) { heap->_gc_lock_counter++; }
~ScopeLock() { heap->_gc_lock_counter--; }
};
ScopeLock gc_scope_lock() { return ScopeLock(this); }
/********************/
template <typename T, typename... Args>
PyObject* _basic_new(Type type, Args&&... args) {
using __T = std::decay_t<T>;
static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types");
// https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
PyObject* p;
if constexpr(py_sizeof<__T> <= kPoolObjectBlockSize){
p = new (PoolObject_alloc()) PyObject(type, false);
}else{
p = new (std::malloc(py_sizeof<__T>)) PyObject(type, true);
}
new (p->_value_ptr()) T(std::forward<Args>(args)...);
// backdoor for important builtin types
if constexpr(std::is_same_v<__T, DummyInstance>) {
p->_attr = new NameDict();
} else if constexpr(std::is_same_v<__T, Type>) {
p->_attr = new NameDict();
} else if constexpr(std::is_same_v<__T, DummyModule>) {
p->_attr = new NameDict();
}
return p;
}
template <typename T, typename... Args>
PyObject* gcnew(Type type, Args&&... args) {
PyObject* p = _basic_new<T>(type, std::forward<Args>(args)...);
gen.push_back(p);
gc_counter++;
return p;
}
template <typename T, typename... Args>
PyObject* _new(Type type, Args&&... args) {
PyObject* p = _basic_new<T>(type, std::forward<Args>(args)...);
_no_gc.push_back(p);
return p;
}
void _delete(PyObject*);
#if PK_DEBUG_GC_STATS
inline static std::map<Type, int> deleted;
#endif
int sweep();
void _auto_collect();
bool _should_auto_collect() const { return gc_counter >= gc_threshold; }
int collect();
void mark();
};
} // namespace pkpy

View File

@ -0,0 +1,14 @@
#include "pocketpy/objects/object.h"
typedef struct pkpy_VM{
PyVar True;
PyVar False;
PyVar None;
PyVar NotImplemented;
PyVar Ellipsis;
} pkpy_VM;
void pkpy_VM__ctor(pkpy_VM* self);
void pkpy_VM__dtor(pkpy_VM* self);
PyObject* pkpy_VM__gcnew(pkpy_VM* self, pkpy_Type type);

View File

@ -4,7 +4,7 @@
#include "pocketpy/objects/dict.hpp" #include "pocketpy/objects/dict.hpp"
#include "pocketpy/objects/error.hpp" #include "pocketpy/objects/error.hpp"
#include "pocketpy/objects/builtins.hpp" #include "pocketpy/objects/builtins.hpp"
#include "pocketpy/interpreter/gc.hpp" #include "pocketpy/interpreter/gc.h"
#include "pocketpy/interpreter/frame.hpp" #include "pocketpy/interpreter/frame.hpp"
#include "pocketpy/interpreter/profiler.hpp" #include "pocketpy/interpreter/profiler.hpp"
@ -162,7 +162,7 @@ class VM {
VM* vm; // self reference to simplify code VM* vm; // self reference to simplify code
public: public:
ManagedHeap heap; pk_ManagedHeap heap;
ValueStack s_data; ValueStack s_data;
CallStack callstack; CallStack callstack;
vector<PyTypeInfo> _all_types; vector<PyTypeInfo> _all_types;
@ -446,7 +446,31 @@ public:
template<typename T, typename ...Args> template<typename T, typename ...Args>
PyVar new_object(Type type, Args&&... args){ PyVar new_object(Type type, Args&&... args){
static_assert(!is_sso_v<T>); static_assert(!is_sso_v<T>);
return heap.gcnew<T>(type, std::forward<Args>(args)...); static_assert(std::is_same_v<T, std::decay_t<T>>);
PyObject* p = (PyObject*)pk_ManagedHeap__new(&heap, type, py_sizeof<T>, true);
new (p->_value_ptr()) T(std::forward<Args>(args)...);
// backdoor for important builtin types
if constexpr(std::is_same_v<T, DummyInstance>
|| std::is_same_v<T, Type>
|| std::is_same_v<T, DummyModule>) {
p->_attr = new NameDict();
}
return p;
}
template<typename T, typename ...Args>
PyVar new_object_no_gc(Type type, Args&&... args){
static_assert(!is_sso_v<T>);
static_assert(std::is_same_v<T, std::decay_t<T>>);
PyObject* p = (PyObject*)pk_ManagedHeap__new(&heap, type, py_sizeof<T>, false);
new (p->_value_ptr()) T(std::forward<Args>(args)...);
// backdoor for important builtin types
if constexpr(std::is_same_v<T, DummyInstance>
|| std::is_same_v<T, Type>
|| std::is_same_v<T, DummyModule>) {
p->_attr = new NameDict();
}
return p;
} }
#endif #endif
@ -456,7 +480,14 @@ public:
if(it == nullptr) PK_FATAL_ERROR("T not found in cxx_typeid_map\n") if(it == nullptr) PK_FATAL_ERROR("T not found in cxx_typeid_map\n")
return *it; return *it;
} }
/********** old heap op **********/
struct HeapScopeLock {
PK_ALWAYS_PASS_BY_POINTER(HeapScopeLock)
pk_ManagedHeap* heap;
HeapScopeLock(pk_ManagedHeap* heap) : heap(heap) { pk_ManagedHeap__push_lock(heap);}
~HeapScopeLock() { pk_ManagedHeap__pop_lock(heap); }
};
HeapScopeLock gc_scope_lock(){ return {&heap}; }
/********** private **********/ /********** private **********/
virtual ~VM(); virtual ~VM();
@ -569,13 +600,13 @@ PyVar py_var(VM* vm, __T&& value) {
if constexpr(is_sso_v<T>) if constexpr(is_sso_v<T>)
return PyVar(const_type, value); return PyVar(const_type, value);
else else
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value)); return vm->new_object<T>(const_type, std::forward<__T>(value));
} else { } else {
Type type = vm->_find_type_in_cxx_typeid_map<T>(); Type type = vm->_find_type_in_cxx_typeid_map<T>();
if constexpr(is_sso_v<T>) if constexpr(is_sso_v<T>)
return PyVar(type, value); return PyVar(type, value);
else else
return vm->heap.gcnew<T>(type, std::forward<__T>(value)); return vm->new_object<T>(type, std::forward<__T>(value));
} }
} }
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "stdint.h" #include "stdint.h"
#include "stdbool.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -15,10 +16,24 @@ struct pkpy_G {
pkpy_VM* vm; pkpy_VM* vm;
} extern pkpy_g; } extern pkpy_g;
void py_initialize();
void py_switch_vm(const char* name);
void py_finalize();
bool py_eq(const PyVar*, const PyVar*); bool py_eq(const PyVar*, const PyVar*);
bool py_le(const PyVar*, const PyVar*); bool py_le(const PyVar*, const PyVar*);
int64_t py_hash(const PyVar*); int64_t py_hash(const PyVar*);
/* py_var */
void py_newint(PyVar*, int64_t);
void py_newfloat(PyVar*, double);
void py_newbool(PyVar*, bool);
void py_newstr(PyVar*, const char*);
void py_newstr2(PyVar*, const char*, int);
void py_newbytes(PyVar*, const uint8_t*, int);
void py_newnone(PyVar*);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -52,7 +52,7 @@ void VM::__op_unpack_sequence(uint16_t arg) {
ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size())); ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size()));
} }
} else { } else {
auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! auto _lock = gc_scope_lock(); // lock the gc via RAII!!
_0 = py_iter(_0); _0 = py_iter(_0);
const PyTypeInfo* ti = _tp_info(_0); const PyTypeInfo* ti = _tp_info(_0);
for(int i = 0; i < arg; i++) { for(int i = 0; i < arg; i++) {
@ -802,7 +802,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH() case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH()
case OP_CALL: { case OP_CALL: {
if(heap._should_auto_collect()) heap._auto_collect(); pk_ManagedHeap__collect_if_needed(&heap);
PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC
(byte.arg >> 8) & 0xFF, // KWARGC (byte.arg >> 8) & 0xFF, // KWARGC
true); true);
@ -814,7 +814,7 @@ PyVar VM::__run_top_frame() {
} }
DISPATCH() DISPATCH()
case OP_CALL_TP: { case OP_CALL_TP: {
if(heap._should_auto_collect()) heap._auto_collect(); pk_ManagedHeap__collect_if_needed(&heap);
PyVar _0; PyVar _0;
PyVar _1; PyVar _1;
PyVar _2; PyVar _2;
@ -1000,7 +1000,7 @@ PyVar VM::__run_top_frame() {
} }
DISPATCH() DISPATCH()
case OP_UNPACK_EX: { case OP_UNPACK_EX: {
auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! auto _lock = gc_scope_lock(); // lock the gc via RAII!!
PyVar _0 = py_iter(POPX()); PyVar _0 = py_iter(POPX());
const PyTypeInfo* _ti = _tp_info(_0); const PyTypeInfo* _ti = _tp_info(_0);
PyVar _1; PyVar _1;

109
src/interpreter/gc.c Normal file
View File

@ -0,0 +1,109 @@
#include "pocketpy/interpreter/gc.h"
#include "pocketpy/common/memorypool.h"
void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pkpy_VM *vm){
c11_vector__ctor(&self->no_gc, sizeof(PyObject*));
c11_vector__ctor(&self->gen, sizeof(PyObject*));
self->gc_threshold = PK_GC_MIN_THRESHOLD;
self->gc_counter = 0;
self->gc_lock_counter = 0;
self->vm = vm;
self->_gc_on_delete = NULL;
self->_gc_marker_ex = NULL;
}
void pk_ManagedHeap__dtor(pk_ManagedHeap *self){
for(int i = 0; i < self->gen.count; i++){
PyObject* obj = c11__getitem(PyObject*, &self->gen, i);
pk_ManagedHeap__delete_obj(self, obj);
}
for(int i = 0; i < self->no_gc.count; i++){
PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
pk_ManagedHeap__delete_obj(self, obj);
}
c11_vector__dtor(&self->no_gc);
c11_vector__dtor(&self->gen);
}
void pk_ManagedHeap__push_lock(pk_ManagedHeap *self){
self->gc_lock_counter++;
}
void pk_ManagedHeap__pop_lock(pk_ManagedHeap *self){
self->gc_lock_counter--;
}
void pk_ManagedHeap__collect_if_needed(pk_ManagedHeap *self){
if(self->gc_counter < self->gc_threshold) return;
if(self->gc_lock_counter > 0) return;
self->gc_counter = 0;
pk_ManagedHeap__collect(self);
self->gc_threshold = self->gen.count * 2;
if(self->gc_threshold < PK_GC_MIN_THRESHOLD){
self->gc_threshold = PK_GC_MIN_THRESHOLD;
}
}
int pk_ManagedHeap__collect(pk_ManagedHeap *self){
assert(self->gc_lock_counter == 0);
pk_ManagedHeap__mark(self);
int freed = pk_ManagedHeap__sweep(self);
return freed;
}
int pk_ManagedHeap__sweep(pk_ManagedHeap *self){
c11_vector alive;
c11_vector__ctor(&alive, sizeof(PyObject*));
c11_vector__reserve(&alive, self->gen.count / 2);
for(int i = 0; i < self->gen.count; i++){
PyObject* obj = c11__getitem(PyObject*, &self->gen, i);
if(obj->gc_marked) {
obj->gc_marked = false;
c11_vector__push(PyObject*, &alive, obj);
} else {
if(self->_gc_on_delete){
self->_gc_on_delete(self->vm, obj);
}
pk_ManagedHeap__delete_obj(self, obj);
}
}
// clear _no_gc marked flag
for(int i=0; i<self->no_gc.count; i++){
PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
obj->gc_marked = false;
}
int freed = self->gen.count - alive.count;
// destroy old gen
c11_vector__dtor(&self->gen);
// move alive to gen
self->gen = alive;
PoolObject_shrink_to_fit();
return freed;
}
PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, pkpy_Type type, int size, bool gc){
PyObject* obj;
// TODO: can we use compile time check?
if(size <= kPoolObjectBlockSize){
obj = PoolObject_alloc();
PyObject__ctor(obj, type, false);
}else{
obj = malloc(size);
PyObject__ctor(obj, type, true);
}
// TODO: can we use compile time check?
if(gc){
c11_vector__push(PyObject*, &self->gen, obj);
self->gc_counter++;
}else{
c11_vector__push(PyObject*, &self->no_gc, obj);
}
return obj;
}

View File

@ -1,56 +0,0 @@
#include "pocketpy/interpreter/gc.hpp"
namespace pkpy {
int ManagedHeap::sweep() {
vector<PyObject*> alive;
alive.reserve(gen.size() / 2);
for(PyObject* obj: gen) {
if(obj->gc_marked) {
obj->gc_marked = false;
alive.push_back(obj);
} else {
#if PK_DEBUG_GC_STATS
deleted[obj->type] += 1;
#endif
if(_gc_on_delete) _gc_on_delete(vm, obj);
_delete(obj);
}
}
// clear _no_gc marked flag
for(PyObject* obj: _no_gc)
obj->gc_marked = false;
int freed = gen.size() - alive.size();
#if PK_DEBUG_GC_STATS
for(auto& [type, count]: deleted) {
std::cout << "GC: " << _type_name(vm, type).sv() << "=" << count << std::endl;
}
std::cout << "GC: " << alive.size() << "/" << gen.size() << " (" << freed << " freed)" << std::endl;
deleted.clear();
#endif
gen.clear();
gen.swap(alive);
PoolObject_shrink_to_fit();
return freed;
}
void ManagedHeap::_auto_collect() {
#if !PK_DEBUG_NO_AUTO_GC
if(_gc_lock_counter > 0) return;
gc_counter = 0;
collect();
gc_threshold = gen.size() * 2;
if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD;
#endif
}
int ManagedHeap::collect() {
assert(_gc_lock_counter == 0);
mark();
int freed = sweep();
return freed;
}
} // namespace pkpy

40
src/interpreter/vm.c Normal file
View File

@ -0,0 +1,40 @@
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/objects/base.h"
void pkpy_VM__ctor(pkpy_VM* self){
self->True = (PyVar){
.type=tp_bool,
.is_ptr=true,
.extra=1,
._obj=pkpy_VM__gcnew(self, tp_bool)
};
self->False = (PyVar){
.type=tp_bool,
.is_ptr=true,
.extra=0,
._obj=pkpy_VM__gcnew(self, tp_bool)
};
self->None = (PyVar){
.type=tp_none_type,
.is_ptr=true,
._obj=pkpy_VM__gcnew(self, tp_none_type)
};
self->NotImplemented = (PyVar){
.type=tp_not_implemented_type,
.is_ptr=true,
._obj=pkpy_VM__gcnew(self, tp_not_implemented_type)
};
self->Ellipsis = (PyVar){
.type=tp_ellipsis,
.is_ptr=true,
._obj=pkpy_VM__gcnew(self, tp_ellipsis)
};
}
void pkpy_VM__dtor(pkpy_VM* self){
}

View File

@ -1,6 +1,7 @@
#include "pocketpy/interpreter/vm.hpp" #include "pocketpy/interpreter/vm.hpp"
#include "pocketpy/common/memorypool.h" #include "pocketpy/common/memorypool.h"
#include "pocketpy/objects/base.h" #include "pocketpy/objects/base.h"
#include "pocketpy/objects/public.h"
#include <cstddef> #include <cstddef>
#include <iostream> #include <iostream>
@ -77,16 +78,17 @@ struct JsonSerializer {
} }
Str serialize() { Str serialize() {
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->gc_scope_lock();
write_object(root); write_object(root);
return ss.str(); return ss.str();
} }
}; };
VM::VM(bool enable_os) : heap(this), enable_os(enable_os) { VM::VM(bool enable_os) : enable_os(enable_os) {
pkpy_g.vm = (pkpy_VM*)this; // setup the current VM
Pools_initialize(); Pools_initialize();
pkpy_StrName__initialize(); pkpy_StrName__initialize();
pkpy_g.vm = (pkpy_VM*)this; // setup the current VM pk_ManagedHeap__ctor(&heap, (pkpy_VM*)this);
static ::PyObject __true_obj = {tp_bool, false, false, NULL}; static ::PyObject __true_obj = {tp_bool, false, false, NULL};
static ::PyObject __false_obj = {tp_bool, false, false, NULL}; static ::PyObject __false_obj = {tp_bool, false, false, NULL};
@ -226,7 +228,7 @@ PyVar VM::exec(std::string_view source) { return exec(source, "main.py", EXEC_MO
PyVar VM::eval(std::string_view source) { return exec(source, "<eval>", EVAL_MODE); } PyVar VM::eval(std::string_view source) { return exec(source, "<eval>", EVAL_MODE); }
PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt) { PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt) {
PyObject* obj = heap._new<Type>(tp_type, Type(_all_types.size())); PyObject* obj = new_object_no_gc<Type>(tp_type, Type(_all_types.size())).get();
const PyTypeInfo& base_info = _all_types[base]; const PyTypeInfo& base_info = _all_types[base];
if(!base_info.subclass_enabled) { if(!base_info.subclass_enabled) {
Str error = _S("type ", base_info.name.escape(), " is not `subclass_enabled`"); Str error = _S("type ", base_info.name.escape(), " is not `subclass_enabled`");
@ -302,7 +304,7 @@ bool VM::py_callable(PyVar obj) {
} }
PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) { PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
auto _lock = heap.gc_scope_lock(); auto _lock = gc_scope_lock();
const Tuple& args_tuple = PK_OBJ_GET(Tuple, args); // from *args, it must be a tuple const Tuple& args_tuple = PK_OBJ_GET(Tuple, args); // from *args, it must be a tuple
if(is_none(key) && args_tuple.size() == 2) { if(is_none(key) && args_tuple.size() == 2) {
// fast path // fast path
@ -328,7 +330,7 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
if((this->*op)(view[i], res)) res = view[i]; if((this->*op)(view[i], res)) res = view[i];
} }
} else { } else {
auto _lock = heap.gc_scope_lock(); auto _lock = gc_scope_lock();
for(int i = 1; i < view.size(); i++) { for(int i = 1; i < view.size(); i++) {
PyVar a = call(key, view[i]); PyVar a = call(key, view[i]);
PyVar b = call(key, res); PyVar b = call(key, res);
@ -418,11 +420,8 @@ PyObject* VM::py_import(Str path, bool throw_err) {
} }
VM::~VM() { VM::~VM() {
// clear managed heap // destroy all objects
for(PyObject* obj: heap.gen) pk_ManagedHeap__dtor(&heap);
heap._delete(obj);
for(PyObject* obj: heap._no_gc)
heap._delete(obj);
// clear everything // clear everything
callstack.clear(); callstack.clear();
s_data.clear(); s_data.clear();
@ -472,7 +471,7 @@ void VM::__stack_gc_mark(PyVar* begin, PyVar* end) {
} }
List VM::py_list(PyVar it) { List VM::py_list(PyVar it) {
auto _lock = heap.gc_scope_lock(); auto _lock = gc_scope_lock();
it = py_iter(it); it = py_iter(it);
List list; List list;
const PyTypeInfo* info = _tp_info(it); const PyTypeInfo* info = _tp_info(it);
@ -566,7 +565,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals); return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
} }
auto _lock = heap.gc_scope_lock(); // for safety auto _lock = gc_scope_lock(); // for safety
PyObject* globals_obj = nullptr; PyObject* globals_obj = nullptr;
Dict* globals_dict = nullptr; Dict* globals_dict = nullptr;
@ -602,7 +601,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
locals_closure->set(CAST(Str&, k), v); locals_closure->set(CAST(Str&, k), v);
}); });
PyObject* _callable = PyObject* _callable =
heap.gcnew<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure); new_object<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure).get();
retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp); retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp);
} }
@ -722,7 +721,7 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
} }
PyObject* VM::new_module(Str name, Str package) { PyObject* VM::new_module(Str name, Str package) {
PyObject* obj = heap._new<DummyModule>(tp_module); PyObject* obj = new_object_no_gc<DummyModule>(tp_module).get();
obj->attr().set(__name__, VAR(name)); obj->attr().set(__name__, VAR(name));
obj->attr().set(__package__, VAR(package)); obj->attr().set(__package__, VAR(package));
// convert to fullname // convert to fullname
@ -872,8 +871,8 @@ void VM::__log_s_data(const char* title) {
void VM::__init_builtin_types() { void VM::__init_builtin_types() {
_all_types.emplace_back(nullptr, Type(), nullptr, "", false); // 0 is not used _all_types.emplace_back(nullptr, Type(), nullptr, "", false); // 0 is not used
_all_types.emplace_back(heap._new<Type>(tp_type, tp_object), Type(), nullptr, "object", true); _all_types.emplace_back(new_object_no_gc<Type>(tp_type, tp_object).get(), Type(), nullptr, "object", true);
_all_types.emplace_back(heap._new<Type>(tp_type, tp_type), tp_object, nullptr, "type", false); _all_types.emplace_back(new_object_no_gc<Type>(tp_type, tp_type).get(), tp_object, nullptr, "type", false);
auto validate = [](Type type, PyObject* ret) { auto validate = [](Type type, PyObject* ret) {
Type ret_t = ret->as<Type>(); Type ret_t = ret->as<Type>();
@ -945,7 +944,7 @@ void VM::__init_builtin_types() {
} }
void VM::__unpack_as_list(ArgsView args, List& list) { void VM::__unpack_as_list(ArgsView args, List& list) {
auto _lock = heap.gc_scope_lock(); auto _lock = gc_scope_lock();
for(PyVar obj: args) { for(PyVar obj: args) {
if(is_type(obj, tp_star_wrapper)) { if(is_type(obj, tp_star_wrapper)) {
const StarWrapper& w = _CAST(StarWrapper&, obj); const StarWrapper& w = _CAST(StarWrapper&, obj);
@ -965,7 +964,7 @@ void VM::__unpack_as_list(ArgsView args, List& list) {
} }
void VM::__unpack_as_dict(ArgsView args, Dict& dict) { void VM::__unpack_as_dict(ArgsView args, Dict& dict) {
auto _lock = heap.gc_scope_lock(); auto _lock = gc_scope_lock();
for(PyVar obj: args) { for(PyVar obj: args) {
if(is_type(obj, tp_star_wrapper)) { if(is_type(obj, tp_star_wrapper)) {
const StarWrapper& w = _CAST(StarWrapper&, obj); const StarWrapper& w = _CAST(StarWrapper&, obj);
@ -1359,11 +1358,11 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
} }
PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata, BindType bt) { PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata, BindType bt) {
PyObject* nf = heap.gcnew<NativeFunc>(tp_native_func, fn, argc, std::move(userdata)); PyObject* nf = new_object<NativeFunc>(tp_native_func, fn, argc, std::move(userdata)).get();
switch(bt) { switch(bt) {
case BindType::DEFAULT: break; case BindType::DEFAULT: break;
case BindType::STATICMETHOD: nf = heap.gcnew<StaticMethod>(tp_staticmethod, nf); break; case BindType::STATICMETHOD: nf = new_object<StaticMethod>(tp_staticmethod, nf).get(); break;
case BindType::CLASSMETHOD: nf = heap.gcnew<ClassMethod>(tp_classmethod, nf); break; case BindType::CLASSMETHOD: nf = new_object<ClassMethod>(tp_classmethod, nf).get(); break;
} }
if(obj != nullptr) obj->attr().set(name, nf); if(obj != nullptr) obj->attr().set(name, nf);
return nf; return nf;
@ -1383,11 +1382,11 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
FuncDecl_ decl = co->func_decls[0]; FuncDecl_ decl = co->func_decls[0];
decl->docstring = docstring; decl->docstring = docstring;
PyObject* f_obj = heap.gcnew<NativeFunc>(tp_native_func, fn, decl, std::move(userdata)); PyObject* f_obj = new_object<NativeFunc>(tp_native_func, fn, decl, std::move(userdata)).get();
switch(bt) { switch(bt) {
case BindType::STATICMETHOD: f_obj = heap.gcnew<StaticMethod>(tp_staticmethod, f_obj); break; case BindType::STATICMETHOD: f_obj = new_object<StaticMethod>(tp_staticmethod, f_obj).get(); break;
case BindType::CLASSMETHOD: f_obj = heap.gcnew<ClassMethod>(tp_classmethod, f_obj); break; case BindType::CLASSMETHOD: f_obj = new_object<ClassMethod>(tp_classmethod, f_obj).get(); break;
case BindType::DEFAULT: break; case BindType::DEFAULT: break;
} }
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj); if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
@ -1402,7 +1401,7 @@ PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, N
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1); PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
PyVar _1 = vm->None; PyVar _1 = vm->None;
if(fset != nullptr) _1 = new_object<NativeFunc>(tp_native_func, fset, 2); if(fset != nullptr) _1 = new_object<NativeFunc>(tp_native_func, fset, 2);
PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1); PyObject* prop = new_object<Property>(tp_property, _0, _1).get();
obj->attr().set(StrName(name_sv), prop); obj->attr().set(StrName(name_sv), prop);
return prop; return prop;
} }
@ -1876,29 +1875,35 @@ void Frame::_gc_mark(VM* vm) const {
vm->obj_gc_mark(_callable); vm->obj_gc_mark(_callable);
} }
void ManagedHeap::mark() { extern "C"{
for(PyObject* obj: _no_gc) void pk_ManagedHeap__mark(pk_ManagedHeap* self){
vm->__obj_gc_mark(obj); VM* vm = (VM*)self->vm;
vm->callstack.apply([this](Frame& frame) { for(int i=0; i<self->no_gc.count; i++){
frame._gc_mark(vm); PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
}); vm->__obj_gc_mark(obj);
vm->obj_gc_mark(vm->__last_exception); }
vm->obj_gc_mark(vm->__curr_class); vm->callstack.apply([vm](Frame& frame) {
vm->obj_gc_mark(vm->__c.error); frame._gc_mark(vm);
vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end()); });
if(_gc_marker_ex) _gc_marker_ex(vm); vm->obj_gc_mark(vm->__last_exception);
} vm->obj_gc_mark(vm->__curr_class);
vm->obj_gc_mark(vm->__c.error);
vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end());
if(self->_gc_marker_ex) self->_gc_marker_ex((pkpy_VM*)vm);
}
void ManagedHeap::_delete(PyObject* obj) { void pk_ManagedHeap__delete_obj(pk_ManagedHeap* self, ::PyObject* __obj){
const PyTypeInfo* ti = vm->_tp_info(obj->type); PyObject* obj = (PyObject*)__obj;
if(ti->vt._dtor) ti->vt._dtor(obj->_value_ptr()); const PyTypeInfo* ti = ((VM*)(self->vm))->_tp_info(obj->type);
if (obj->_attr) if(ti->vt._dtor) ti->vt._dtor(obj->_value_ptr());
c11_vector__dtor(obj->_attr); if (obj->_attr)
delete obj->_attr; // delete __dict__ if exists c11_vector__dtor(obj->_attr);
if(obj->gc_is_large){ delete obj->_attr; // delete __dict__ if exists
std::free(obj); if(obj->gc_is_large){
}else{ std::free(obj);
PoolObject_dealloc(obj); }else{
PoolObject_dealloc(obj);
}
} }
} }

View File

@ -151,7 +151,7 @@ void add_module_io(VM* vm) {
void add_module_os(VM* vm) { void add_module_os(VM* vm) {
PyObject* mod = vm->new_module("os"); PyObject* mod = vm->new_module("os");
PyObject* path_obj = vm->heap.gcnew<DummyInstance>(VM::tp_object); PyObject* path_obj = vm->new_object<DummyInstance>(VM::tp_object).get();
mod->attr().set("path", path_obj); mod->attr().set("path", path_obj);
// Working directory is shared by all VMs!! // Working directory is shared by all VMs!!

View File

@ -78,8 +78,8 @@ void add_module_sys(VM* vm) {
vm->setattr(mod, "version", VAR(PK_VERSION)); vm->setattr(mod, "version", VAR(PK_VERSION));
vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM])); vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM]));
PyObject* stdout_ = vm->heap.gcnew<DummyInstance>(vm->tp_object); PyObject* stdout_ = vm->new_object<DummyInstance>(vm->tp_object).get();
PyObject* stderr_ = vm->heap.gcnew<DummyInstance>(vm->tp_object); PyObject* stderr_ = vm->new_object<DummyInstance>(vm->tp_object).get();
vm->setattr(mod, "stdout", stdout_); vm->setattr(mod, "stdout", stdout_);
vm->setattr(mod, "stderr", stderr_); vm->setattr(mod, "stderr", stderr_);
@ -240,7 +240,7 @@ void add_module_dis(VM* vm) {
void add_module_gc(VM* vm) { void add_module_gc(VM* vm) {
PyObject* mod = vm->new_module("gc"); PyObject* mod = vm->new_module("gc");
vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(vm->heap.collect()))); vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(pk_ManagedHeap__collect(&vm->heap))));
} }
void add_module_enum(VM* vm) { void add_module_enum(VM* vm) {

View File

@ -94,7 +94,7 @@ void __init_builtins(VM* _vm) {
return vm->None; return vm->None;
}); });
_vm->bind_func(_vm->builtins, "super", -1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "super", -1, [](VM* vm, ArgsView args)->PyVar {
PyObject* class_arg = nullptr; PyObject* class_arg = nullptr;
PyVar self_arg = nullptr; PyVar self_arg = nullptr;
if(args.size() == 2) { if(args.size() == 2) {
@ -122,13 +122,13 @@ void __init_builtins(VM* _vm) {
return vm->new_object<Super>(vm->tp_super, self_arg, vm->_all_types[type].base); return vm->new_object<Super>(vm->tp_super, self_arg, vm->_all_types[type].base);
}); });
_vm->bind_func(_vm->builtins, "staticmethod", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "staticmethod", 1, [](VM* vm, ArgsView args)->PyVar {
PyVar func = args[0]; PyVar func = args[0];
vm->check_type(func, vm->tp_function); vm->check_type(func, vm->tp_function);
return vm->new_object<StaticMethod>(vm->tp_staticmethod, args[0]); return vm->new_object<StaticMethod>(vm->tp_staticmethod, args[0]);
}); });
_vm->bind_func(_vm->builtins, "classmethod", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "classmethod", 1, [](VM* vm, ArgsView args)->PyVar {
PyVar func = args[0]; PyVar func = args[0];
vm->check_type(func, vm->tp_function); vm->check_type(func, vm->tp_function);
return vm->new_object<ClassMethod>(vm->tp_classmethod, args[0]); return vm->new_object<ClassMethod>(vm->tp_classmethod, args[0]);
@ -380,7 +380,7 @@ void __init_builtins(VM* _vm) {
return _0._obj == _1._obj ? vm->True : vm->False; return _0._obj == _1._obj ? vm->True : vm->False;
}); });
_vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) { _vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) ->PyVar {
vm->check_type(args[0], vm->tp_type); vm->check_type(args[0], vm->tp_type);
Type t = PK_OBJ_GET(Type, args[0]); Type t = PK_OBJ_GET(Type, args[0]);
return vm->new_object<DummyInstance>(t); return vm->new_object<DummyInstance>(t);
@ -734,7 +734,7 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind_func(VM::tp_str, "join", 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_str, "join", 2, [](VM* vm, ArgsView args) {
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->gc_scope_lock();
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
SStream ss; SStream ss;
PyVar it = vm->py_iter(args[1]); // strong ref PyVar it = vm->py_iter(args[1]); // strong ref
@ -964,7 +964,7 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind_func(VM::tp_list, "extend", 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "extend", 2, [](VM* vm, ArgsView args) {
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->gc_scope_lock();
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
PyVar it = vm->py_iter(args[1]); // strong ref PyVar it = vm->py_iter(args[1]); // strong ref
const PyTypeInfo* info = vm->_tp_info(args[1]); const PyTypeInfo* info = vm->_tp_info(args[1]);
@ -1342,7 +1342,7 @@ void __init_builtins(VM* _vm) {
}); });
// tp_dict // tp_dict
_vm->bind_func(VM::tp_dict, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_dict, __new__, -1, [](VM* vm, ArgsView args)->PyVar {
Type cls_t = PK_OBJ_GET(Type, args[0]); Type cls_t = PK_OBJ_GET(Type, args[0]);
return vm->new_object<Dict>(cls_t); return vm->new_object<Dict>(cls_t);
}); });
@ -1350,7 +1350,7 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) return vm->None; if(args.size() == 1 + 0) return vm->None;
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->gc_scope_lock();
Dict& self = PK_OBJ_GET(Dict, args[0]); Dict& self = PK_OBJ_GET(Dict, args[0]);
if(is_type(args[1], vm->tp_dict)) { if(is_type(args[1], vm->tp_dict)) {
Dict& other = CAST(Dict&, args[1]); Dict& other = CAST(Dict&, args[1]);
@ -1539,7 +1539,7 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(VM::tp_exception, __new__, -1, [](VM* vm, ArgsView args) -> PyVar { _vm->bind_func(VM::tp_exception, __new__, -1, [](VM* vm, ArgsView args) -> PyVar {
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
StrName cls_name = _type_name(vm, cls); StrName cls_name = _type_name(vm, cls);
PyObject* e_obj = vm->heap.gcnew<Exception>(cls, cls_name.index); PyObject* e_obj = vm->new_object<Exception>(cls, cls_name.index).get();
e_obj->_attr = new NameDict(); e_obj->_attr = new NameDict();
e_obj->as<Exception>().self = e_obj; e_obj->as<Exception>().self = e_obj;
return e_obj; return e_obj;

View File

@ -428,7 +428,7 @@ bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->gc_scope_lock();
PK_PROTECTED( PK_PROTECTED(
PyVar _0 = vm->py_iter(vm->s_data.popx()); PyVar _0 = vm->py_iter(vm->s_data.popx());
for(int i=0; i<n; i++){ for(int i=0; i<n; i++){

36
src/public.c Normal file
View File

@ -0,0 +1,36 @@
#include "pocketpy/objects/public.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
void py_initialize(){
// initialize the global VM
}
void py_newint(PyVar* self, int64_t val){
self->type = tp_int;
self->is_ptr = false;
self->_i64 = val;
}
void py_newfloat(PyVar* self, double val){
self->type = tp_float;
self->is_ptr = false;
self->_f64 = val;
}
void py_newbool(PyVar* self, bool val){
// return a global singleton
}
void py_newnone(PyVar* self){
// return a heap object
}
void py_newstr(PyVar* self, const char* val){
// return a heap object
}
void py_newstr2(PyVar*, const char*, int);
void py_newbytes(PyVar*, const uint8_t*, int);