mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
update gc
This commit is contained in:
parent
78b73998da
commit
6a9d220433
@ -1,8 +1,12 @@
|
||||
class dict:
|
||||
def __init__(self, capacity=13):
|
||||
self._capacity = capacity
|
||||
def __init__(self, mapping=None):
|
||||
self._capacity = 16
|
||||
self._a = [None] * self._capacity
|
||||
self._len = 0
|
||||
|
||||
if mapping is not None:
|
||||
for k,v in mapping:
|
||||
self[k] = v
|
||||
|
||||
def __len__(self):
|
||||
return self._len
|
||||
|
11
src/ceval.h
11
src/ceval.h
@ -186,11 +186,14 @@ inline PyObject* VM::run_frame(Frame* frame){
|
||||
frame->push(VAR(frame->pop_n_values_reversed(this, byte.arg).to_list()));
|
||||
continue;
|
||||
case OP_BUILD_MAP: {
|
||||
Args items = frame->pop_n_values_reversed(this, byte.arg*2);
|
||||
PyObject* obj = call(builtins->attr("dict"), no_arg());
|
||||
for(int i=0; i<items.size(); i+=2){
|
||||
call(obj, __setitem__, Args{items[i], items[i+1]});
|
||||
List list(byte.arg);
|
||||
for(int i=0; i<byte.arg; i++){
|
||||
PyObject* value = frame->pop_value(this);
|
||||
PyObject* key = frame->pop_value(this);
|
||||
list[i] = VAR(Tuple({key, value}));
|
||||
}
|
||||
PyObject* d_arg = VAR(std::move(list));
|
||||
PyObject* obj = call(builtins->attr("dict"), Args{d_arg});
|
||||
frame->push(obj);
|
||||
} continue;
|
||||
case OP_BUILD_SET: {
|
||||
|
39
src/gc.h
39
src/gc.h
@ -1,59 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "obj.h"
|
||||
#include "codeobject.h"
|
||||
#include "namedict.h"
|
||||
|
||||
namespace pkpy {
|
||||
struct ManagedHeap{
|
||||
std::vector<PyObject*> _no_gc;
|
||||
std::vector<PyObject*> gen;
|
||||
int counter = 0;
|
||||
|
||||
int gc_threshold = 700;
|
||||
int gc_counter = 0;
|
||||
|
||||
template<typename T>
|
||||
PyObject* gcnew(Type type, T&& val){
|
||||
PyObject* obj = new Py_<std::decay_t<T>>(type, std::forward<T>(val));
|
||||
gen.push_back(obj);
|
||||
counter++;
|
||||
gc_counter++;
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
PyObject* _new(Type type, T&& val){
|
||||
return gcnew<T>(type, std::forward<T>(val));
|
||||
PyObject* obj = new Py_<std::decay_t<T>>(type, std::forward<T>(val));
|
||||
obj->gc.enabled = false;
|
||||
_no_gc.push_back(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
int sweep(){
|
||||
~ManagedHeap(){
|
||||
for(PyObject* obj: _no_gc) delete obj;
|
||||
}
|
||||
|
||||
int sweep(VM* vm){
|
||||
std::vector<PyObject*> alive;
|
||||
for(PyObject* obj: gen){
|
||||
if(obj->gc.marked){
|
||||
obj->gc.marked = false;
|
||||
alive.push_back(obj);
|
||||
}else{
|
||||
// _delete_hook(vm, obj);
|
||||
delete obj;
|
||||
}
|
||||
}
|
||||
|
||||
// clear _no_gc marked flag
|
||||
for(PyObject* obj: _no_gc) obj->gc.marked = false;
|
||||
|
||||
int freed = gen.size() - alive.size();
|
||||
gen.clear();
|
||||
gen.swap(alive);
|
||||
return freed;
|
||||
}
|
||||
|
||||
void _delete_hook(VM* vm, PyObject* obj);
|
||||
|
||||
void _auto_collect(VM* vm){
|
||||
if(counter > 1000){
|
||||
counter = 0;
|
||||
collect(vm);
|
||||
}
|
||||
if(gc_counter < gc_threshold) return;
|
||||
gc_counter = 0;
|
||||
collect(vm);
|
||||
gc_threshold = gen.size() * 2;
|
||||
}
|
||||
|
||||
int collect(VM* vm){
|
||||
mark(vm);
|
||||
return sweep();
|
||||
int freed = sweep(vm);
|
||||
// std::cout << "GC: " << freed << " objects freed" << std::endl;
|
||||
return freed;
|
||||
}
|
||||
|
||||
void mark(VM* vm);
|
||||
};
|
||||
|
||||
|
||||
inline void NameDict::_mark(){
|
||||
for(uint16_t i=0; i<_capacity; i++){
|
||||
if(_items[i].first.empty()) continue;
|
||||
|
@ -72,7 +72,7 @@ inline void BaseIter::_mark() {
|
||||
|
||||
inline void Generator::_mark(){
|
||||
BaseIter::_mark();
|
||||
frame->_mark();
|
||||
if(frame!=nullptr) frame->_mark();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -91,8 +91,9 @@ public:
|
||||
};
|
||||
|
||||
struct GCHeader {
|
||||
bool enabled; // whether this object is managed by GC
|
||||
bool marked; // whether this object is marked
|
||||
GCHeader() : marked(false) {}
|
||||
GCHeader() : enabled(true), marked(false) {}
|
||||
};
|
||||
|
||||
struct PyObject {
|
||||
@ -135,7 +136,6 @@ struct Py_ : PyObject {
|
||||
|
||||
void _mark() override {
|
||||
if(gc.marked) return;
|
||||
// std::cout << "marking " << type << std::endl;
|
||||
gc.marked = true;
|
||||
if(_attr != nullptr) _attr->_mark();
|
||||
pkpy::_mark<T>(_value); // handle PyObject* inside _value `T`
|
||||
|
@ -88,8 +88,7 @@ inline void init_builtins(VM* _vm) {
|
||||
i64 lhs = CAST(i64, args[0]);
|
||||
i64 rhs = CAST(i64, args[1]);
|
||||
if(rhs == 0) vm->ZeroDivisionError();
|
||||
Tuple t = Tuple{VAR(lhs/rhs), VAR(lhs%rhs)};
|
||||
return VAR(std::move(t));
|
||||
return VAR(Tuple({VAR(lhs/rhs), VAR(lhs%rhs)}));
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) {
|
||||
@ -146,7 +145,7 @@ inline void init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<1>("hex", [](VM* vm, Args& args) {
|
||||
std::stringstream ss;
|
||||
StrStream ss;
|
||||
ss << std::hex << CAST(i64, args[0]);
|
||||
return VAR("0x" + ss.str());
|
||||
});
|
||||
@ -649,8 +648,7 @@ struct ReMatch {
|
||||
|
||||
vm->bind_method<0>(type, "span", [](VM* vm, Args& args) {
|
||||
auto& self = CAST(ReMatch&, args[0]);
|
||||
Tuple t = Tuple{VAR(self.start), VAR(self.end)};
|
||||
return VAR(std::move(t));
|
||||
return VAR(Tuple({VAR(self.start), VAR(self.end)}));
|
||||
});
|
||||
|
||||
vm->bind_method<1>(type, "group", [](VM* vm, Args& args) {
|
||||
|
13
src/vm.h
13
src/vm.h
@ -881,15 +881,14 @@ inline void VM::_error(Exception e){
|
||||
|
||||
inline PyObject* VM::_exec(){
|
||||
Frame* frame = top_frame();
|
||||
i64 base_id = frame->id;
|
||||
PyObject* ret = nullptr;
|
||||
const i64 base_id = frame->id;
|
||||
bool need_raise = false;
|
||||
|
||||
while(true){
|
||||
if(frame->id < base_id) UNREACHABLE();
|
||||
try{
|
||||
if(need_raise){ need_raise = false; _raise(); }
|
||||
ret = run_frame(frame);
|
||||
PyObject* ret = run_frame(frame);
|
||||
if(ret == _py_op_yield) return _py_op_yield;
|
||||
if(ret != _py_op_call){
|
||||
if(frame->id == base_id){ // [ frameBase<- ]
|
||||
@ -922,11 +921,15 @@ inline PyObject* VM::_exec(){
|
||||
}
|
||||
|
||||
inline void ManagedHeap::mark(VM *vm) {
|
||||
vm->_modules._mark();
|
||||
for(auto& t: vm->_all_types) t.obj->_mark();
|
||||
for(PyObject* obj: _no_gc) OBJ_MARK(obj);
|
||||
for(auto& frame : vm->callstack.data()){
|
||||
frame->_mark();
|
||||
}
|
||||
}
|
||||
|
||||
inline void ManagedHeap::_delete_hook(VM *vm, PyObject *obj){
|
||||
Type t = OBJ_GET(Type, vm->_t(obj));
|
||||
std::cout << "delete " << vm->_all_types[t].name << " at " << obj << std::endl;
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
@ -42,4 +42,7 @@ d1 = {1:2, 3:4}
|
||||
d2 = {3:4, 1:2}
|
||||
d3 = {1:2, 3:4, 5:6}
|
||||
assert d1 == d2
|
||||
assert d1 != d3
|
||||
assert d1 != d3
|
||||
|
||||
a = dict([(1, 2), (3, 4)])
|
||||
assert a == {1: 2, 3: 4}
|
@ -3,12 +3,12 @@ a = {
|
||||
'b': 2,
|
||||
'c': None,
|
||||
'd': [1, 2, 3],
|
||||
# 'e': {
|
||||
# 'a': 1,
|
||||
# 'b': 2,
|
||||
# 'c': None,
|
||||
# 'd': [1, 2, 3],
|
||||
# },
|
||||
'e': {
|
||||
'a': 1,
|
||||
'b': 2,
|
||||
'c': None,
|
||||
'd': [1, 2, 3],
|
||||
},
|
||||
"f": 'This is a string',
|
||||
'g': [True, False, None],
|
||||
'h': False
|
||||
|
Loading…
x
Reference in New Issue
Block a user