update gc

This commit is contained in:
blueloveTH 2023-03-27 22:23:46 +08:00
parent 06d486d2a2
commit c2ef720d90
5 changed files with 227 additions and 158 deletions

51
src/gc.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include "obj.h"
namespace pkpy {
using PyVar0 = PyObject*;
// a generational mark and sweep garbage collector
struct GC{
using Generation = std::vector<PyVar0>;
static const int kTotalGen = 3;
Generation gen[kTotalGen];
void add(PyVar0 obj){
if(!obj->need_gc) return;
gen[0].push_back(obj);
}
void sweep(int index){
Generation& g = gen[index];
if(index < kTotalGen-1){
for(int i=0; i<g.size(); i++){
if(g[i]->marked){
g[i]->marked = false;
gen[index+1].push_back(g[i]);
}else{
delete g[i];
}
}
g.clear();
}else{
Generation alive;
// the oldest generation
for(int i=0; i<g.size(); i++){
if(g[i]->marked){
g[i]->marked = false;
alive.push_back(g[i]);
}else{
delete g[i];
}
}
g = std::move(alive);
}
}
void collect(int index){
sweep(index);
}
};
} // namespace pkpy

View File

@ -230,6 +230,13 @@ while(!_keys[i].empty()) { \
} }
return v; return v;
} }
void apply_v(void(*f)(PyVar)) {
for(uint16_t i=0; i<_capacity; i++){
if(_keys[i].empty()) continue;
f(value(i));
}
}
#undef HASH_PROBE #undef HASH_PROBE
#undef _hash #undef _hash
}; };

View File

@ -88,6 +88,9 @@ public:
}; };
struct PyObject { struct PyObject {
bool need_gc;
bool marked;
/**********/
Type type; Type type;
NameDict* _attr; NameDict* _attr;
@ -96,6 +99,12 @@ struct PyObject {
inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); } inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); }
virtual void* value() = 0; virtual void* value() = 0;
virtual void mark() {
if(!need_gc || marked) return;
marked = true;
if(is_attr_valid()) attr().apply_v([](PyVar v){ v->mark(); });
}
PyObject(Type type) : type(type) {} PyObject(Type type) : type(type) {}
virtual ~PyObject() { delete _attr; } virtual ~PyObject() { delete _attr; }
}; };
@ -119,9 +128,14 @@ struct Py_ : PyObject {
} }
} }
void* value() override { return &_value; } void* value() override { return &_value; }
void mark() override {
PyObject::mark();
// extra mark for `T`
}
}; };
#define OBJ_GET(T, obj) (((Py_<T>*)((obj).get()))->_value) #define OBJ_GET(T, obj) (((Py_<T>*)(obj))->_value)
#define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__)) #define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__))
const int kTpIntIndex = 2; const int kTpIntIndex = 2;

View File

