update gc

This commit is contained in:
blueloveTH 2023-03-28 17:08:42 +08:00
parent c2ef720d90
commit f57fa16ee2
18 changed files with 323 additions and 415 deletions

View File

@ -7,7 +7,7 @@ namespace pkpy{
Str _read_file_cwd(const Str& name, bool* ok); Str _read_file_cwd(const Str& name, bool* ok);
PyVar VM::run_frame(Frame* frame){ PyObject* VM::run_frame(Frame* frame){
while(frame->has_next_bytecode()){ while(frame->has_next_bytecode()){
const Bytecode& byte = frame->next_bytecode(); const Bytecode& byte = frame->next_bytecode();
switch (byte.op) switch (byte.op)
@ -16,7 +16,7 @@ PyVar VM::run_frame(Frame* frame){
case OP_SETUP_DECORATOR: continue; case OP_SETUP_DECORATOR: continue;
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue; case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
case OP_LOAD_FUNCTION: { case OP_LOAD_FUNCTION: {
const PyVar obj = frame->co->consts[byte.arg]; PyObject* obj = frame->co->consts[byte.arg];
Function f = CAST(Function, obj); // copy Function f = CAST(Function, obj); // copy
f._module = frame->_module; f._module = frame->_module;
frame->push(VAR(f)); frame->push(VAR(f));
@ -37,13 +37,13 @@ PyVar VM::run_frame(Frame* frame){
} continue; } continue;
case OP_BUILD_ATTR_REF: case OP_BUILD_ATTR: { case OP_BUILD_ATTR_REF: case OP_BUILD_ATTR: {
auto& attr = frame->co->names[byte.arg]; auto& attr = frame->co->names[byte.arg];
PyVar obj = frame->pop_value(this); PyObject* obj = frame->pop_value(this);
AttrRef ref = AttrRef(obj, NameRef(attr)); AttrRef ref = AttrRef(obj, NameRef(attr));
if(byte.op == OP_BUILD_ATTR) frame->push(ref.get(this, frame)); if(byte.op == OP_BUILD_ATTR) frame->push(ref.get(this, frame));
else frame->push(PyRef(ref)); else frame->push(PyRef(ref));
} continue; } continue;
case OP_BUILD_INDEX: { case OP_BUILD_INDEX: {
PyVar index = frame->pop_value(this); PyObject* index = frame->pop_value(this);
auto ref = IndexRef(frame->pop_value(this), index); auto ref = IndexRef(frame->pop_value(this), index);
if(byte.arg > 0) frame->push(ref.get(this, frame)); if(byte.arg > 0) frame->push(ref.get(this, frame));
else frame->push(PyRef(ref)); else frame->push(PyRef(ref));
@ -57,9 +57,6 @@ PyVar VM::run_frame(Frame* frame){
} continue; } continue;
case OP_ROT_TWO: ::std::swap(frame->top(), frame->top_1()); continue; case OP_ROT_TWO: ::std::swap(frame->top(), frame->top_1()); continue;
case OP_STORE_REF: { case OP_STORE_REF: {
// PyVar obj = frame->pop_value(this);
// PyVarRef r = frame->pop();
// PyRef_AS_C(r)->set(this, frame, std::move(obj));
PyRef_AS_C(frame->top_1())->set(this, frame, frame->top_value(this)); PyRef_AS_C(frame->top_1())->set(this, frame, frame->top_value(this));
frame->_pop(); frame->_pop(); frame->_pop(); frame->_pop();
} continue; } continue;
@ -84,25 +81,25 @@ PyVar VM::run_frame(Frame* frame){
case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue; case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue;
case OP_BEGIN_CLASS: { case OP_BEGIN_CLASS: {
auto& name = frame->co->names[byte.arg]; auto& name = frame->co->names[byte.arg];
PyVar clsBase = frame->pop_value(this); PyObject* clsBase = frame->pop_value(this);
if(clsBase == None) clsBase = _t(tp_object); if(clsBase == None) clsBase = _t(tp_object);
check_type(clsBase, tp_type); check_type(clsBase, tp_type);
PyVar cls = new_type_object(frame->_module, name.first, OBJ_GET(Type, clsBase)); PyObject* cls = new_type_object(frame->_module, name.first, OBJ_GET(Type, clsBase));
frame->push(cls); frame->push(cls);
} continue; } continue;
case OP_END_CLASS: { case OP_END_CLASS: {
PyVar cls = frame->pop(); PyObject* cls = frame->pop();
cls->attr()._try_perfect_rehash(); cls->attr()._try_perfect_rehash();
}; continue; }; continue;
case OP_STORE_CLASS_ATTR: { case OP_STORE_CLASS_ATTR: {
auto& name = frame->co->names[byte.arg]; auto& name = frame->co->names[byte.arg];
PyVar obj = frame->pop_value(this); PyObject* obj = frame->pop_value(this);
PyVar& cls = frame->top(); PyObject* cls = frame->top();
cls->attr().set(name.first, std::move(obj)); cls->attr().set(name.first, std::move(obj));
} continue; } continue;
case OP_RETURN_VALUE: return frame->pop_value(this); case OP_RETURN_VALUE: return frame->pop_value(this);
case OP_PRINT_EXPR: { case OP_PRINT_EXPR: {
const PyVar expr = frame->top_value(this); PyObject* expr = frame->top_value(this);
if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n'; if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n';
} continue; } continue;
case OP_POP_TOP: frame->_pop(); continue; case OP_POP_TOP: frame->_pop(); continue;
@ -122,7 +119,7 @@ PyVar VM::run_frame(Frame* frame){
Args args(2); Args args(2);
args[1] = frame->pop(); args[1] = frame->pop();
args[0] = frame->top_value(this); args[0] = frame->top_value(this);
PyVar ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); PyObject* ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
PyRef_AS_C(frame->top())->set(this, frame, std::move(ret)); PyRef_AS_C(frame->top())->set(this, frame, std::move(ret));
frame->_pop(); frame->_pop();
} continue; } continue;
@ -130,7 +127,7 @@ PyVar VM::run_frame(Frame* frame){
Args args(2); Args args(2);
args[1] = frame->pop_value(this); args[1] = frame->pop_value(this);
args[0] = frame->top_value(this); args[0] = frame->top_value(this);
PyVar ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args)); PyObject* ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
PyRef_AS_C(frame->top())->set(this, frame, std::move(ret)); PyRef_AS_C(frame->top())->set(this, frame, std::move(ret));
frame->_pop(); frame->_pop();
} continue; } continue;
@ -141,14 +138,14 @@ PyVar VM::run_frame(Frame* frame){
frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args)); frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args));
} continue; } continue;
case OP_IS_OP: { case OP_IS_OP: {
PyVar rhs = frame->pop_value(this); PyObject* rhs = frame->pop_value(this);
bool ret_c = rhs == frame->top_value(this); bool ret_c = rhs == frame->top_value(this);
if(byte.arg == 1) ret_c = !ret_c; if(byte.arg == 1) ret_c = !ret_c;
frame->top() = VAR(ret_c); frame->top() = VAR(ret_c);
} continue; } continue;
case OP_CONTAINS_OP: { case OP_CONTAINS_OP: {
PyVar rhs = frame->pop_value(this); PyObject* rhs = frame->pop_value(this);
bool ret_c = CAST(bool, call(rhs, __contains__, one_arg(frame->pop_value(this)))); bool ret_c = CAST(bool, call(rhs, __contains__, Args{frame->pop_value(this)}));
if(byte.arg == 1) ret_c = !ret_c; if(byte.arg == 1) ret_c = !ret_c;
frame->push(VAR(ret_c)); frame->push(VAR(ret_c));
} continue; } continue;
@ -156,8 +153,8 @@ PyVar VM::run_frame(Frame* frame){
frame->top() = num_negated(frame->top_value(this)); frame->top() = num_negated(frame->top_value(this));
continue; continue;
case OP_UNARY_NOT: { case OP_UNARY_NOT: {
PyVar obj = frame->pop_value(this); PyObject* obj = frame->pop_value(this);
const PyVar& obj_bool = asBool(obj); PyObject* obj_bool = asBool(obj);
frame->push(VAR(!_CAST(bool, obj_bool))); frame->push(VAR(!_CAST(bool, obj_bool)));
} continue; } continue;
case OP_POP_JUMP_IF_FALSE: case OP_POP_JUMP_IF_FALSE:
@ -168,9 +165,9 @@ PyVar VM::run_frame(Frame* frame){
case OP_LOAD_FALSE: frame->push(False); continue; case OP_LOAD_FALSE: frame->push(False); continue;
case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue; case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); continue;
case OP_ASSERT: { case OP_ASSERT: {
PyVar _msg = frame->pop_value(this); PyObject* _msg = frame->pop_value(this);
Str msg = CAST(Str, asStr(_msg)); Str msg = CAST(Str, asStr(_msg));
PyVar expr = frame->pop_value(this); PyObject* expr = frame->pop_value(this);
if(asBool(expr) != True) _error("AssertionError", msg); if(asBool(expr) != True) _error("AssertionError", msg);
} continue; } continue;
case OP_EXCEPTION_MATCH: { case OP_EXCEPTION_MATCH: {
@ -179,7 +176,7 @@ PyVar VM::run_frame(Frame* frame){
frame->push(VAR(e.match_type(name))); frame->push(VAR(e.match_type(name)));
} continue; } continue;
case OP_RAISE: { case OP_RAISE: {
PyVar obj = frame->pop_value(this); PyObject* obj = frame->pop_value(this);
Str msg = obj == None ? "" : CAST(Str, asStr(obj)); Str msg = obj == None ? "" : CAST(Str, asStr(obj));
StrName type = frame->co->names[byte.arg].first; StrName type = frame->co->names[byte.arg].first;
_error(type, msg); _error(type, msg);
@ -190,32 +187,32 @@ PyVar VM::run_frame(Frame* frame){
continue; continue;
case OP_BUILD_MAP: { case OP_BUILD_MAP: {
Args items = frame->pop_n_values_reversed(this, byte.arg*2); Args items = frame->pop_n_values_reversed(this, byte.arg*2);
PyVar obj = call(builtins->attr("dict")); PyObject* obj = call(builtins->attr("dict"));
for(int i=0; i<items.size(); i+=2){ for(int i=0; i<items.size(); i+=2){
call(obj, __setitem__, two_args(items[i], items[i+1])); call(obj, __setitem__, Args{items[i], items[i+1]});
} }
frame->push(obj); frame->push(obj);
} continue; } continue;
case OP_BUILD_SET: { case OP_BUILD_SET: {
PyVar list = VAR( PyObject* list = VAR(
frame->pop_n_values_reversed(this, byte.arg).move_to_list() frame->pop_n_values_reversed(this, byte.arg).move_to_list()
); );
PyVar obj = call(builtins->attr("set"), one_arg(list)); PyObject* obj = call(builtins->attr("set"), Args{list});
frame->push(obj); frame->push(obj);
} continue; } continue;
case OP_LIST_APPEND: { case OP_LIST_APPEND: {
PyVar obj = frame->pop_value(this); PyObject* obj = frame->pop_value(this);
List& list = CAST(List&, frame->top_1()); List& list = CAST(List&, frame->top_1());
list.push_back(std::move(obj)); list.push_back(std::move(obj));
} continue; } continue;
case OP_MAP_ADD: { case OP_MAP_ADD: {
PyVar value = frame->pop_value(this); PyObject* value = frame->pop_value(this);
PyVar key = frame->pop_value(this); PyObject* key = frame->pop_value(this);
call(frame->top_1(), __setitem__, two_args(key, value)); call(frame->top_1(), __setitem__, Args{key, value});
} continue; } continue;
case OP_SET_ADD: { case OP_SET_ADD: {
PyVar obj = frame->pop_value(this); PyObject* obj = frame->pop_value(this);
call(frame->top_1(), "add", one_arg(obj)); call(frame->top_1(), "add", Args{obj});
} continue; } continue;
case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue; case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
case OP_UNARY_STAR: { case OP_UNARY_STAR: {
@ -232,16 +229,16 @@ PyVar VM::run_frame(Frame* frame){
Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2); Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
Args args = frame->pop_n_values_reversed(this, ARGC); Args args = frame->pop_n_values_reversed(this, ARGC);
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args); if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
PyVar callable = frame->pop_value(this); PyObject* callable = frame->pop_value(this);
PyVar ret = call(callable, std::move(args), kwargs, true); PyObject* ret = call(callable, std::move(args), kwargs, true);
if(ret == _py_op_call) return ret; if(ret == _py_op_call) return ret;
frame->push(std::move(ret)); frame->push(std::move(ret));
} continue; } continue;
case OP_CALL_UNPACK: case OP_CALL: { case OP_CALL_UNPACK: case OP_CALL: {
Args args = frame->pop_n_values_reversed(this, byte.arg); Args args = frame->pop_n_values_reversed(this, byte.arg);
if(byte.op == OP_CALL_UNPACK) unpack_args(args); if(byte.op == OP_CALL_UNPACK) unpack_args(args);
PyVar callable = frame->pop_value(this); PyObject* callable = frame->pop_value(this);
PyVar ret = call(callable, std::move(args), no_arg(), true); PyObject* ret = call(callable, std::move(args), no_arg(), true);
if(ret == _py_op_call) return ret; if(ret == _py_op_call) return ret;
frame->push(std::move(ret)); frame->push(std::move(ret));
} continue; } continue;
@ -254,15 +251,15 @@ PyVar VM::run_frame(Frame* frame){
frame->jump_abs_safe(it->second); frame->jump_abs_safe(it->second);
} continue; } continue;
case OP_GET_ITER: { case OP_GET_ITER: {
PyVar obj = frame->pop_value(this); PyObject* obj = frame->pop_value(this);
PyVar iter = asIter(obj); PyObject* iter = asIter(obj);
check_type(frame->top(), tp_ref); check_type(frame->top(), tp_ref);
PyIter_AS_C(iter)->loop_var = frame->pop(); PyIter_AS_C(iter)->loop_var = frame->pop();
frame->push(std::move(iter)); frame->push(std::move(iter));
} continue; } continue;
case OP_FOR_ITER: { case OP_FOR_ITER: {
BaseIter* it = PyIter_AS_C(frame->top()); BaseIter* it = PyIter_AS_C(frame->top());
PyVar obj = it->next(); PyObject* obj = it->next();
if(obj != nullptr){ if(obj != nullptr){
PyRef_AS_C(it->loop_var)->set(this, frame, std::move(obj)); PyRef_AS_C(it->loop_var)->set(this, frame, std::move(obj));
}else{ }else{
@ -279,18 +276,18 @@ PyVar VM::run_frame(Frame* frame){
frame->jump_abs_safe(blockEnd); frame->jump_abs_safe(blockEnd);
} continue; } continue;
case OP_JUMP_IF_FALSE_OR_POP: { case OP_JUMP_IF_FALSE_OR_POP: {
const PyVar expr = frame->top_value(this); PyObject* expr = frame->top_value(this);
if(asBool(expr)==False) frame->jump_abs(byte.arg); if(asBool(expr)==False) frame->jump_abs(byte.arg);
else frame->pop_value(this); else frame->pop_value(this);
} continue; } continue;
case OP_JUMP_IF_TRUE_OR_POP: { case OP_JUMP_IF_TRUE_OR_POP: {
const PyVar expr = frame->top_value(this); PyObject* expr = frame->top_value(this);
if(asBool(expr)==True) frame->jump_abs(byte.arg); if(asBool(expr)==True) frame->jump_abs(byte.arg);
else frame->pop_value(this); else frame->pop_value(this);
} continue; } continue;
case OP_BUILD_SLICE: { case OP_BUILD_SLICE: {
PyVar stop = frame->pop_value(this); PyObject* stop = frame->pop_value(this);
PyVar start = frame->pop_value(this); PyObject* start = frame->pop_value(this);
Slice s; Slice s;
if(start != None) { s.start = CAST(int, start);} if(start != None) { s.start = CAST(int, start);}
if(stop != None) { s.stop = CAST(int, stop);} if(stop != None) { s.stop = CAST(int, stop);}
@ -298,7 +295,7 @@ PyVar VM::run_frame(Frame* frame){
} continue; } continue;
case OP_IMPORT_NAME: { case OP_IMPORT_NAME: {
StrName name = frame->co->names[byte.arg].first; StrName name = frame->co->names[byte.arg].first;
PyVar* ext_mod = _modules.try_get(name); PyObject** ext_mod = _modules.try_get(name);
if(ext_mod == nullptr){ if(ext_mod == nullptr){
Str source; Str source;
auto it2 = _lazy_modules.find(name); auto it2 = _lazy_modules.find(name);
@ -311,7 +308,7 @@ PyVar VM::run_frame(Frame* frame){
_lazy_modules.erase(it2); _lazy_modules.erase(it2);
} }
CodeObject_ code = compile(source, name.str(), EXEC_MODE); CodeObject_ code = compile(source, name.str(), EXEC_MODE);
PyVar new_mod = new_module(name); PyObject* new_mod = new_module(name);
_exec(code, new_mod); _exec(code, new_mod);
frame->push(new_mod); frame->push(new_mod);
new_mod->attr()._try_perfect_rehash(); new_mod->attr()._try_perfect_rehash();
@ -320,7 +317,7 @@ PyVar VM::run_frame(Frame* frame){
} }
} continue; } continue;
case OP_STORE_ALL_NAMES: { case OP_STORE_ALL_NAMES: {
PyVar obj = frame->pop_value(this); PyObject* obj = frame->pop_value(this);
for(auto& [name, value]: obj->attr().items()){ for(auto& [name, value]: obj->attr().items()){
Str s = name.str(); Str s = name.str();
if(s.empty() || s[0] == '_') continue; if(s.empty() || s[0] == '_') continue;

View File

@ -14,7 +14,7 @@ struct NativeProxyFunc {
_Fp func; _Fp func;
NativeProxyFunc(_Fp func) : func(func) {} NativeProxyFunc(_Fp func) : func(func) {}
PyVar operator()(VM* vm, Args& args) { PyObject* operator()(VM* vm, Args& args) {
if (args.size() != N) { if (args.size() != N) {
vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size())); vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size()));
} }
@ -22,13 +22,13 @@ struct NativeProxyFunc {
} }
template<typename __Ret, size_t... Is> template<typename __Ret, size_t... Is>
std::enable_if_t<std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) { std::enable_if_t<std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
func(py_cast<Params>(vm, args[Is])...); func(py_cast<Params>(vm, args[Is])...);
return vm->None; return vm->None;
} }
template<typename __Ret, size_t... Is> template<typename __Ret, size_t... Is>
std::enable_if_t<!std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) { std::enable_if_t<!std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
__Ret ret = func(py_cast<Params>(vm, args[Is])...); __Ret ret = func(py_cast<Params>(vm, args[Is])...);
return VAR(std::move(ret)); return VAR(std::move(ret));
} }
@ -41,7 +41,7 @@ struct NativeProxyMethod {
_Fp func; _Fp func;
NativeProxyMethod(_Fp func) : func(func) {} NativeProxyMethod(_Fp func) : func(func) {}
PyVar operator()(VM* vm, Args& args) { PyObject* operator()(VM* vm, Args& args) {
int actual_size = args.size() - 1; int actual_size = args.size() - 1;
if (actual_size != N) { if (actual_size != N) {
vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(actual_size)); vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(actual_size));
@ -50,14 +50,14 @@ struct NativeProxyMethod {
} }
template<typename __Ret, size_t... Is> template<typename __Ret, size_t... Is>
std::enable_if_t<std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) { std::enable_if_t<std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
T& self = py_cast<T&>(vm, args[0]); T& self = py_cast<T&>(vm, args[0]);
(self.*func)(py_cast<Params>(vm, args[Is+1])...); (self.*func)(py_cast<Params>(vm, args[Is+1])...);
return vm->None; return vm->None;
} }
template<typename __Ret, size_t... Is> template<typename __Ret, size_t... Is>
std::enable_if_t<!std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) { std::enable_if_t<!std::is_void_v<__Ret>, PyObject*> call(VM* vm, Args& args, std::index_sequence<Is...>) {
T& self = py_cast<T&>(vm, args[0]); T& self = py_cast<T&>(vm, args[0]);
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...); __Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
return VAR(std::move(ret)); return VAR(std::move(ret));
@ -200,7 +200,7 @@ struct Pointer{
return Pointer(ctype, level, ptr-offset*unit_size()); return Pointer(ctype, level, ptr-offset*unit_size());
} }
static void _register(VM* vm, PyVar mod, PyVar type){ static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
@ -268,7 +268,7 @@ struct Pointer{
template<typename T> template<typename T>
inline T& ref() noexcept { return *reinterpret_cast<T*>(ptr); } inline T& ref() noexcept { return *reinterpret_cast<T*>(ptr); }
PyVar get(VM* vm){ PyObject* get(VM* vm){
if(level > 1) return VAR_T(Pointer, ctype, level-1, ref<char*>()); if(level > 1) return VAR_T(Pointer, ctype, level-1, ref<char*>());
switch(ctype->index){ switch(ctype->index){
#define CASE(T) case type_index<T>(): return VAR(ref<T>()) #define CASE(T) case type_index<T>(): return VAR(ref<T>())
@ -291,7 +291,7 @@ struct Pointer{
return VAR_T(Pointer, *this); return VAR_T(Pointer, *this);
} }
void set(VM* vm, const PyVar& val){ void set(VM* vm, PyObject* val){
if(level > 1) { if(level > 1) {
Pointer& p = CAST(Pointer&, val); Pointer& p = CAST(Pointer&, val);
ref<char*>() = p.ptr; // We don't check the type, just copy the underlying address ref<char*>() = p.ptr; // We don't check the type, just copy the underlying address
@ -359,7 +359,7 @@ struct Value {
Value& operator=(const Value& other) = delete; Value& operator=(const Value& other) = delete;
Value(const Value& other) = delete; Value(const Value& other) = delete;
static void _register(VM* vm, PyVar mod, PyVar type){ static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
vm->bind_method<0>(type, "ptr", [](VM* vm, Args& args) { vm->bind_method<0>(type, "ptr", [](VM* vm, Args& args) {
@ -388,7 +388,7 @@ struct CType{
CType() : type(_type_db.get<void>()) {} CType() : type(_type_db.get<void>()) {}
CType(const TypeInfo* type) : type(type) {} CType(const TypeInfo* type) : type(type) {}
static void _register(VM* vm, PyVar mod, PyVar type){ static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_static_method<1>(type, "__new__", [](VM* vm, Args& args) { vm->bind_static_method<1>(type, "__new__", [](VM* vm, Args& args) {
const Str& name = CAST(Str&, args[0]); const Str& name = CAST(Str&, args[0]);
const TypeInfo* type = _type_db.get(name); const TypeInfo* type = _type_db.get(name);
@ -404,8 +404,8 @@ struct CType{
}; };
void add_module_c(VM* vm){ void add_module_c(VM* vm){
PyVar mod = vm->new_module("c"); PyObject* mod = vm->new_module("c");
PyVar ptr_t = Pointer::register_class(vm, mod); PyObject* ptr_t = Pointer::register_class(vm, mod);
Value::register_class(vm, mod); Value::register_class(vm, mod);
CType::register_class(vm, mod); CType::register_class(vm, mod);
@ -462,11 +462,11 @@ void add_module_c(VM* vm){
}); });
} }
PyVar py_var(VM* vm, void* p){ PyObject* py_var(VM* vm, void* p){
return VAR_T(Pointer, _type_db.get<void>(), (char*)p); return VAR_T(Pointer, _type_db.get<void>(), (char*)p);
} }
PyVar py_var(VM* vm, char* p){ PyObject* py_var(VM* vm, char* p){
return VAR_T(Pointer, _type_db.get<char>(), (char*)p); return VAR_T(Pointer, _type_db.get<char>(), (char*)p);
} }
@ -491,7 +491,7 @@ struct pointer {
}; };
template<typename T> template<typename T>
T py_pointer_cast(VM* vm, const PyVar& var){ T py_pointer_cast(VM* vm, PyObject* var){
static_assert(std::is_pointer_v<T>); static_assert(std::is_pointer_v<T>);
Pointer& p = CAST(Pointer&, var); Pointer& p = CAST(Pointer&, var);
const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>(); const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>();
@ -503,14 +503,14 @@ T py_pointer_cast(VM* vm, const PyVar& var){
} }
template<typename T> template<typename T>
T py_value_cast(VM* vm, const PyVar& var){ T py_value_cast(VM* vm, PyObject* var){
static_assert(std::is_pod_v<T>); static_assert(std::is_pod_v<T>);
Value& v = CAST(Value&, var); Value& v = CAST(Value&, var);
return *reinterpret_cast<T*>(v.data); return *reinterpret_cast<T*>(v.data);
} }
template<typename T> template<typename T>
std::enable_if_t<std::is_pointer_v<std::decay_t<T>>, PyVar> std::enable_if_t<std::is_pointer_v<std::decay_t<T>>, PyObject*>
py_var(VM* vm, T p){ py_var(VM* vm, T p){
const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>(); const TypeInfo* type = _type_db.get<typename pointer<T>::baseT>();
if(type == nullptr) type = _type_db.get<void>(); if(type == nullptr) type = _type_db.get<void>();
@ -518,9 +518,9 @@ py_var(VM* vm, T p){
} }
template<typename T> template<typename T>
std::enable_if_t<!std::is_pointer_v<std::decay_t<T>>, PyVar> std::enable_if_t<!std::is_pointer_v<std::decay_t<T>>, PyObject*>
py_var(VM* vm, T p){ py_var(VM* vm, T p){
if constexpr(std::is_same_v<T, PyVar>) return p; if constexpr(std::is_same_v<T, PyObject*>) return p;
const TypeInfo* type = _type_db.get<T>(); const TypeInfo* type = _type_db.get<T>();
return VAR_T(Value, type, &p); return VAR_T(Value, type, &p);
} }

View File

@ -94,7 +94,7 @@ struct CodeObject {
return names.size() - 1; return names.size() - 1;
} }
int add_const(PyVar v){ int add_const(PyObject* v){
consts.push_back(v); consts.push_back(v);
return consts.size() - 1; return consts.size() - 1;
} }

View File

@ -57,7 +57,6 @@ namespace std = ::std;
struct Dummy { }; struct Dummy { };
struct DummyInstance { }; struct DummyInstance { };
struct DummyModule { }; struct DummyModule { };
#define DUMMY_VAL Dummy()
struct Type { struct Type {
int index; int index;
@ -85,4 +84,24 @@ struct Type {
const float kLocalsLoadFactor = 0.67f; const float kLocalsLoadFactor = 0.67f;
const float kInstAttrLoadFactor = 0.67f; const float kInstAttrLoadFactor = 0.67f;
const float kTypeAttrLoadFactor = 0.5f; const float kTypeAttrLoadFactor = 0.5f;
static_assert(sizeof(i64) == sizeof(int*));
static_assert(sizeof(f64) == sizeof(int*));
static_assert(std::numeric_limits<float>::is_iec559);
static_assert(std::numeric_limits<double>::is_iec559);
struct PyObject;
#define BITS(p) (reinterpret_cast<i64>(p))
inline bool is_tagged(PyObject* p) noexcept { return (BITS(p) & 0b11) != 0b00; }
inline bool is_int(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b01; }
inline bool is_float(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b10; }
inline bool is_both_int_or_float(PyObject* a, PyObject* b) noexcept {
return is_tagged(a) && is_tagged(b);
}
inline bool is_both_int(PyObject* a, PyObject* b) noexcept {
return is_int(a) && is_int(b);
}
} // namespace pkpy } // namespace pkpy

View File

@ -353,14 +353,14 @@ private:
} }
void exprLiteral() { void exprLiteral() {
PyVar value = parser->prev.value; PyObject* value = parser->prev.value;
int index = co()->add_const(value); int index = co()->add_const(value);
emit(OP_LOAD_CONST, index); emit(OP_LOAD_CONST, index);
} }
void exprFString() { void exprFString() {
static const std::regex pattern(R"(\{(.*?)\})"); static const std::regex pattern(R"(\{(.*?)\})");
PyVar value = parser->prev.value; PyObject* value = parser->prev.value;
Str s = CAST(Str, value); Str s = CAST(Str, value);
std::sregex_iterator begin(s.begin(), s.end(), pattern); std::sregex_iterator begin(s.begin(), s.end(), pattern);
std::sregex_iterator end; std::sregex_iterator end;
@ -1059,7 +1059,7 @@ private:
case 1: func.starred_arg = name; state+=1; break; case 1: func.starred_arg = name; state+=1; break;
case 2: { case 2: {
consume(TK("=")); consume(TK("="));
PyVarOrNull value = read_literal(); PyObject* value = read_literal();
if(value == nullptr){ if(value == nullptr){
SyntaxError(Str("expect a literal, not ") + TK_STR(parser->curr.type)); SyntaxError(Str("expect a literal, not ") + TK_STR(parser->curr.type));
} }
@ -1115,10 +1115,10 @@ private:
} }
} }
PyVarOrNull read_literal(){ PyObject* read_literal(){
if(match(TK("-"))){ if(match(TK("-"))){
consume(TK("@num")); consume(TK("@num"));
PyVar val = parser->prev.value; PyObject* val = parser->prev.value;
return vm->num_negated(val); return vm->num_negated(val);
} }
if(match(TK("@num"))) return parser->prev.value; if(match(TK("@num"))) return parser->prev.value;
@ -1166,7 +1166,7 @@ public:
code->optimize(vm); code->optimize(vm);
return code; return code;
}else if(mode()==JSON_MODE){ }else if(mode()==JSON_MODE){
PyVarOrNull value = read_literal(); PyObject* value = read_literal();
if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value)); if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value));
else if(match(TK("{"))) exprMap(); else if(match(TK("{"))) exprMap();
else if(match(TK("["))) exprList(); else if(match(TK("["))) exprList();

View File

@ -7,27 +7,27 @@ namespace pkpy{
static THREAD_LOCAL uint64_t kFrameGlobalId = 0; static THREAD_LOCAL uint64_t kFrameGlobalId = 0;
struct Frame { struct Frame {
std::vector<PyVar> _data; std::vector<PyObject*> _data;
int _ip = -1; int _ip = -1;
int _next_ip = 0; int _next_ip = 0;
const CodeObject* co; const CodeObject* co;
PyVar _module; PyObject* _module;
NameDict_ _locals; NameDict_ _locals;
NameDict_ _closure; NameDict_ _closure;
const uint64_t id; const uint64_t id;
std::vector<std::pair<int, std::vector<PyVar>>> s_try_block; std::vector<std::pair<int, std::vector<PyObject*>>> s_try_block;
inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); } inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
inline NameDict& f_globals() noexcept { return _module->attr(); } inline NameDict& f_globals() noexcept { return _module->attr(); }
inline PyVar* f_closure_try_get(StrName name) noexcept { inline PyObject** f_closure_try_get(StrName name) noexcept {
if(_closure == nullptr) return nullptr; if(_closure == nullptr) return nullptr;
return _closure->try_get(name); return _closure->try_get(name);
} }
Frame(const CodeObject_& co, Frame(const CodeObject_& co,
const PyVar& _module, PyObject* _module,
const NameDict_& _locals=nullptr, const NameDict_& _locals=nullptr,
const NameDict_& _closure=nullptr) const NameDict_& _closure=nullptr)
: co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) { } : co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) { }
@ -57,11 +57,11 @@ struct Frame {
return _next_ip < co->codes.size(); return _next_ip < co->codes.size();
} }
inline PyVar pop(){ inline PyObject* pop(){
#if PK_EXTRA_CHECK #if PK_EXTRA_CHECK
if(_data.empty()) throw std::runtime_error("_data.empty() is true"); if(_data.empty()) throw std::runtime_error("_data.empty() is true");
#endif #endif
PyVar v = std::move(_data.back()); PyObject* v = _data.back();
_data.pop_back(); _data.pop_back();
return v; return v;
} }
@ -73,28 +73,28 @@ struct Frame {
_data.pop_back(); _data.pop_back();
} }
inline void try_deref(VM*, PyVar&); inline void try_deref(VM*, PyObject*&);
inline PyVar pop_value(VM* vm){ inline PyObject* pop_value(VM* vm){
PyVar value = pop(); PyObject* value = pop();
try_deref(vm, value); try_deref(vm, value);
return value; return value;
} }
inline PyVar top_value(VM* vm){ inline PyObject* top_value(VM* vm){
PyVar value = top(); PyObject* value = top();
try_deref(vm, value); try_deref(vm, value);
return value; return value;
} }
inline PyVar& top(){ inline PyObject*& top(){
#if PK_EXTRA_CHECK #if PK_EXTRA_CHECK
if(_data.empty()) throw std::runtime_error("_data.empty() is true"); if(_data.empty()) throw std::runtime_error("_data.empty() is true");
#endif #endif
return _data.back(); return _data.back();
} }
inline PyVar& top_1(){ inline PyObject*& top_1(){
#if PK_EXTRA_CHECK #if PK_EXTRA_CHECK
if(_data.size() < 2) throw std::runtime_error("_data.size() < 2"); if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
#endif #endif
@ -117,7 +117,7 @@ struct Frame {
bool jump_to_exception_handler(){ bool jump_to_exception_handler(){
if(s_try_block.empty()) return false; if(s_try_block.empty()) return false;
PyVar obj = pop(); PyObject* obj = pop();
auto& p = s_try_block.back(); auto& p = s_try_block.back();
_data = std::move(p.second); _data = std::move(p.second);
_data.push_back(obj); _data.push_back(obj);

View File

@ -3,49 +3,38 @@
#include "obj.h" #include "obj.h"
namespace pkpy { namespace pkpy {
using PyVar0 = PyObject*; struct ManagedHeap{
std::vector<PyObject*> heap;
// a generational mark and sweep garbage collector template<typename T>
struct GC{ PyObject* gcnew(Type type, T&& val){
using Generation = std::vector<PyVar0>; PyObject* obj = new Py_<std::decay_t<T>>(type, std::forward<T>(val));
static const int kTotalGen = 3; obj->gc.enabled = true;
Generation gen[kTotalGen]; heap.push_back(obj);
return obj;
void add(PyVar0 obj){
if(!obj->need_gc) return;
gen[0].push_back(obj);
} }
void sweep(int index){ void sweep(){
Generation& g = gen[index]; std::vector<PyObject*> alive;
if(index < kTotalGen-1){ for(PyObject* obj: heap){
for(int i=0; i<g.size(); i++){ if(obj->gc.marked){
if(g[i]->marked){ obj->gc.marked = false;
g[i]->marked = false; alive.push_back(obj);
gen[index+1].push_back(g[i]); }else{
}else{ delete obj;
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);
} }
heap.clear();
heap.swap(alive);
} }
void collect(int index){ void collect(VM* vm){
sweep(index); std::vector<PyObject*> roots = get_roots(vm);
for(PyObject* obj: roots) obj->mark();
sweep();
} }
std::vector<PyObject*> get_roots(VM* vm);
}; };
} // namespace pkpy } // namespace pkpy

View File

@ -42,7 +42,7 @@ struct FileIO {
if(!_fs.is_open()) vm->IOError(strerror(errno)); if(!_fs.is_open()) vm->IOError(strerror(errno));
} }
static void _register(VM* vm, PyVar mod, PyVar type){ static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){ vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
return VAR_T(FileIO, return VAR_T(FileIO,
vm, CAST(Str, args[0]), CAST(Str, args[1]) vm, CAST(Str, args[0]), CAST(Str, args[1])
@ -79,15 +79,15 @@ struct FileIO {
}; };
void add_module_io(VM* vm){ void add_module_io(VM* vm){
PyVar mod = vm->new_module("io"); PyObject* mod = vm->new_module("io");
PyVar type = FileIO::register_class(vm, mod); PyObject* type = FileIO::register_class(vm, mod);
vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){ vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
return vm->call(type, args); return vm->call(type, args);
}); });
} }
void add_module_os(VM* vm){ void add_module_os(VM* vm){
PyVar mod = vm->new_module("os"); PyObject* mod = vm->new_module("os");
// Working directory is shared by all VMs!! // Working directory is shared by all VMs!!
vm->bind_func<0>(mod, "getcwd", [](VM* vm, const Args& args){ vm->bind_func<0>(mod, "getcwd", [](VM* vm, const Args& args){
return VAR(std::filesystem::current_path().string()); return VAR(std::filesystem::current_path().string());

View File

@ -8,7 +8,7 @@ class RangeIter : public BaseIter {
i64 current; i64 current;
Range r; Range r;
public: public:
RangeIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { RangeIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) {
this->r = OBJ_GET(Range, _ref); this->r = OBJ_GET(Range, _ref);
this->current = r.start; this->current = r.start;
} }
@ -17,7 +17,7 @@ public:
return r.step > 0 ? current < r.stop : current > r.stop; return r.step > 0 ? current < r.stop : current > r.stop;
} }
PyVar next(){ PyObject* next(){
if(!_has_next()) return nullptr; if(!_has_next()) return nullptr;
current += r.step; current += r.step;
return VAR(current-r.step); return VAR(current-r.step);
@ -29,8 +29,8 @@ class ArrayIter : public BaseIter {
size_t index = 0; size_t index = 0;
const T* p; const T* p;
public: public:
ArrayIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);} ArrayIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) { p = &OBJ_GET(T, _ref);}
PyVar next(){ PyObject* next(){
if(index == p->size()) return nullptr; if(index == p->size()) return nullptr;
return p->operator[](index++); return p->operator[](index++);
} }
@ -40,20 +40,20 @@ class StringIter : public BaseIter {
int index = 0; int index = 0;
Str* str; Str* str;
public: public:
StringIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) { StringIter(VM* vm, PyObject* _ref) : BaseIter(vm, _ref) {
str = &OBJ_GET(Str, _ref); str = &OBJ_GET(Str, _ref);
} }
PyVar next() { PyObject* next() {
if(index == str->u8_length()) return nullptr; if(index == str->u8_length()) return nullptr;
return VAR(str->u8_getitem(index++)); return VAR(str->u8_getitem(index++));
} }
}; };
PyVar Generator::next(){ PyObject* Generator::next(){
if(state == 2) return nullptr; if(state == 2) return nullptr;
vm->callstack.push(std::move(frame)); vm->callstack.push(std::move(frame));
PyVar ret = vm->_exec(); PyObject* ret = vm->_exec();
if(ret == vm->_py_op_yield){ if(ret == vm->_py_op_yield){
frame = std::move(vm->callstack.top()); frame = std::move(vm->callstack.top());
vm->callstack.pop(); vm->callstack.pop();

View File

@ -75,7 +75,7 @@ int main(int argc, char** argv){
// set parent path as cwd // set parent path as cwd
std::filesystem::current_path(filepath.parent_path()); std::filesystem::current_path(filepath.parent_path());
pkpy::PyVarOrNull ret = nullptr; pkpy::PyObject* ret = nullptr;
ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE); ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE);
pkpy_delete(vm); pkpy_delete(vm);
return ret != nullptr ? 0 : 1; return ret != nullptr ? 0 : 1;

View File

@ -4,31 +4,12 @@
namespace pkpy{ namespace pkpy{
struct PyObject;
template<typename T>
struct SpAllocator {
template<typename U>
inline static int* alloc(){
return (int*)malloc(sizeof(int) + sizeof(U));
}
inline static void dealloc(int* counter){
((T*)(counter + 1))->~T();
free(counter);
}
};
template <typename T> template <typename T>
struct shared_ptr { struct shared_ptr {
union { int* counter;
int* counter;
i64 bits;
};
#define _t() (T*)(counter + 1) #define _t() (T*)(counter + 1)
#define _inc_counter() if(!is_tagged() && counter) ++(*counter) #define _inc_counter() if(counter) ++(*counter)
#define _dec_counter() if(!is_tagged() && counter && --(*counter) == 0) SpAllocator<T>::dealloc(counter) #define _dec_counter() if(counter && --(*counter) == 0) {((T*)(counter + 1))->~T(); free(counter);}
public: public:
shared_ptr() : counter(nullptr) {} shared_ptr() : counter(nullptr) {}
@ -69,7 +50,6 @@ public:
T* get() const { return _t(); } T* get() const { return _t(); }
int use_count() const { int use_count() const {
if(is_tagged()) return 0;
return counter ? *counter : 0; return counter ? *counter : 0;
} }
@ -77,44 +57,20 @@ public:
_dec_counter(); _dec_counter();
counter = nullptr; counter = nullptr;
} }
inline constexpr bool is_tagged() const {
if constexpr(!std::is_same_v<T, PyObject>) return false;
return (bits & 0b11) != 0b00;
}
inline bool is_tag_00() const { return (bits & 0b11) == 0b00; }
inline bool is_tag_01() const { return (bits & 0b11) == 0b01; }
inline bool is_tag_10() const { return (bits & 0b11) == 0b10; }
inline bool is_tag_11() const { return (bits & 0b11) == 0b11; }
}; };
#undef _t #undef _t
#undef _inc_counter #undef _inc_counter
#undef _dec_counter #undef _dec_counter
template <typename T, typename U, typename... Args>
shared_ptr<T> make_sp(Args&&... args) {
static_assert(std::is_base_of_v<T, U>, "U must be derived from T");
static_assert(std::has_virtual_destructor_v<T>, "T must have virtual destructor");
static_assert(!std::is_same_v<T, PyObject> || (!std::is_same_v<U, i64> && !std::is_same_v<U, f64>));
int* p = SpAllocator<T>::template alloc<U>(); *p = 1;
new(p+1) U(std::forward<Args>(args)...);
return shared_ptr<T>(p);
}
template <typename T, typename... Args> template <typename T, typename... Args>
shared_ptr<T> make_sp(Args&&... args) { shared_ptr<T> make_sp(Args&&... args) {
int* p = SpAllocator<T>::template alloc<T>(); *p = 1; int* p = (int*)malloc(sizeof(int) + sizeof(T));
*p = 1;
new(p+1) T(std::forward<Args>(args)...); new(p+1) T(std::forward<Args>(args)...);
return shared_ptr<T>(p); return shared_ptr<T>(p);
} }
static_assert(sizeof(i64) == sizeof(int*));
static_assert(sizeof(f64) == sizeof(int*));
static_assert(sizeof(shared_ptr<PyObject>) == sizeof(int*));
static_assert(std::numeric_limits<float>::is_iec559);
static_assert(std::numeric_limits<double>::is_iec559);
template<typename T, int __Bucket, int __BucketSize=32> template<typename T, int __Bucket, int __BucketSize=32>
struct SmallArrayPool { struct SmallArrayPool {
std::vector<T*> buckets[__Bucket+1]; std::vector<T*> buckets[__Bucket+1];
@ -145,10 +101,4 @@ struct SmallArrayPool {
} }
} }
}; };
typedef shared_ptr<PyObject> PyVar;
typedef PyVar PyVarOrNull;
typedef PyVar PyVarRef;
}; // namespace pkpy }; // namespace pkpy

View File

@ -6,7 +6,7 @@
namespace pkpy{ namespace pkpy{
const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyVar); const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyObject*);
template<int __Bucket, int __BucketSize=32> template<int __Bucket, int __BucketSize=32>
struct DictArrayPool { struct DictArrayPool {
@ -26,9 +26,7 @@ struct DictArrayPool {
} }
void dealloc(StrName* head, uint16_t n){ void dealloc(StrName* head, uint16_t n){
PyVar* _values = (PyVar*)(head + n);
if(n > __Bucket || buckets[n].size() >= __BucketSize){ if(n > __Bucket || buckets[n].size() >= __BucketSize){
for(int i=0; i<n; i++) _values[i].~PyVar();
free(head); free(head);
}else{ }else{
buckets[n].push_back(head); buckets[n].push_back(head);
@ -75,12 +73,12 @@ struct NameDict {
uint16_t _mask; uint16_t _mask;
StrName* _keys; StrName* _keys;
inline PyVar& value(uint16_t i){ inline PyObject*& value(uint16_t i){
return reinterpret_cast<PyVar*>(_keys + _capacity)[i]; return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
} }
inline const PyVar& value(uint16_t i) const { inline PyObject* value(uint16_t i) const {
return reinterpret_cast<const PyVar*>(_keys + _capacity)[i]; return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
} }
NameDict(uint16_t capacity=2, float load_factor=0.67, uint16_t hash_seed=kHashSeeds[0]): NameDict(uint16_t capacity=2, float load_factor=0.67, uint16_t hash_seed=kHashSeeds[0]):
@ -123,19 +121,19 @@ while(!_keys[i].empty()) { \
i = (i + 1) & _mask; \ i = (i + 1) & _mask; \
} }
const PyVar& operator[](StrName key) const { PyObject* operator[](StrName key) const {
bool ok; uint16_t i; bool ok; uint16_t i;
HASH_PROBE(key, ok, i); HASH_PROBE(key, ok, i);
if(!ok) throw std::out_of_range("NameDict key not found: " + key.str()); if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
return value(i); return value(i);
} }
PyVar& get(StrName key){ // PyObject*& get(StrName key){
bool ok; uint16_t i; // bool ok; uint16_t i;
HASH_PROBE(key, ok, i); // HASH_PROBE(key, ok, i);
if(!ok) throw std::out_of_range("NameDict key not found: " + key.str()); // if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
return value(i); // return value(i);
} // }
template<typename T> template<typename T>
void set(StrName key, T&& val){ void set(StrName key, T&& val){
@ -154,7 +152,7 @@ while(!_keys[i].empty()) { \
void _rehash(bool resize){ void _rehash(bool resize){
StrName* old_keys = _keys; StrName* old_keys = _keys;
PyVar* old_values = &value(0); PyObject** old_values = &value(0);
uint16_t old_capacity = _capacity; uint16_t old_capacity = _capacity;
if(resize){ if(resize){
_capacity = find_next_capacity(_capacity * 2); _capacity = find_next_capacity(_capacity * 2);
@ -177,18 +175,18 @@ while(!_keys[i].empty()) { \
_rehash(false); // do not resize _rehash(false); // do not resize
} }
inline PyVar* try_get(StrName key){ inline PyObject** try_get(StrName key){
bool ok; uint16_t i; bool ok; uint16_t i;
HASH_PROBE(key, ok, i); HASH_PROBE(key, ok, i);
if(!ok) return nullptr; if(!ok) return nullptr;
return &value(i); return &value(i);
} }
inline bool try_set(StrName key, PyVar&& val){ inline bool try_set(StrName key, PyObject* val){
bool ok; uint16_t i; bool ok; uint16_t i;
HASH_PROBE(key, ok, i); HASH_PROBE(key, ok, i);
if(!ok) return false; if(!ok) return false;
value(i) = std::move(val); value(i) = val;
return true; return true;
} }
@ -213,8 +211,8 @@ while(!_keys[i].empty()) { \
_size--; _size--;
} }
std::vector<std::pair<StrName, PyVar>> items() const { std::vector<std::pair<StrName, PyObject*>> items() const {
std::vector<std::pair<StrName, PyVar>> v; std::vector<std::pair<StrName, PyObject*>> v;
for(uint16_t i=0; i<_capacity; i++){ for(uint16_t i=0; i<_capacity; i++){
if(_keys[i].empty()) continue; if(_keys[i].empty()) continue;
v.push_back(std::make_pair(_keys[i], value(i))); v.push_back(std::make_pair(_keys[i], value(i)));
@ -231,7 +229,7 @@ while(!_keys[i].empty()) { \
return v; return v;
} }
void apply_v(void(*f)(PyVar)) { void apply_v(void(*f)(PyObject*)) {
for(uint16_t i=0; i<_capacity; i++){ for(uint16_t i=0; i<_capacity; i++){
if(_keys[i].empty()) continue; if(_keys[i].empty()) continue;
f(value(i)); f(value(i));

View File

@ -12,7 +12,7 @@ struct Frame;
struct BaseRef; struct BaseRef;
class VM; class VM;
typedef std::function<PyVar(VM*, Args&)> NativeFuncRaw; typedef std::function<PyObject*(VM*, Args&)> NativeFuncRaw;
typedef shared_ptr<CodeObject> CodeObject_; typedef shared_ptr<CodeObject> CodeObject_;
typedef shared_ptr<NameDict> NameDict_; typedef shared_ptr<NameDict> NameDict_;
@ -22,7 +22,7 @@ struct NativeFunc {
bool method; bool method;
NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {} NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {}
inline PyVar operator()(VM* vm, Args& args) const; inline PyObject* operator()(VM* vm, Args& args) const;
}; };
struct Function { struct Function {
@ -34,7 +34,7 @@ struct Function {
std::vector<StrName> kwargs_order; std::vector<StrName> kwargs_order;
// runtime settings // runtime settings
PyVar _module = nullptr; PyObject* _module = nullptr;
NameDict_ _closure = nullptr; NameDict_ _closure = nullptr;
bool has_name(StrName val) const { bool has_name(StrName val) const {
@ -46,9 +46,9 @@ struct Function {
}; };
struct BoundMethod { struct BoundMethod {
PyVar obj; PyObject* obj;
PyVar method; PyObject* method;
BoundMethod(const PyVar& obj, const PyVar& method) : obj(obj), method(method) {} BoundMethod(PyObject* obj, PyObject* method) : obj(obj), method(method) {}
}; };
struct Range { struct Range {
@ -58,9 +58,9 @@ struct Range {
}; };
struct StarWrapper { struct StarWrapper {
PyVar obj; PyObject* obj;
bool rvalue; bool rvalue;
StarWrapper(const PyVar& obj, bool rvalue): obj(obj), rvalue(rvalue) {} StarWrapper(PyObject* obj, bool rvalue): obj(obj), rvalue(rvalue) {}
}; };
struct Slice { struct Slice {
@ -79,30 +79,34 @@ struct Slice {
class BaseIter { class BaseIter {
protected: protected:
VM* vm; VM* vm;
PyVar _ref; // keep a reference to the object so it will not be deleted while iterating PyObject* _ref; // keep a reference to the object so it will not be deleted while iterating
public: public:
virtual PyVar next() = 0; virtual PyObject* next() = 0;
PyVarRef loop_var; PyObject* loop_var;
BaseIter(VM* vm, PyVar _ref) : vm(vm), _ref(_ref) {} BaseIter(VM* vm, PyObject* _ref) : vm(vm), _ref(_ref) {}
virtual ~BaseIter() = default; virtual ~BaseIter() = default;
}; };
struct GCHeader {
bool enabled; // whether this object is managed by GC
bool marked; // whether this object is marked
GCHeader() : enabled(false), marked(false) {}
};
struct PyObject { struct PyObject {
bool need_gc; GCHeader gc;
bool marked;
/**********/
Type type; Type type;
NameDict* _attr; NameDict* _attr;
inline bool is_attr_valid() const noexcept { return _attr != nullptr; } inline bool is_attr_valid() const noexcept { return _attr != nullptr; }
inline NameDict& attr() noexcept { return *_attr; } inline NameDict& attr() noexcept { return *_attr; }
inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); } inline PyObject* attr(StrName name) const noexcept { return (*_attr)[name]; }
virtual void* value() = 0; virtual void* value() = 0;
virtual void mark() { virtual void mark() {
if(!need_gc || marked) return; if(!gc.enabled || gc.marked) return;
marked = true; gc.marked = true;
if(is_attr_valid()) attr().apply_v([](PyVar v){ v->mark(); }); if(is_attr_valid()) attr().apply_v([](PyObject* v){ v->mark(); });
} }
PyObject(Type type) : type(type) {} PyObject(Type type) : type(type) {}
@ -141,67 +145,51 @@ struct Py_ : PyObject {
const int kTpIntIndex = 2; const int kTpIntIndex = 2;
const int kTpFloatIndex = 3; const int kTpFloatIndex = 3;
inline bool is_type(const PyVar& obj, Type type) noexcept { inline bool is_type(PyObject* obj, Type type) noexcept {
switch(type.index){ switch(type.index){
case kTpIntIndex: return obj.is_tag_01(); case kTpIntIndex: return is_tag_01(obj);
case kTpFloatIndex: return obj.is_tag_10(); case kTpFloatIndex: return is_tag_10(obj);
default: return !obj.is_tagged() && obj->type == type; default: return !is_tagged(obj) && obj->type == type;
} }
} }
inline bool is_both_int_or_float(const PyVar& a, const PyVar& b) noexcept {
return a.is_tagged() && b.is_tagged();
}
inline bool is_both_int(const PyVar& a, const PyVar& b) noexcept {
return (a.bits & b.bits & 0b11) == 0b01;
}
inline bool is_int(const PyVar& obj) noexcept {
return obj.is_tag_01();
}
inline bool is_float(const PyVar& obj) noexcept {
return obj.is_tag_10();
}
#define PY_CLASS(T, mod, name) \ #define PY_CLASS(T, mod, name) \
static Type _type(VM* vm) { \ static Type _type(VM* vm) { \
static const StrName __x0(#mod); \ static const StrName __x0(#mod); \
static const StrName __x1(#name); \ static const StrName __x1(#name); \
return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \ return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \
} \ } \
static PyVar register_class(VM* vm, PyVar mod) { \ static PyObject* register_class(VM* vm, PyObject* mod) { \
PyVar type = vm->new_type_object(mod, #name, vm->tp_object); \ PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \
if(OBJ_NAME(mod) != #mod) UNREACHABLE(); \ if(OBJ_NAME(mod) != #mod) UNREACHABLE(); \
T::_register(vm, mod, type); \ T::_register(vm, mod, type); \
type->attr()._try_perfect_rehash(); \ type->attr()._try_perfect_rehash(); \
return type; \ return type; \
} }
union __8B { union BitsCvt {
i64 _int; i64 _int;
f64 _float; f64 _float;
__8B(i64 val) : _int(val) {} BitsCvt(i64 val) : _int(val) {}
__8B(f64 val) : _float(val) {} BitsCvt(f64 val) : _float(val) {}
}; };
template <typename, typename = void> struct is_py_class : std::false_type {}; template <typename, typename = void> struct is_py_class : std::false_type {};
template <typename T> struct is_py_class<T, std::void_t<decltype(T::_type)>> : std::true_type {}; template <typename T> struct is_py_class<T, std::void_t<decltype(T::_type)>> : std::true_type {};
template<typename T> template<typename T>
void _check_py_class(VM* vm, const PyVar& var); void _check_py_class(VM* vm, PyObject* var);
template<typename T> template<typename T>
T py_pointer_cast(VM* vm, const PyVar& var); T py_pointer_cast(VM* vm, PyObject* var);
template<typename T> template<typename T>
T py_value_cast(VM* vm, const PyVar& var); T py_value_cast(VM* vm, PyObject* var);
struct Discarded {}; struct Discarded {};
template<typename __T> template<typename __T>
__T py_cast(VM* vm, const PyVar& obj) { __T py_cast(VM* vm, PyObject* obj) {
using T = std::decay_t<__T>; using T = std::decay_t<__T>;
if constexpr(std::is_pointer_v<T>){ if constexpr(std::is_pointer_v<T>){
return py_pointer_cast<T>(vm, obj); return py_pointer_cast<T>(vm, obj);
@ -216,7 +204,7 @@ __T py_cast(VM* vm, const PyVar& obj) {
} }
template<typename __T> template<typename __T>
__T _py_cast(VM* vm, const PyVar& obj) { __T _py_cast(VM* vm, PyObject* obj) {
using T = std::decay_t<__T>; using T = std::decay_t<__T>;
if constexpr(std::is_pointer_v<__T>){ if constexpr(std::is_pointer_v<__T>){
return py_pointer_cast<__T>(vm, obj); return py_pointer_cast<__T>(vm, obj);
@ -228,7 +216,7 @@ __T _py_cast(VM* vm, const PyVar& obj) {
} }
#define VAR(x) py_var(vm, x) #define VAR(x) py_var(vm, x)
#define VAR_T(T, ...) vm->new_object(T::_type(vm), T(__VA_ARGS__)) #define VAR_T(T, ...) vm->heap.gcnew<T>(T::_type(vm), T(__VA_ARGS__))
#define CAST(T, x) py_cast<T>(vm, x) #define CAST(T, x) py_cast<T>(vm, x)
#define _CAST(T, x) _py_cast<T>(vm, x) #define _CAST(T, x) _py_cast<T>(vm, x)

View File

@ -54,7 +54,7 @@ struct Token{
const char* start; const char* start;
int length; int length;
int line; int line;
PyVar value; PyObject* value;
Str str() const { return Str(start, length);} Str str() const { return Str(start, length);}
@ -271,7 +271,7 @@ struct Parser {
return true; return true;
} }
void set_next_token(TokenIndex type, PyVar value=nullptr) { void set_next_token(TokenIndex type, PyObject* value=nullptr) {
switch(type){ switch(type){
case TK("{"): case TK("["): case TK("("): brackets_level++; break; case TK("{"): case TK("["): case TK("("): brackets_level++; break;
case TK(")"): case TK("]"): case TK("}"): brackets_level--; break; case TK(")"): case TK("]"): case TK("}"): brackets_level--; break;

View File

@ -69,7 +69,7 @@ void init_builtins(VM* _vm) {
vm->TypeError("super(type, obj): obj must be an instance or subtype of type"); vm->TypeError("super(type, obj): obj must be an instance or subtype of type");
} }
Type base = vm->_all_types[type.index].base; Type base = vm->_all_types[type.index].base;
return vm->new_object(vm->tp_super, Super(args[1], base)); return vm->heap.gcnew(vm->tp_super, Super(args[1], base));
}); });
_vm->bind_builtin_func<2>("isinstance", [](VM* vm, Args& args) { _vm->bind_builtin_func<2>("isinstance", [](VM* vm, Args& args) {
@ -79,16 +79,16 @@ void init_builtins(VM* _vm) {
}); });
_vm->bind_builtin_func<1>("id", [](VM* vm, Args& args) { _vm->bind_builtin_func<1>("id", [](VM* vm, Args& args) {
const PyVar& obj = args[0]; PyObject* obj = args[0];
if(obj.is_tagged()) return VAR((i64)0); if(is_tagged(obj)) return VAR((i64)0);
return VAR(obj.bits); return VAR(BITS(obj));
}); });
_vm->bind_builtin_func<2>("divmod", [](VM* vm, Args& args) { _vm->bind_builtin_func<2>("divmod", [](VM* vm, Args& args) {
i64 lhs = CAST(i64, args[0]); i64 lhs = CAST(i64, args[0]);
i64 rhs = CAST(i64, args[1]); i64 rhs = CAST(i64, args[1]);
if(rhs == 0) vm->ZeroDivisionError(); if(rhs == 0) vm->ZeroDivisionError();
return VAR(two_args(VAR(lhs/rhs), VAR(lhs%rhs))); return VAR(Tuple{VAR(lhs/rhs), VAR(lhs%rhs)});
}); });
_vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) { _vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) {
@ -169,8 +169,8 @@ void init_builtins(VM* _vm) {
}); });
_vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) { _vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) {
PyVar self = args[0]; PyObject* self = args[0];
std::uintptr_t addr = self.is_tagged() ? 0 : (uintptr_t)self.get(); std::uintptr_t addr = is_tagged(self) ? 0 : (uintptr_t)self;
StrStream ss; StrStream ss;
ss << std::hex << addr; ss << std::hex << addr;
Str s = "<" + OBJ_NAME(vm->_t(self)) + " object at 0x" + ss.str() + ">"; Str s = "<" + OBJ_NAME(vm->_t(self)) + " object at 0x" + ss.str() + ">";
@ -405,7 +405,7 @@ void init_builtins(VM* _vm) {
_vm->bind_method<1>("str", "join", [](VM* vm, Args& args) { _vm->bind_method<1>("str", "join", [](VM* vm, Args& args) {
const Str& self = CAST(Str&, args[0]); const Str& self = CAST(Str&, args[0]);
StrStream ss; StrStream ss;
PyVar obj = vm->asList(args[1]); PyObject* obj = vm->asList(args[1]);
const List& list = CAST(List&, obj); const List& list = CAST(List&, obj);
for (int i = 0; i < list.size(); ++i) { for (int i = 0; i < list.size(); ++i) {
if (i > 0) ss << self; if (i > 0) ss << self;
@ -423,7 +423,7 @@ void init_builtins(VM* _vm) {
_vm->bind_method<1>("list", "extend", [](VM* vm, Args& args) { _vm->bind_method<1>("list", "extend", [](VM* vm, Args& args) {
List& self = CAST(List&, args[0]); List& self = CAST(List&, args[0]);
PyVar obj = vm->asList(args[1]); PyObject* obj = vm->asList(args[1]);
const List& list = CAST(List&, obj); const List& list = CAST(List&, obj);
self.insert(self.end(), list.begin(), list.end()); self.insert(self.end(), list.begin(), list.end());
return vm->None; return vm->None;
@ -575,7 +575,7 @@ void init_builtins(VM* _vm) {
#endif #endif
void add_module_time(VM* vm){ void add_module_time(VM* vm){
PyVar mod = vm->new_module("time"); PyObject* mod = vm->new_module("time");
vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) { vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) {
auto now = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now();
return VAR(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0); return VAR(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0);
@ -583,7 +583,7 @@ void add_module_time(VM* vm){
} }
void add_module_sys(VM* vm){ void add_module_sys(VM* vm){
PyVar mod = vm->new_module("sys"); PyObject* mod = vm->new_module("sys");
vm->setattr(mod, "version", VAR(PK_VERSION)); vm->setattr(mod, "version", VAR(PK_VERSION));
vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(VAR(args[0].use_count()))); vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(VAR(args[0].use_count())));
@ -596,7 +596,7 @@ void add_module_sys(VM* vm){
} }
void add_module_json(VM* vm){ void add_module_json(VM* vm){
PyVar mod = vm->new_module("json"); PyObject* mod = vm->new_module("json");
vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) { vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) {
const Str& expr = CAST(Str&, args[0]); const Str& expr = CAST(Str&, args[0]);
CodeObject_ code = vm->compile(expr, "<json>", JSON_MODE); CodeObject_ code = vm->compile(expr, "<json>", JSON_MODE);
@ -607,7 +607,7 @@ void add_module_json(VM* vm){
} }
void add_module_math(VM* vm){ void add_module_math(VM* vm){
PyVar mod = vm->new_module("math"); PyObject* mod = vm->new_module("math");
vm->setattr(mod, "pi", VAR(3.1415926535897932384)); vm->setattr(mod, "pi", VAR(3.1415926535897932384));
vm->setattr(mod, "e" , VAR(2.7182818284590452354)); vm->setattr(mod, "e" , VAR(2.7182818284590452354));
@ -626,9 +626,9 @@ void add_module_math(VM* vm){
} }
void add_module_dis(VM* vm){ void add_module_dis(VM* vm){
PyVar mod = vm->new_module("dis"); PyObject* mod = vm->new_module("dis");
vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) { vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) {
PyVar f = args[0]; PyObject* f = args[0];
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, args[0]).method; if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, args[0]).method;
CodeObject_ code = CAST(Function, f).code; CodeObject_ code = CAST(Function, f).code;
(*vm->_stdout) << vm->disassemble(code); (*vm->_stdout) << vm->disassemble(code);
@ -644,14 +644,14 @@ struct ReMatch {
std::smatch m; std::smatch m;
ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {} ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {}
static void _register(VM* vm, PyVar mod, PyVar type){ static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED()); vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED());
vm->bind_method<0>(type, "start", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).start))); vm->bind_method<0>(type, "start", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).start)));
vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).end))); vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).end)));
vm->bind_method<0>(type, "span", [](VM* vm, Args& args) { vm->bind_method<0>(type, "span", [](VM* vm, Args& args) {
auto& self = CAST(ReMatch&, args[0]); auto& self = CAST(ReMatch&, args[0]);
return VAR(two_args(VAR(self.start), VAR(self.end))); return VAR(Tuple{VAR(self.start), VAR(self.end)});
}); });
vm->bind_method<1>(type, "group", [](VM* vm, Args& args) { vm->bind_method<1>(type, "group", [](VM* vm, Args& args) {
@ -663,7 +663,7 @@ struct ReMatch {
} }
}; };
PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* vm){ PyObject* _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* vm){
std::regex re(pattern); std::regex re(pattern);
std::smatch m; std::smatch m;
if(std::regex_search(string, m, re)){ if(std::regex_search(string, m, re)){
@ -676,7 +676,7 @@ PyVar _regex_search(const Str& pattern, const Str& string, bool fromStart, VM* v
}; };
void add_module_re(VM* vm){ void add_module_re(VM* vm){
PyVar mod = vm->new_module("re"); PyObject* mod = vm->new_module("re");
ReMatch::register_class(vm, mod); ReMatch::register_class(vm, mod);
vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) { vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) {
@ -740,7 +740,7 @@ struct Random{
gen.seed(seed); gen.seed(seed);
} }
static void _register(VM* vm, PyVar mod, PyVar type){ static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random))); vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random)));
vm->bind_method<1>(type, "seed", native_proxy_callable(&Random::seed)); vm->bind_method<1>(type, "seed", native_proxy_callable(&Random::seed));
vm->bind_method<2>(type, "randint", native_proxy_callable(&Random::randint)); vm->bind_method<2>(type, "randint", native_proxy_callable(&Random::randint));
@ -750,7 +750,7 @@ struct Random{
}; };
void add_module_random(VM* vm){ void add_module_random(VM* vm){
PyVar mod = vm->new_module("random"); PyObject* mod = vm->new_module("random");
Random::register_class(vm, mod); Random::register_class(vm, mod);
CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE); CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE);
vm->_exec(code, mod); vm->_exec(code, mod);
@ -851,7 +851,7 @@ extern "C" {
/// Return `__repr__` of the result. /// Return `__repr__` of the result.
/// If the variable is not found, return `nullptr`. /// If the variable is not found, return `nullptr`.
char* pkpy_vm_get_global(pkpy::VM* vm, const char* name){ char* pkpy_vm_get_global(pkpy::VM* vm, const char* name){
pkpy::PyVar* val = vm->_main->attr().try_get(name); pkpy::PyObject** val = vm->_main->attr().try_get(name);
if(val == nullptr) return nullptr; if(val == nullptr) return nullptr;
try{ try{
pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(*val)); pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(*val));
@ -867,7 +867,7 @@ extern "C" {
/// Return `__repr__` of the result. /// Return `__repr__` of the result.
/// If there is any error, return `nullptr`. /// If there is any error, return `nullptr`.
char* pkpy_vm_eval(pkpy::VM* vm, const char* source){ char* pkpy_vm_eval(pkpy::VM* vm, const char* source){
pkpy::PyVarOrNull ret = vm->exec(source, "<eval>", pkpy::EVAL_MODE); pkpy::PyObject* ret = vm->exec(source, "<eval>", pkpy::EVAL_MODE);
if(ret == nullptr) return nullptr; if(ret == nullptr) return nullptr;
try{ try{
pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret)); pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret));
@ -950,13 +950,13 @@ extern "C" {
for(int i=0; mod[i]; i++) if(mod[i] == ' ') return nullptr; for(int i=0; mod[i]; i++) if(mod[i] == ' ') return nullptr;
for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr; for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr;
std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++); std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++);
pkpy::PyVar obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod); pkpy::PyObject* obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod);
vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){ vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){
pkpy::StrStream ss; pkpy::StrStream ss;
ss << f_header; ss << f_header;
for(int i=0; i<args.size(); i++){ for(int i=0; i<args.size(); i++){
ss << ' '; ss << ' ';
pkpy::PyVar x = vm->call(args[i], pkpy::__json__); pkpy::PyObject* x = vm->call(args[i], pkpy::__json__);
ss << pkpy::CAST(pkpy::Str&, x); ss << pkpy::CAST(pkpy::Str&, x);
} }
char* packet = strdup(ss.str().c_str()); char* packet = strdup(ss.str().c_str());

View File

@ -6,8 +6,8 @@
namespace pkpy { namespace pkpy {
struct BaseRef { struct BaseRef {
virtual PyVar get(VM*, Frame*) const = 0; virtual PyObject* get(VM*, Frame*) const = 0;
virtual void set(VM*, Frame*, PyVar) const = 0; virtual void set(VM*, Frame*, PyObject*) const = 0;
virtual void del(VM*, Frame*) const = 0; virtual void del(VM*, Frame*) const = 0;
virtual ~BaseRef() = default; virtual ~BaseRef() = default;
}; };
@ -18,8 +18,8 @@ struct NameRef : BaseRef {
inline NameScope scope() const { return pair.second; } inline NameScope scope() const { return pair.second; }
NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {} NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {}
PyVar get(VM* vm, Frame* frame) const{ PyObject* get(VM* vm, Frame* frame) const{
PyVar* val; PyObject** val;
val = frame->f_locals().try_get(name()); val = frame->f_locals().try_get(name());
if(val != nullptr) return *val; if(val != nullptr) return *val;
val = frame->f_closure_try_get(name()); val = frame->f_closure_try_get(name());
@ -32,12 +32,12 @@ struct NameRef : BaseRef {
return nullptr; return nullptr;
} }
void set(VM* vm, Frame* frame, PyVar val) const{ void set(VM* vm, Frame* frame, PyObject* val) const{
switch(scope()) { switch(scope()) {
case NAME_LOCAL: frame->f_locals().set(name(), std::move(val)); break; case NAME_LOCAL: frame->f_locals().set(name(), val); break;
case NAME_GLOBAL: case NAME_GLOBAL:
if(frame->f_locals().try_set(name(), std::move(val))) return; if(frame->f_locals().try_set(name(), val)) return;
frame->f_globals().set(name(), std::move(val)); frame->f_globals().set(name(), val);
break; break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
@ -70,15 +70,15 @@ struct NameRef : BaseRef {
}; };
struct AttrRef : BaseRef { struct AttrRef : BaseRef {
mutable PyVar obj; mutable PyObject* obj;
NameRef attr; NameRef attr;
AttrRef(PyVar obj, NameRef attr) : obj(obj), attr(attr) {} AttrRef(PyObject* obj, NameRef attr) : obj(obj), attr(attr) {}
PyVar get(VM* vm, Frame* frame) const{ PyObject* get(VM* vm, Frame* frame) const{
return vm->getattr(obj, attr.name()); return vm->getattr(obj, attr.name());
} }
void set(VM* vm, Frame* frame, PyVar val) const{ void set(VM* vm, Frame* frame, PyObject* val) const{
vm->setattr(obj, attr.name(), std::move(val)); vm->setattr(obj, attr.name(), std::move(val));
} }
@ -90,22 +90,22 @@ struct AttrRef : BaseRef {
}; };
struct IndexRef : BaseRef { struct IndexRef : BaseRef {
mutable PyVar obj; mutable PyObject* obj;
PyVar index; PyObject* index;
IndexRef(PyVar obj, PyVar index) : obj(obj), index(index) {} IndexRef(PyObject* obj, PyObject* index) : obj(obj), index(index) {}
PyVar get(VM* vm, Frame* frame) const{ PyObject* get(VM* vm, Frame* frame) const{
return vm->fast_call(__getitem__, two_args(obj, index)); return vm->fast_call(__getitem__, Args{obj, index});
} }
void set(VM* vm, Frame* frame, PyVar val) const{ void set(VM* vm, Frame* frame, PyObject* val) const{
Args args(3); Args args(3);
args[0] = obj; args[1] = index; args[2] = std::move(val); args[0] = obj; args[1] = index; args[2] = std::move(val);
vm->fast_call(__setitem__, std::move(args)); vm->fast_call(__setitem__, std::move(args));
} }
void del(VM* vm, Frame* frame) const{ void del(VM* vm, Frame* frame) const{
vm->fast_call(__delitem__, two_args(obj, index)); vm->fast_call(__delitem__, Args{obj, index});
} }
}; };
@ -113,7 +113,7 @@ struct TupleRef : BaseRef {
Tuple objs; Tuple objs;
TupleRef(Tuple&& objs) : objs(std::move(objs)) {} TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
PyVar get(VM* vm, Frame* frame) const{ PyObject* get(VM* vm, Frame* frame) const{
Tuple args(objs.size()); Tuple args(objs.size());
for (int i = 0; i < objs.size(); i++) { for (int i = 0; i < objs.size(); i++) {
args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame); args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
@ -121,11 +121,11 @@ struct TupleRef : BaseRef {
return VAR(std::move(args)); return VAR(std::move(args));
} }
void set(VM* vm, Frame* frame, PyVar val) const{ void set(VM* vm, Frame* frame, PyObject* val) const{
val = vm->asIter(val); val = vm->asIter(val);
BaseIter* iter = vm->PyIter_AS_C(val); BaseIter* iter = vm->PyIter_AS_C(val);
for(int i=0; i<objs.size(); i++){ for(int i=0; i<objs.size(); i++){
PyVarOrNull x; PyObject* x;
if(is_type(objs[i], vm->tp_star_wrapper)){ if(is_type(objs[i], vm->tp_star_wrapper)){
auto& star = _CAST(StarWrapper&, objs[i]); auto& star = _CAST(StarWrapper&, objs[i]);
if(star.rvalue) vm->ValueError("can't use starred expression here"); if(star.rvalue) vm->ValueError("can't use starred expression here");
@ -141,7 +141,7 @@ struct TupleRef : BaseRef {
vm->PyRef_AS_C(objs[i])->set(vm, frame, x); vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
} }
} }
PyVarOrNull x = iter->next(); PyObject* x = iter->next();
if(x != nullptr) vm->ValueError("too many values to unpack"); if(x != nullptr) vm->ValueError("too many values to unpack");
} }
@ -152,19 +152,19 @@ struct TupleRef : BaseRef {
template<typename P> template<typename P>
PyVarRef VM::PyRef(P&& value) { PyObject* VM::PyRef(P&& value) {
static_assert(std::is_base_of_v<BaseRef, std::decay_t<P>>); static_assert(std::is_base_of_v<BaseRef, std::decay_t<P>>);
return new_object(tp_ref, std::forward<P>(value)); return heap.gcnew<P>(tp_ref, std::forward<P>(value));
} }
const BaseRef* VM::PyRef_AS_C(const PyVar& obj) const BaseRef* VM::PyRef_AS_C(PyObject* obj)
{ {
if(!is_type(obj, tp_ref)) TypeError("expected an l-value"); if(!is_type(obj, tp_ref)) TypeError("expected an l-value");
return static_cast<const BaseRef*>(obj->value()); return static_cast<const BaseRef*>(obj->value());
} }
/***** Frame's Impl *****/ /***** Frame's Impl *****/
inline void Frame::try_deref(VM* vm, PyVar& v){ inline void Frame::try_deref(VM* vm, PyObject*& v){
if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this); if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this);
} }

View File

@ -3,6 +3,7 @@
#include "common.h" #include "common.h"
#include "memory.h" #include "memory.h"
#include "str.h" #include "str.h"
#include <initializer_list>
namespace pkpy { namespace pkpy {
using List = std::vector<PyObject*>; using List = std::vector<PyObject*>;
@ -33,6 +34,11 @@ namespace pkpy {
other._size = 0; other._size = 0;
} }
Args(std::initializer_list<PyObject*> list) : Args(list.size()){
int i=0;
for(auto& p : list) _args[i++] = p;
}
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(PyObject*)*ret.size()); memcpy((void*)ret._args, (void*)other.data(), sizeof(PyObject*)*ret.size());
@ -82,30 +88,6 @@ namespace pkpy {
return _zero; return _zero;
} }
template<typename T>
Args one_arg(T&& a) {
Args ret(1);
ret[0] = std::forward<T>(a);
return ret;
}
template<typename T1, typename T2>
Args two_args(T1&& a, T2&& b) {
Args ret(2);
ret[0] = std::forward<T1>(a);
ret[1] = std::forward<T2>(b);
return ret;
}
template<typename T1, typename T2, typename T3>
Args three_args(T1&& a, T2&& b, T3&& c) {
Args ret(3);
ret[0] = std::forward<T1>(a);
ret[1] = std::forward<T2>(b);
ret[2] = std::forward<T3>(c);
return ret;
}
typedef Args Tuple; typedef Args Tuple;
THREAD_LOCAL SmallArrayPool<PyObject*, 10> Args::_pool; THREAD_LOCAL SmallArrayPool<PyObject*, 10> Args::_pool;
} // namespace pkpy } // namespace pkpy

131
src/vm.h
View File

@ -1,7 +1,9 @@
#pragma once #pragma once
#include "common.h"
#include "frame.h" #include "frame.h"
#include "error.h" #include "error.h"
#include "gc.h"
namespace pkpy{ namespace pkpy{
@ -20,8 +22,8 @@ namespace pkpy{
template<> ctype& _py_cast<ctype&>(VM* vm, PyObject* obj) { \ template<> ctype& _py_cast<ctype&>(VM* vm, PyObject* obj) { \
return OBJ_GET(ctype, obj); \ return OBJ_GET(ctype, obj); \
} \ } \
PyObject* py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \ PyObject* py_var(VM* vm, const ctype& value) { return vm->heap.gcnew(vm->ptype, value);} \
PyObject* py_var(VM* vm, ctype&& value) { return vm->new_object(vm->ptype, std::move(value));} PyObject* py_var(VM* vm, ctype&& value) { return vm->heap.gcnew(vm->ptype, std::move(value));}
class Generator: public BaseIter { class Generator: public BaseIter {
std::unique_ptr<Frame> frame; std::unique_ptr<Frame> frame;
@ -41,6 +43,7 @@ struct PyTypeInfo{
class VM { class VM {
VM* vm; // self reference for simplify code VM* vm; // self reference for simplify code
ManagedHeap heap;
public: public:
std::stack< std::unique_ptr<Frame> > callstack; std::stack< std::unique_ptr<Frame> > callstack;
std::vector<PyTypeInfo> _all_types; std::vector<PyTypeInfo> _all_types;
@ -78,11 +81,10 @@ public:
} }
init_builtin_types(); init_builtin_types();
// for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i));
} }
PyObject* asStr(PyObject* obj){ PyObject* asStr(PyObject* obj){
PyVarOrNull f = getattr(obj, __str__, false, true); PyObject* f = getattr(obj, __str__, false, true);
if(f != nullptr) return call(f); if(f != nullptr) return call(f);
return asRepr(obj); return asRepr(obj);
} }
@ -95,8 +97,8 @@ public:
} }
PyObject* asIter(PyObject* obj){ PyObject* asIter(PyObject* obj){
if(is_type(obj, tp_native_iterator)) return obj; if(is_type(obj, tp_iterator)) return obj;
PyVarOrNull iter_f = getattr(obj, __iter__, false, true); PyObject* iter_f = getattr(obj, __iter__, false, true);
if(iter_f != nullptr) return call(iter_f); if(iter_f != nullptr) return call(iter_f);
TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable"); TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable");
return nullptr; return nullptr;
@ -104,7 +106,7 @@ public:
PyObject* asList(PyObject* 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), Args{iterable});
} }
PyObject** find_name_in_mro(PyObject* cls, StrName name){ PyObject** find_name_in_mro(PyObject* cls, StrName name){
@ -191,13 +193,13 @@ public:
PyObject* property(NativeFuncRaw fget){ PyObject* property(NativeFuncRaw fget){
PyObject* p = builtins->attr("property"); PyObject* p = builtins->attr("property");
PyObject* method = new_object(tp_native_function, NativeFunc(fget, 1, false)); PyObject* method = heap.gcnew(tp_native_function, NativeFunc(fget, 1, false));
return call(p, one_arg(method)); return call(p, Args{method});
} }
PyObject* new_type_object(PyObject* mod, StrName name, Type base){ PyObject* new_type_object(PyObject* mod, StrName name, Type base){
// use gcnew // use gcnew
PyObject* obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size()); PyObject* obj = new Py_<Type>(tp_type, _all_types.size());
PyTypeInfo info{ PyTypeInfo info{
.obj = obj, .obj = obj,
.base = base, .base = base,
@ -213,30 +215,6 @@ public:
return OBJ_GET(Type, obj); return OBJ_GET(Type, obj);
} }
template<typename T>
inline PyObject* new_object(PyObject* type, const T& _value) {
#if PK_EXTRA_CHECK
if(!is_type(type, tp_type)) UNREACHABLE();
#endif
return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value);
}
template<typename T>
inline PyObject* new_object(PyObject* type, T&& _value) {
#if PK_EXTRA_CHECK
if(!is_type(type, tp_type)) UNREACHABLE();
#endif
return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), std::move(_value));
}
template<typename T>
inline PyObject* new_object(Type type, const T& _value) {
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, _value);
}
template<typename T>
inline PyObject* new_object(Type type, T&& _value) {
return make_sp<PyObject, Py_<std::decay_t<T>>>(type, std::move(_value));
}
PyObject* _find_type(const Str& type){ PyObject* _find_type(const Str& type){
PyObject** obj = builtins->attr().try_get(type); PyObject** obj = builtins->attr().try_get(type);
if(!obj){ if(!obj){
@ -282,19 +260,19 @@ public:
// for quick access // for quick access
Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str; Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str;
Type tp_list, tp_tuple; Type tp_list, tp_tuple;
Type tp_function, tp_native_function, tp_native_iterator, tp_bound_method; Type tp_function, tp_native_function, tp_iterator, tp_bound_method;
Type tp_slice, tp_range, tp_module, tp_ref; Type tp_slice, tp_range, tp_module, tp_ref;
Type tp_super, tp_exception, tp_star_wrapper; Type tp_super, tp_exception, tp_star_wrapper;
template<typename P> template<typename P>
inline PyObject* 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 heap.gcnew<P>(tp_iterator, std::forward<P>(value));
} }
inline BaseIter* PyIter_AS_C(PyObject* obj) inline BaseIter* PyIter_AS_C(PyObject* obj)
{ {
check_type(obj, tp_native_iterator); check_type(obj, tp_iterator);
return static_cast<BaseIter*>(obj->value()); return static_cast<BaseIter*>(obj->value());
} }
@ -369,7 +347,7 @@ public:
PyObject* _exec(); PyObject* _exec();
template<typename P> template<typename P>
PyVarRef PyRef(P&& value); PyObject* PyRef(P&& value);
const BaseRef* PyRef_AS_C(PyObject* obj); const BaseRef* PyRef_AS_C(PyObject* obj);
}; };
@ -458,23 +436,23 @@ 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 BitsCvt(bits)._float;
} }
template<> float _py_cast<float>(VM* vm, PyObject* 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 BitsCvt(bits)._float;
} }
template<> double py_cast<double>(VM* vm, PyObject* 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 BitsCvt(bits)._float;
} }
template<> double _py_cast<double>(VM* vm, PyObject* 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 BitsCvt(bits)._float;
} }
@ -502,7 +480,7 @@ PY_VAR_INT(unsigned long long)
#define PY_VAR_FLOAT(T) \ #define PY_VAR_FLOAT(T) \
PyObject* 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 = BitsCvt(val)._int; \
bits = (bits >> 2) << 2; \ bits = (bits >> 2) << 2; \
bits |= 0b10; \ bits |= 0b10; \
return reinterpret_cast<PyObject*>(bits); \ return reinterpret_cast<PyObject*>(bits); \
@ -561,7 +539,7 @@ PyObject* VM::asBool(PyObject* 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); PyObject* len_fn = getattr(obj, __len__, false, true);
if(len_fn != nullptr){ if(len_fn != nullptr){
PyObject* ret = call(len_fn); PyObject* ret = call(len_fn);
return VAR(CAST(i64, ret) > 0); return VAR(CAST(i64, ret) > 0);
@ -596,8 +574,11 @@ PyObject* VM::asRepr(PyObject* obj){
} }
PyObject* VM::new_module(StrName name) { PyObject* VM::new_module(StrName name) {
PyObject* obj = new_object(tp_module, DummyModule()); PyObject* obj = new Py_<DummyModule>(tp_module, DummyModule());
obj->attr().set(__name__, VAR(name.str())); obj->attr().set(__name__, VAR(name.str()));
// we do not allow override in order to avoid memory leak
// it is because Module objects are not garbage collected
if(_modules.contains(name)) UNREACHABLE();
_modules.set(name, obj); _modules.set(name, obj);
return obj; return obj;
} }
@ -672,9 +653,11 @@ Str VM::disassemble(CodeObject_ co){
} }
void VM::init_builtin_types(){ void VM::init_builtin_types(){
// Py_(Type type, T&& val) PyObject* _tp_object = new Py_<Type>(Type(1), Type(0));
PyVar _tp_object = make_sp<PyObject, Py_<Type>>(Type(1), Type(0)); PyObject* _tp_type = new Py_<Type>(Type(1), Type(1));
PyVar _tp_type = make_sp<PyObject, Py_<Type>>(Type(1), Type(1)); // PyTypeObject is managed by _all_types
// PyModuleObject is managed by _modules
// They are not managed by GC, so we use a simple "new"
_all_types.push_back({.obj = _tp_object, .base = -1, .name = "object"}); _all_types.push_back({.obj = _tp_object, .base = -1, .name = "object"});
_all_types.push_back({.obj = _tp_type, .base = 0, .name = "type"}); _all_types.push_back({.obj = _tp_type, .base = 0, .name = "type"});
tp_object = 0; tp_type = 1; tp_object = 0; tp_type = 1;
@ -695,17 +678,17 @@ void VM::init_builtin_types(){
tp_function = _new_type_object("function"); tp_function = _new_type_object("function");
tp_native_function = _new_type_object("native_function"); tp_native_function = _new_type_object("native_function");
tp_native_iterator = _new_type_object("native_iterator"); tp_iterator = _new_type_object("iterator");
tp_bound_method = _new_type_object("bound_method"); tp_bound_method = _new_type_object("bound_method");
tp_super = _new_type_object("super"); tp_super = _new_type_object("super");
tp_exception = _new_type_object("Exception"); tp_exception = _new_type_object("Exception");
this->None = new_object(_new_type_object("NoneType"), DUMMY_VAL); this->None = new Py_<Dummy>(_new_type_object("NoneType"), {});
this->Ellipsis = new_object(_new_type_object("ellipsis"), DUMMY_VAL); this->Ellipsis = new Py_<Dummy>(_new_type_object("ellipsis"), {});
this->True = new_object(tp_bool, true); this->True = new Py_<Dummy>(tp_bool, {});
this->False = new_object(tp_bool, false); this->False = new Py_<Dummy>(tp_bool, {});
this->_py_op_call = new_object(_new_type_object("_py_op_call"), DUMMY_VAL); this->_py_op_call = new Py_<Dummy>(_new_type_object("_py_op_call"), {});
this->_py_op_yield = new_object(_new_type_object("_py_op_yield"), DUMMY_VAL); this->_py_op_yield = new Py_<Dummy>(_new_type_object("_py_op_yield"), {});
this->builtins = new_module("builtins"); this->builtins = new_module("builtins");
this->_main = new_module("__main__"); this->_main = new_module("__main__");
@ -735,8 +718,8 @@ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCal
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{
obj = new_object(_callable, DummyInstance()); obj = heap.gcnew<DummyInstance>(_callable, {});
PyVarOrNull init_f = getattr(obj, __init__, false, true); PyObject* init_f = getattr(obj, __init__, false, true);
if (init_f != nullptr) call(init_f, std::move(args), kwargs, false); if (init_f != nullptr) call(init_f, std::move(args), kwargs, false);
} }
return obj; return obj;
@ -801,7 +784,7 @@ PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, bool opCal
return _exec(); return _exec();
} }
PyVarOrNull call_f = getattr(_callable, __call__, false, true); PyObject* call_f = getattr(_callable, __call__, false, true);
if(call_f != nullptr){ if(call_f != nullptr){
return call(call_f, std::move(args), kwargs, false); return call(call_f, std::move(args), kwargs, false);
} }
@ -829,42 +812,44 @@ 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
PyObject* VM::getattr(PyObject* 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);
if(is_type(*obj, tp_super)){ // handle super() proxy
const Super& super = OBJ_GET(Super, *obj); if(is_type(obj, tp_super)){
obj = &super.first; const Super& super = OBJ_GET(Super, obj);
objtype = _t(super.second).get(); obj = super.first;
objtype = _t(super.second);
} }
PyObject** 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
PyObject** 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, Args{*cls_var, obj});
} }
// handle instance __dict__ // handle instance __dict__
if(!class_only && !(*obj).is_tagged() && (*obj)->is_attr_valid()){ if(!class_only && !is_tagged(obj) && obj->is_attr_valid()){
PyObject** 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){
// bound method is non-data descriptor // bound method is non-data descriptor
if(is_type(*cls_var, tp_function) || is_type(*cls_var, tp_native_function)){ if(is_type(*cls_var, tp_function) || is_type(*cls_var, tp_native_function)){
return VAR(BoundMethod(*obj, *cls_var)); return VAR(BoundMethod(obj, *cls_var));
} }
return *cls_var; return *cls_var;
} }
if(throw_err) AttributeError(*obj, name); if(throw_err) AttributeError(obj, name);
return nullptr; return nullptr;
} }
template<typename T> template<typename T>
void VM::setattr(PyObject* 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>, PyObject*>);
PyObject* objtype = _t(obj).get(); PyObject* objtype = _t(obj);
// handle super() proxy
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);
} }
PyObject** 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){
@ -873,7 +858,7 @@ void VM::setattr(PyObject* obj, StrName name, T&& value){
if(cls_var_t->attr().contains(__get__)){ if(cls_var_t->attr().contains(__get__)){
PyObject** 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, Args{*cls_var, obj, std::forward<T>(value)});
}else{ }else{
TypeError("readonly attribute: " + name.str().escape(true)); TypeError("readonly attribute: " + name.str().escape(true));
} }
@ -881,7 +866,7 @@ void VM::setattr(PyObject* obj, StrName name, T&& value){
} }
} }
// handle instance __dict__ // handle instance __dict__
if(obj.is_tagged() || !(*obj)->is_attr_valid()) TypeError("cannot set attribute"); if(is_tagged(obj) || !obj->is_attr_valid()) TypeError("cannot set attribute");
obj->attr().set(name, std::forward<T>(value)); obj->attr().set(name, std::forward<T>(value));
} }