@ -5,12 +5,12 @@
#include "str.h" #include "str.h"
namespace pkpy { namespace pkpy {
using List = std::vector<PyVar>; using List = std::vector<PyObject*>;
class Args { class Args {
static THREAD_LOCAL SmallArrayPool<PyVar, 10> _pool; static THREAD_LOCAL SmallArrayPool<PyObject*, 10> _pool;
PyVar* _args; PyObject** _args;
int _size; int _size;
inline void _alloc(int n){ inline void _alloc(int n){
@ -35,14 +35,14 @@ namespace pkpy {
static pkpy::Args from_list(List&& other) noexcept { static pkpy::Args from_list(List&& other) noexcept {
Args ret(other.size()); Args ret(other.size());
memcpy((void*)ret._args, (void*)other.data(), sizeof(PyVar)*ret.size()); memcpy((void*)ret._args, (void*)other.data(), sizeof(PyObject*)*ret.size());
memset((void*)other.data(), 0, sizeof(PyVar)*ret.size()); memset((void*)other.data(), 0, sizeof(PyObject*)*ret.size());
other.clear(); other.clear();
return ret; return ret;
} }
PyVar& operator[](int i){ return _args[i]; } PyObject*& operator[](int i){ return _args[i]; }
const PyVar& operator[](int i) const { return _args[i]; } PyObject* operator[](int i) const { return _args[i]; }
Args& operator=(Args&& other) noexcept { Args& operator=(Args&& other) noexcept {
_pool.dealloc(_args, _size); _pool.dealloc(_args, _size);
@ -57,29 +57,30 @@ namespace pkpy {
List move_to_list() noexcept { List move_to_list() noexcept {
List ret(_size); List ret(_size);
memcpy((void*)ret.data(), (void*)_args, sizeof(PyVar)*_size); memcpy((void*)ret.data(), (void*)_args, sizeof(PyObject*)*_size);
memset((void*)_args, 0, sizeof(PyVar)*_size); memset((void*)_args, 0, sizeof(PyObject*)*_size);
return ret; return ret;
} }
void extend_self(const PyVar& self){ void extend_self(PyObject* self){
static_assert(std::is_standard_layout_v<PyVar>); PyObject** old_args = _args;
PyVar* old_args = _args;
int old_size = _size; int old_size = _size;
_alloc(old_size+1); _alloc(old_size+1);
_args[0] = self; _args[0] = self;
if(old_size == 0) return; if(old_size == 0) return;
memcpy((void*)(_args+1), (void*)old_args, sizeof(PyVar)*old_size); memcpy((void*)(_args+1), (void*)old_args, sizeof(PyObject*)*old_size);
memset((void*)old_args, 0, sizeof(PyVar)*old_size); memset((void*)old_args, 0, sizeof(PyObject*)*old_size);
_pool.dealloc(old_args, old_size); _pool.dealloc(old_args, old_size);
} }
~Args(){ _pool.dealloc(_args, _size); } ~Args(){ _pool.dealloc(_args, _size); }
}; };
static const Args _zero(0); inline const Args& no_arg() {
inline const Args& no_arg() { return _zero; } static const Args _zero(0);
return _zero;
}
template<typename T> template<typename T>
Args one_arg(T&& a) { Args one_arg(T&& a) {
@ -106,5 +107,5 @@ namespace pkpy {
} }
typedef Args Tuple; typedef Args Tuple;
THREAD_LOCAL SmallArrayPool<PyVar, 10> Args::_pool; THREAD_LOCAL SmallArrayPool<PyObject*, 10> Args::_pool;
} // namespace pkpy } // namespace pkpy

276
src/vm.h
View File

@ -6,22 +6,22 @@
namespace pkpy{ namespace pkpy{
#define DEF_NATIVE_2(ctype, ptype) \ #define DEF_NATIVE_2(ctype, ptype) \
template<> ctype py_cast<ctype>(VM* vm, const PyVar& obj) { \ template<> ctype py_cast<ctype>(VM* vm, PyObject* obj) { \
vm->check_type(obj, vm->ptype); \ vm->check_type(obj, vm->ptype); \
return OBJ_GET(ctype, obj); \ return OBJ_GET(ctype, obj); \
} \ } \
template<> ctype _py_cast<ctype>(VM* vm, const PyVar& obj) { \ template<> ctype _py_cast<ctype>(VM* vm, PyObject* obj) { \
return OBJ_GET(ctype, obj); \ return OBJ_GET(ctype, obj); \
} \ } \
template<> ctype& py_cast<ctype&>(VM* vm, const PyVar& obj) { \ template<> ctype& py_cast<ctype&>(VM* vm, PyObject* obj) { \
vm->check_type(obj, vm->ptype); \ vm->check_type(obj, vm->ptype); \
return OBJ_GET(ctype, obj); \ return OBJ_GET(ctype, obj); \
} \ } \
template<> ctype& _py_cast<ctype&>(VM* vm, const PyVar& obj) { \ template<> ctype& _py_cast<ctype&>(VM* vm, PyObject* obj) { \
return OBJ_GET(ctype, obj); \ return OBJ_GET(ctype, obj); \
} \ } \
PyVar py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \ PyObject* py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \
PyVar py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));} PyObject* py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));}
class Generator: public BaseIter { class Generator: public BaseIter {
std::unique_ptr<Frame> frame; std::unique_ptr<Frame> frame;
@ -30,11 +30,11 @@ public:
Generator(VM* vm, std::unique_ptr<Frame>&& frame) Generator(VM* vm, std::unique_ptr<Frame>&& frame)
: BaseIter(vm, nullptr), frame(std::move(frame)), state(0) {} : BaseIter(vm, nullptr), frame(std::move(frame)), state(0) {}
PyVar next(); PyObject* next();
}; };
struct PyTypeInfo{ struct PyTypeInfo{
PyVar obj; PyObject* obj;
Type base; Type base;
Str name; Str name;
}; };
@ -43,23 +43,27 @@ class VM {
VM* vm; // self reference for simplify code VM* vm; // self reference for simplify code
public: public:
std::stack< std::unique_ptr<Frame> > callstack; std::stack< std::unique_ptr<Frame> > callstack;
PyVar _py_op_call;
PyVar _py_op_yield;
std::vector<PyTypeInfo> _all_types; std::vector<PyTypeInfo> _all_types;
PyVar run_frame(Frame* frame); PyObject* run_frame(Frame* frame);
NameDict _modules; // loaded modules NameDict _modules; // loaded modules
std::map<StrName, Str> _lazy_modules; // lazy loaded modules std::map<StrName, Str> _lazy_modules; // lazy loaded modules
PyVar None, True, False, Ellipsis;
// singleton objects, need_gc=false
PyObject* _py_op_call;
PyObject* _py_op_yield;
PyObject* None;
PyObject* True;
PyObject* False;
PyObject* Ellipsis;
PyObject* builtins; // builtins module
PyObject* _main; // __main__ module
bool use_stdio; bool use_stdio;
std::ostream* _stdout; std::ostream* _stdout;
std::ostream* _stderr; std::ostream* _stderr;
PyVar builtins; // builtins module
PyVar _main; // __main__ module
int recursionlimit = 1000; int recursionlimit = 1000;
VM(bool use_stdio){ VM(bool use_stdio){
@ -77,7 +81,7 @@ public:
// for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i)); // for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i));
} }
PyVar asStr(const PyVar& obj){ PyObject* asStr(PyObject* obj){
PyVarOrNull f = getattr(obj, __str__, false, true); PyVarOrNull f = getattr(obj, __str__, false, true);
if(f != nullptr) return call(f); if(f != nullptr) return call(f);
return asRepr(obj); return asRepr(obj);
@ -90,7 +94,7 @@ public:
return callstack.top().get(); return callstack.top().get();
} }
PyVar asIter(const PyVar& obj){ PyObject* asIter(PyObject* obj){
if(is_type(obj, tp_native_iterator)) return obj; if(is_type(obj, tp_native_iterator)) return obj;
PyVarOrNull iter_f = getattr(obj, __iter__, false, true); PyVarOrNull iter_f = getattr(obj, __iter__, false, true);
if(iter_f != nullptr) return call(iter_f); if(iter_f != nullptr) return call(iter_f);
@ -98,25 +102,25 @@ public:
return nullptr; return nullptr;
} }
PyVar asList(const PyVar& iterable){ PyObject* asList(PyObject* iterable){
if(is_type(iterable, tp_list)) return iterable; if(is_type(iterable, tp_list)) return iterable;
return call(_t(tp_list), one_arg(iterable)); return call(_t(tp_list), one_arg(iterable));
} }
PyVar* find_name_in_mro(PyObject* cls, StrName name){ PyObject** find_name_in_mro(PyObject* cls, StrName name){
PyVar* val; PyObject** val;
do{ do{
val = cls->attr().try_get(name); val = cls->attr().try_get(name);
if(val != nullptr) return val; if(val != nullptr) return val;
Type cls_t = static_cast<Py_<Type>*>(cls)->_value; Type cls_t = static_cast<Py_<Type>*>(cls)->_value;
Type base = _all_types[cls_t.index].base; Type base = _all_types[cls_t.index].base;
if(base.index == -1) break; if(base.index == -1) break;
cls = _all_types[base.index].obj.get(); cls = _all_types[base.index].obj;
}while(true); }while(true);
return nullptr; return nullptr;
} }
bool isinstance(const PyVar& obj, Type cls_t){ bool isinstance(PyObject* obj, Type cls_t){
Type obj_t = OBJ_GET(Type, _t(obj)); Type obj_t = OBJ_GET(Type, _t(obj));
do{ do{
if(obj_t == cls_t) return true; if(obj_t == cls_t) return true;
@ -127,36 +131,36 @@ public:
return false; return false;
} }
PyVar fast_call(StrName name, Args&& args){ PyObject* fast_call(StrName name, Args&& args){
PyVar* val = find_name_in_mro(_t(args[0]).get(), name); PyObject** val = find_name_in_mro(_t(args[0]).get(), name);
if(val != nullptr) return call(*val, std::move(args)); if(val != nullptr) return call(*val, std::move(args));
AttributeError(args[0], name); AttributeError(args[0], name);
return nullptr; return nullptr;
} }
inline PyVar call(const PyVar& _callable){ inline PyObject* call(PyObject* _callable){
return call(_callable, no_arg(), no_arg(), false); return call(_callable, no_arg(), no_arg(), false);
} }
template<typename ArgT> template<typename ArgT>
inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyVar> inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
call(const PyVar& _callable, ArgT&& args){ call(PyObject* _callable, ArgT&& args){
return call(_callable, std::forward<ArgT>(args), no_arg(), false); return call(_callable, std::forward<ArgT>(args), no_arg(), false);
} }
template<typename ArgT> template<typename ArgT>
inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyVar> inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
call(const PyVar& obj, const StrName name, ArgT&& args){ call(PyObject* obj, const StrName name, ArgT&& args){
return call(getattr(obj, name, true, true), std::forward<ArgT>(args), no_arg(), false); return call(getattr(obj, name, true, true), std::forward<ArgT>(args), no_arg(), false);
} }
inline PyVar call(const PyVar& obj, StrName name){ inline PyObject* call(PyObject* obj, StrName name){
return call(getattr(obj, name, true, true), no_arg(), no_arg(), false); return call(getattr(obj, name, true, true), no_arg(), no_arg(), false);
} }
// repl mode is only for setting `frame->id` to 0 // repl mode is only for setting `frame->id` to 0
PyVarOrNull exec(Str source, Str filename, CompileMode mode, PyVar _module=nullptr){ PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr){
if(_module == nullptr) _module = _main; if(_module == nullptr) _module = _main;
try { try {
CodeObject_ code = compile(source, filename, mode); CodeObject_ code = compile(source, filename, mode);
@ -180,19 +184,20 @@ public:
} }
template<typename ...Args> template<typename ...Args>
inline PyVar _exec(Args&&... args){ inline PyObject* _exec(Args&&... args){
callstack.push(_new_frame(std::forward<Args>(args)...)); callstack.push(_new_frame(std::forward<Args>(args)...));
return _exec(); return _exec();
} }
PyVar property(NativeFuncRaw fget){ PyObject* property(NativeFuncRaw fget){
PyVar p = builtins->attr("property"); PyObject* p = builtins->attr("property");
PyVar method = new_object(tp_native_function, NativeFunc(fget, 1, false)); PyObject* method = new_object(tp_native_function, NativeFunc(fget, 1, false));
return call(p, one_arg(method)); return call(p, one_arg(method));
} }
PyVar new_type_object(PyVar mod, StrName name, Type base){ PyObject* new_type_object(PyObject* mod, StrName name, Type base){
PyVar obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size()); // use gcnew
PyObject* obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
PyTypeInfo info{ PyTypeInfo info{
.obj = obj, .obj = obj,
.base = base, .base = base,
@ -204,19 +209,19 @@ public:
} }
Type _new_type_object(StrName name, Type base=0) { Type _new_type_object(StrName name, Type base=0) {
PyVar obj = new_type_object(nullptr, name, base); PyObject* obj = new_type_object(nullptr, name, base);
return OBJ_GET(Type, obj); return OBJ_GET(Type, obj);
} }
template<typename T> template<typename T>
inline PyVar new_object(const PyVar& type, const T& _value) { inline PyObject* new_object(PyObject* type, const T& _value) {
#if PK_EXTRA_CHECK #if PK_EXTRA_CHECK
if(!is_type(type, tp_type)) UNREACHABLE(); if(!is_type(type, tp_type)) UNREACHABLE();
#endif #endif
return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value); return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value);
} }
template<typename T> template<typename T>
inline PyVar new_object(const PyVar& type, T&& _value) { inline PyObject* new_object(PyObject* type, T&& _value) {
#if PK_EXTRA_CHECK #if PK_EXTRA_CHECK
if(!is_type(type, tp_type)) UNREACHABLE(); if(!is_type(type, tp_type)) UNREACHABLE();
#endif #endif
@ -224,16 +229,16 @@ public:
} }
template<typename T> template<typename T>
inline PyVar new_object(Type type, const T& _value) { inline PyObject* new_object(Type type, const T& _value) {
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, _value); return make_sp<PyObject, Py_<std::decay_t<T>>>(type, _value);
} }
template<typename T> template<typename T>
inline PyVar new_object(Type type, T&& _value) { inline PyObject* new_object(Type type, T&& _value) {
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, std::move(_value)); return make_sp<PyObject, Py_<std::decay_t<T>>>(type, std::move(_value));
} }
PyVar _find_type(const Str& type){ PyObject* _find_type(const Str& type){
PyVar* obj = builtins->attr().try_get(type); PyObject** obj = builtins->attr().try_get(type);
if(!obj){ if(!obj){
for(auto& t: _all_types) if(t.name == type) return t.obj; for(auto& t: _all_types) if(t.name == type) return t.obj;
throw std::runtime_error("type not found: " + type); throw std::runtime_error("type not found: " + type);
@ -282,12 +287,12 @@ public:
Type tp_super, tp_exception, tp_star_wrapper; Type tp_super, tp_exception, tp_star_wrapper;
template<typename P> template<typename P>
inline PyVar PyIter(P&& value) { inline PyObject* PyIter(P&& value) {
static_assert(std::is_base_of_v<BaseIter, std::decay_t<P>>); static_assert(std::is_base_of_v<BaseIter, std::decay_t<P>>);
return new_object(tp_native_iterator, std::forward<P>(value)); return new_object(tp_native_iterator, std::forward<P>(value));
} }
inline BaseIter* PyIter_AS_C(const PyVar& obj) inline BaseIter* PyIter_AS_C(PyObject* obj)
{ {
check_type(obj, tp_native_iterator); check_type(obj, tp_native_iterator);
return static_cast<BaseIter*>(obj->value()); return static_cast<BaseIter*>(obj->value());
@ -313,22 +318,22 @@ public:
void ValueError(const Str& msg){ _error("ValueError", msg); } void ValueError(const Str& msg){ _error("ValueError", msg); }
void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); } void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); }
void AttributeError(PyVar obj, StrName name){ void AttributeError(PyObject* obj, StrName name){
_error("AttributeError", "type " + OBJ_NAME(_t(obj)).escape(true) + " has no attribute " + name.str().escape(true)); _error("AttributeError", "type " + OBJ_NAME(_t(obj)).escape(true) + " has no attribute " + name.str().escape(true));
} }
void AttributeError(Str msg){ _error("AttributeError", msg); } void AttributeError(Str msg){ _error("AttributeError", msg); }
inline void check_type(const PyVar& obj, Type type){ inline void check_type(PyObject* obj, Type type){
if(is_type(obj, type)) return; if(is_type(obj, type)) return;
TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true)); TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true));
} }
inline PyVar& _t(Type t){ inline PyObject* _t(Type t){
return _all_types[t.index].obj; return _all_types[t.index].obj;
} }
inline PyVar& _t(const PyVar& obj){ inline PyObject* _t(PyObject* obj){
if(is_int(obj)) return _t(tp_int); if(is_int(obj)) return _t(tp_int);
if(is_float(obj)) return _t(tp_float); if(is_float(obj)) return _t(tp_float);
return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj; return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj;
@ -341,42 +346,34 @@ public:
} }
} }
inline PyVarOrNull getattr(const PyVar& obj, StrName name, bool throw_err=true, bool class_only=false){
return getattr(&obj, name, throw_err, class_only);
}
template<typename T>
inline void setattr(PyVar& obj, StrName name, T&& value){
setattr(&obj, name, std::forward<T>(value));
}
CodeObject_ compile(Str source, Str filename, CompileMode mode); CodeObject_ compile(Str source, Str filename, CompileMode mode);
void post_init(); void post_init();
PyVar num_negated(const PyVar& obj); PyObject* num_negated(PyObject* obj);
f64 num_to_float(const PyVar& obj); f64 num_to_float(PyObject* obj);
const PyVar& asBool(const PyVar& obj); PyObject* asBool(PyObject* obj);
i64 hash(const PyVar& obj); i64 hash(PyObject* obj);
PyVar asRepr(const PyVar& obj); PyObject* asRepr(PyObject* obj);
PyVar new_module(StrName name); PyObject* new_module(StrName name);
Str disassemble(CodeObject_ co); Str disassemble(CodeObject_ co);
void init_builtin_types(); void init_builtin_types();
PyVar call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall); PyObject* call(PyObject* _callable, Args args, const Args& kwargs, bool opCall);
void unpack_args(Args& args); void unpack_args(Args& args);
PyVarOrNull getattr(const PyVar* obj, StrName name, bool throw_err=true, bool class_only=false); PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true, bool class_only=false);
template<typename T> template<typename T>
void setattr(PyVar* obj, StrName name, T&& value); void setattr(PyObject* obj, StrName name, T&& value);
template<int ARGC> template<int ARGC>
void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn); void bind_method(PyObject* obj, Str funcName, NativeFuncRaw fn);
template<int ARGC> template<int ARGC>
void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn); void bind_func(PyObject* obj, Str funcName, NativeFuncRaw fn);
void _error(Exception e); void _error(Exception e);
PyVar _exec(); PyObject* _exec();
template<typename P> template<typename P>
PyVarRef PyRef(P&& value); PyVarRef PyRef(P&& value);
const BaseRef* PyRef_AS_C(const PyVar& obj); const BaseRef* PyRef_AS_C(PyObject* obj);
}; };
PyVar NativeFunc::operator()(VM* vm, Args& args) const{ PyObject* NativeFunc::operator()(VM* vm, Args& args) const{
int args_size = args.size() - (int)method; // remove self int args_size = args.size() - (int)method; // remove self
if(argc != -1 && args_size != argc) { if(argc != -1 && args_size != argc) {
vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size)); vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
@ -437,11 +434,11 @@ DEF_NATIVE_2(Exception, tp_exception)
DEF_NATIVE_2(StarWrapper, tp_star_wrapper) DEF_NATIVE_2(StarWrapper, tp_star_wrapper)
#define PY_CAST_INT(T) \ #define PY_CAST_INT(T) \
template<> T py_cast<T>(VM* vm, const PyVar& obj){ \ template<> T py_cast<T>(VM* vm, PyObject* obj){ \
vm->check_type(obj, vm->tp_int); \ vm->check_type(obj, vm->tp_int); \
return (T)(obj.bits >> 2); \ return (T)(obj.bits >> 2); \
} \ } \
template<> T _py_cast<T>(VM* vm, const PyVar& obj){ \ template<> T _py_cast<T>(VM* vm, PyObject* obj){ \
return (T)(obj.bits >> 2); \ return (T)(obj.bits >> 2); \
} }
@ -457,38 +454,38 @@ PY_CAST_INT(unsigned long)
PY_CAST_INT(unsigned long long) PY_CAST_INT(unsigned long long)
template<> float py_cast<float>(VM* vm, const PyVar& obj){ template<> float py_cast<float>(VM* vm, PyObject* obj){
vm->check_type(obj, vm->tp_float); vm->check_type(obj, vm->tp_float);
i64 bits = obj.bits; i64 bits = obj.bits;
bits = (bits >> 2) << 2; bits = (bits >> 2) << 2;
return __8B(bits)._float; return __8B(bits)._float;
} }
template<> float _py_cast<float>(VM* vm, const PyVar& obj){ template<> float _py_cast<float>(VM* vm, PyObject* obj){
i64 bits = obj.bits; i64 bits = obj.bits;
bits = (bits >> 2) << 2; bits = (bits >> 2) << 2;
return __8B(bits)._float; return __8B(bits)._float;
} }
template<> double py_cast<double>(VM* vm, const PyVar& obj){ template<> double py_cast<double>(VM* vm, PyObject* obj){
vm->check_type(obj, vm->tp_float); vm->check_type(obj, vm->tp_float);
i64 bits = obj.bits; i64 bits = obj.bits;
bits = (bits >> 2) << 2; bits = (bits >> 2) << 2;
return __8B(bits)._float; return __8B(bits)._float;
} }
template<> double _py_cast<double>(VM* vm, const PyVar& obj){ template<> double _py_cast<double>(VM* vm, PyObject* obj){
i64 bits = obj.bits; i64 bits = obj.bits;
bits = (bits >> 2) << 2; bits = (bits >> 2) << 2;
return __8B(bits)._float; return __8B(bits)._float;
} }
#define PY_VAR_INT(T) \ #define PY_VAR_INT(T) \
PyVar py_var(VM* vm, T _val){ \ PyObject* py_var(VM* vm, T _val){ \
i64 val = static_cast<i64>(_val); \ i64 val = static_cast<i64>(_val); \
if(((val << 2) >> 2) != val){ \ if(((val << 2) >> 2) != val){ \
vm->_error("OverflowError", std::to_string(val) + " is out of range"); \ vm->_error("OverflowError", std::to_string(val) + " is out of range"); \
} \ } \
val = (val << 2) | 0b01; \ val = (val << 2) | 0b01; \
return PyVar(reinterpret_cast<int*>(val)); \ return reinterpret_cast<PyObject*>(val); \
} }
PY_VAR_INT(char) PY_VAR_INT(char)
@ -502,44 +499,44 @@ PY_VAR_INT(unsigned int)
PY_VAR_INT(unsigned long) PY_VAR_INT(unsigned long)
PY_VAR_INT(unsigned long long) PY_VAR_INT(unsigned long long)
#define PY_VAR_FLOAT(T) \ #define PY_VAR_FLOAT(T) \
PyVar py_var(VM* vm, T _val){ \ PyObject* py_var(VM* vm, T _val){ \
f64 val = static_cast<f64>(_val); \ f64 val = static_cast<f64>(_val); \
i64 bits = __8B(val)._int; \ i64 bits = __8B(val)._int; \
bits = (bits >> 2) << 2; \ bits = (bits >> 2) << 2; \
bits |= 0b10; \ bits |= 0b10; \
return PyVar(reinterpret_cast<int*>(bits)); \ return reinterpret_cast<PyObject*>(bits); \
} }
PY_VAR_FLOAT(float) PY_VAR_FLOAT(float)
PY_VAR_FLOAT(double) PY_VAR_FLOAT(double)
const PyVar& py_var(VM* vm, bool val){ PyObject* py_var(VM* vm, bool val){
return val ? vm->True : vm->False; return val ? vm->True : vm->False;
} }
template<> bool py_cast<bool>(VM* vm, const PyVar& obj){ template<> bool py_cast<bool>(VM* vm, PyObject* obj){
vm->check_type(obj, vm->tp_bool); vm->check_type(obj, vm->tp_bool);
return obj == vm->True; return obj == vm->True;
} }
template<> bool _py_cast<bool>(VM* vm, const PyVar& obj){ template<> bool _py_cast<bool>(VM* vm, PyObject* obj){
return obj == vm->True; return obj == vm->True;
} }
PyVar py_var(VM* vm, const char val[]){ PyObject* py_var(VM* vm, const char val[]){
return VAR(Str(val)); return VAR(Str(val));
} }
PyVar py_var(VM* vm, std::string val){ PyObject* py_var(VM* vm, std::string val){
return VAR(Str(std::move(val))); return VAR(Str(std::move(val)));
} }
template<typename T> template<typename T>
void _check_py_class(VM* vm, const PyVar& obj){ void _check_py_class(VM* vm, PyObject* obj){
vm->check_type(obj, T::_type(vm)); vm->check_type(obj, T::_type(vm));
} }
PyVar VM::num_negated(const PyVar& obj){ PyObject* VM::num_negated(PyObject* obj){
if (is_int(obj)){ if (is_int(obj)){
return VAR(-CAST(i64, obj)); return VAR(-CAST(i64, obj));
}else if(is_float(obj)){ }else if(is_float(obj)){
@ -549,7 +546,7 @@ PyVar VM::num_negated(const PyVar& obj){
return nullptr; return nullptr;
} }
f64 VM::num_to_float(const PyVar& obj){ f64 VM::num_to_float(PyObject* obj){
if(is_float(obj)){ if(is_float(obj)){
return CAST(f64, obj); return CAST(f64, obj);
} else if (is_int(obj)){ } else if (is_int(obj)){
@ -559,20 +556,20 @@ f64 VM::num_to_float(const PyVar& obj){
return 0; return 0;
} }
const PyVar& VM::asBool(const PyVar& obj){ PyObject* VM::asBool(PyObject* obj){
if(is_type(obj, tp_bool)) return obj; if(is_type(obj, tp_bool)) return obj;
if(obj == None) return False; if(obj == None) return False;
if(is_type(obj, tp_int)) return VAR(CAST(i64, obj) != 0); if(is_type(obj, tp_int)) return VAR(CAST(i64, obj) != 0);
if(is_type(obj, tp_float)) return VAR(CAST(f64, obj) != 0.0); if(is_type(obj, tp_float)) return VAR(CAST(f64, obj) != 0.0);
PyVarOrNull len_fn = getattr(obj, __len__, false, true); PyVarOrNull len_fn = getattr(obj, __len__, false, true);
if(len_fn != nullptr){ if(len_fn != nullptr){
PyVar ret = call(len_fn); PyObject* ret = call(len_fn);
return VAR(CAST(i64, ret) > 0); return VAR(CAST(i64, ret) > 0);
} }
return True; return True;
} }
i64 VM::hash(const PyVar& obj){ i64 VM::hash(PyObject* obj){
if (is_type(obj, tp_str)) return CAST(Str&, obj).hash(); if (is_type(obj, tp_str)) return CAST(Str&, obj).hash();
if (is_int(obj)) return CAST(i64, obj); if (is_int(obj)) return CAST(i64, obj);
if (is_type(obj, tp_tuple)) { if (is_type(obj, tp_tuple)) {
@ -594,12 +591,12 @@ i64 VM::hash(const PyVar& obj){
return 0; return 0;
} }
PyVar VM::asRepr(const PyVar& obj){ PyObject* VM::asRepr(PyObject* obj){
return call(obj, __repr__); return call(obj, __repr__);
} }
PyVar VM::new_module(StrName name) { PyObject* VM::new_module(StrName name) {
PyVar obj = new_object(tp_module, DummyModule()); PyObject* obj = new_object(tp_module, DummyModule());
obj->attr().set(__name__, VAR(name.str())); obj->attr().set(__name__, VAR(name.str()));
_modules.set(name, obj); _modules.set(name, obj);
return obj; return obj;
@ -665,7 +662,7 @@ Str VM::disassemble(CodeObject_ co){
ss << '\n' << consts.str() << '\n' << names.str() << '\n'; ss << '\n' << consts.str() << '\n' << names.str() << '\n';
for(int i=0; i<co->consts.size(); i++){ for(int i=0; i<co->consts.size(); i++){
PyVar obj = co->consts[i]; PyObject* obj = co->consts[i];
if(is_type(obj, tp_function)){ if(is_type(obj, tp_function)){
const auto& f = CAST(Function&, obj); const auto& f = CAST(Function&, obj);
ss << disassemble(f.code); ss << disassemble(f.code);
@ -731,10 +728,10 @@ void VM::init_builtin_types(){
for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash(); for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash();
} }
PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall){ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCall){
if(is_type(_callable, tp_type)){ if(is_type(callable, tp_type)){
PyVar* new_f = _callable->attr().try_get(__new__); PyObject** new_f = callable->attr().try_get(__new__);
PyVar obj; PyObject* obj;
if(new_f != nullptr){ if(new_f != nullptr){
obj = call(*new_f, std::move(args), kwargs, false); obj = call(*new_f, std::move(args), kwargs, false);
}else{ }else{
@ -745,19 +742,18 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal
return obj; return obj;
} }
const PyVar* callable = &_callable; if(is_type(callable, tp_bound_method)){
if(is_type(*callable, tp_bound_method)){ auto& bm = CAST(BoundMethod&, callable);
auto& bm = CAST(BoundMethod&, *callable); callable = bm.method; // get unbound method
callable = &bm.method; // get unbound method
args.extend_self(bm.obj); args.extend_self(bm.obj);
} }
if(is_type(*callable, tp_native_function)){ if(is_type(callable, tp_native_function)){
const auto& f = OBJ_GET(NativeFunc, *callable); const auto& f = OBJ_GET(NativeFunc, callable);
if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments"); if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments");
return f(this, args); return f(this, args);
} else if(is_type(*callable, tp_function)){ } else if(is_type(callable, tp_function)){
const Function& fn = CAST(Function&, *callable); const Function& fn = CAST(Function&, callable);
NameDict_ locals = make_sp<NameDict>( NameDict_ locals = make_sp<NameDict>(
fn.code->perfect_locals_capacity, fn.code->perfect_locals_capacity,
kLocalsLoadFactor, kLocalsLoadFactor,
@ -797,7 +793,7 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal
} }
locals->set(key, kwargs[i+1]); locals->set(key, kwargs[i+1]);
} }
const PyVar& _module = fn._module != nullptr ? fn._module : top_frame()->_module; PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module;
auto _frame = _new_frame(fn.code, _module, locals, fn._closure); auto _frame = _new_frame(fn.code, _module, locals, fn._closure);
if(fn.code->is_generator) return PyIter(Generator(this, std::move(_frame))); if(fn.code->is_generator) return PyIter(Generator(this, std::move(_frame)));
callstack.push(std::move(_frame)); callstack.push(std::move(_frame));
@ -819,7 +815,7 @@ void VM::unpack_args(Args& args){
if(is_type(args[i], tp_star_wrapper)){ if(is_type(args[i], tp_star_wrapper)){
auto& star = _CAST(StarWrapper&, args[i]); auto& star = _CAST(StarWrapper&, args[i]);
if(!star.rvalue) UNREACHABLE(); if(!star.rvalue) UNREACHABLE();
PyVar list = asList(star.obj); PyObject* list = asList(star.obj);
List& list_c = CAST(List&, list); List& list_c = CAST(List&, list);
unpacked.insert(unpacked.end(), list_c.begin(), list_c.end()); unpacked.insert(unpacked.end(), list_c.begin(), list_c.end());
}else{ }else{
@ -829,25 +825,25 @@ void VM::unpack_args(Args& args){
args = Args::from_list(std::move(unpacked)); args = Args::from_list(std::move(unpacked));
} }
using Super = std::pair<PyVar, Type>; using Super = std::pair<PyObject*, Type>;
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
PyVarOrNull VM::getattr(const PyVar* obj, StrName name, bool throw_err, bool class_only){ PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool class_only){
PyObject* objtype = _t(*obj).get(); PyObject* objtype = _t(*obj).get();
if(is_type(*obj, tp_super)){ if(is_type(*obj, tp_super)){
const Super& super = OBJ_GET(Super, *obj); const Super& super = OBJ_GET(Super, *obj);
obj = &super.first; obj = &super.first;
objtype = _t(super.second).get(); objtype = _t(super.second).get();
} }
PyVar* cls_var = find_name_in_mro(objtype, name); PyObject** cls_var = find_name_in_mro(objtype, name);
if(cls_var != nullptr){ if(cls_var != nullptr){
// handle descriptor // handle descriptor
PyVar* descr_get = _t(*cls_var)->attr().try_get(__get__); PyObject** descr_get = _t(*cls_var)->attr().try_get(__get__);
if(descr_get != nullptr) return call(*descr_get, two_args(*cls_var, *obj)); if(descr_get != nullptr) return call(*descr_get, two_args(*cls_var, *obj));
} }
// handle instance __dict__ // handle instance __dict__
if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){ if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){
PyVar* val = (*obj)->attr().try_get(name); PyObject** val = (*obj)->attr().try_get(name);
if(val != nullptr) return *val; if(val != nullptr) return *val;
} }
if(cls_var != nullptr){ if(cls_var != nullptr){
@ -862,22 +858,22 @@ PyVarOrNull VM::getattr(const PyVar* obj, StrName name, bool throw_err, bool cla
} }
template<typename T> template<typename T>
void VM::setattr(PyVar* obj, StrName name, T&& value){ void VM::setattr(PyObject* obj, StrName name, T&& value){
static_assert(std::is_same_v<std::decay_t<T>, PyVar>); static_assert(std::is_same_v<std::decay_t<T>, PyVar>);
PyObject* objtype = _t(*obj).get(); PyObject* objtype = _t(obj).get();
if(is_type(*obj, tp_super)){ if(is_type(obj, tp_super)){
Super& super = OBJ_GET(Super, *obj); Super& super = OBJ_GET(Super, *obj);
obj = &super.first; obj = super.first;
objtype = _t(super.second).get(); objtype = _t(super.second).get();
} }
PyVar* cls_var = find_name_in_mro(objtype, name); PyObject** cls_var = find_name_in_mro(objtype, name);
if(cls_var != nullptr){ if(cls_var != nullptr){
// handle descriptor // handle descriptor
const PyVar& cls_var_t = _t(*cls_var); PyObject* cls_var_t = _t(*cls_var);
if(cls_var_t->attr().contains(__get__)){ if(cls_var_t->attr().contains(__get__)){
PyVar* descr_set = cls_var_t->attr().try_get(__set__); PyObject** descr_set = cls_var_t->attr().try_get(__set__);
if(descr_set != nullptr){ if(descr_set != nullptr){
call(*descr_set, three_args(*cls_var, *obj, std::forward<T>(value))); call(*descr_set, three_args(*cls_var, obj, std::forward<T>(value)));
}else{ }else{
TypeError("readonly attribute: " + name.str().escape(true)); TypeError("readonly attribute: " + name.str().escape(true));
} }
@ -885,18 +881,18 @@ void VM::setattr(PyVar* obj, StrName name, T&& value){
} }
} }
// handle instance __dict__ // handle instance __dict__
if((*obj).is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute"); if(obj.is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute");
(*obj)->attr().set(name, std::forward<T>(value)); obj->attr().set(name, std::forward<T>(value));
} }
template<int ARGC> template<int ARGC>
void VM::bind_method(PyVar obj, Str name, NativeFuncRaw fn) { void VM::bind_method(PyObject* obj, Str name, NativeFuncRaw fn) {
check_type(obj, tp_type); check_type(obj, tp_type);
obj->attr().set(name, VAR(NativeFunc(fn, ARGC, true))); obj->attr().set(name, VAR(NativeFunc(fn, ARGC, true)));
} }
template<int ARGC> template<int ARGC>
void VM::bind_func(PyVar obj, Str name, NativeFuncRaw fn) { void VM::bind_func(PyObject* obj, Str name, NativeFuncRaw fn) {
obj->attr().set(name, VAR(NativeFunc(fn, ARGC, false))); obj->attr().set(name, VAR(NativeFunc(fn, ARGC, false)));
} }
@ -909,10 +905,10 @@ void VM::_error(Exception e){
_raise(); _raise();
} }
PyVar VM::_exec(){ PyObject* VM::_exec(){
Frame* frame = top_frame(); Frame* frame = top_frame();
i64 base_id = frame->id; i64 base_id = frame->id;
PyVar ret = nullptr; PyObject* ret = nullptr;
bool need_raise = false; bool need_raise = false;
while(true){ while(true){
@ -936,7 +932,7 @@ PyVar VM::_exec(){
}catch(HandledException& e){ }catch(HandledException& e){
continue; continue;
}catch(UnhandledException& e){ }catch(UnhandledException& e){
PyVar obj = frame->pop(); PyObject* obj = frame->pop();
Exception& _e = CAST(Exception&, obj); Exception& _e = CAST(Exception&, obj);
_e.st_push(frame->snapshot()); _e.st_push(frame->snapshot());
callstack.pop(); callstack.pop();