This commit is contained in:
blueloveTH 2024-05-12 23:43:06 +08:00
parent 4ab7c10ed1
commit f5a4c37968
22 changed files with 167 additions and 136 deletions

View File

@ -88,7 +88,7 @@ struct Struct{
};
static_assert(sizeof(Py_<Struct>) <= 64);
static_assert(sizeof(Py_<Tuple>) <= 64);
static_assert(sizeof(Py_<Tuple>) <= 128);
/***********************************************/
template<typename Tp>

View File

@ -148,7 +148,7 @@ template<>
struct Py_<Function> final: PyObject {
Function _value;
template<typename... Args>
Py_(Type type, Args&&... args): PyObject(type), _value(std::forward<Args>(args)...) {
Py_(Args&&... args): PyObject(), _value(std::forward<Args>(args)...) {
// _enable_instance_dict();
}
void _obj_gc_mark() override {
@ -161,7 +161,7 @@ template<>
struct Py_<NativeFunc> final: PyObject {
NativeFunc _value;
template<typename... Args>
Py_(Type type, Args&&... args): PyObject(type), _value(std::forward<Args>(args)...) {
Py_(Args&&... args): PyObject(), _value(std::forward<Args>(args)...) {
// _enable_instance_dict();
}
void _obj_gc_mark() override {

View File

@ -125,10 +125,6 @@ struct Type {
#define PK_DEBUG_ASSERT(x)
#endif
struct PyObject;
using PyVar = PyObject *;
#define PK_BITS(p) (reinterpret_cast<i64>(p))
// is_pod_v<> for c++17 and c++20
template<typename T>
inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
@ -172,4 +168,45 @@ inline constexpr bool is_floating_point_v = std::is_same_v<T, float> || std::is_
inline const char* PK_HEX_TABLE = "0123456789abcdef";
struct PyObject;
// using PyVar = PyObject *;
struct PyVar final{
Type type;
bool is_sso;
uint8_t flags;
char _bytes[12];
PyVar(): type(), is_sso(false), flags(0) { }
PyVar(std::nullptr_t): type(), is_sso(false), flags(0) { }
PyVar(Type type, bool is_sso): type(type), is_sso(is_sso), flags(0) { }
PyVar(Type type, PyObject* p): type(type), is_sso(false), flags(0) { as<PyObject*>() = p; }
template<typename T>
T& as() const {
static_assert(!std::is_reference_v<T>);
PK_DEBUG_ASSERT(is_sso)
return *(T*)_bytes;
}
operator bool() const { return type; }
bool operator==(const PyVar& other) const {
return memcmp(this, &other, sizeof(PyVar)) == 0;
}
bool operator!=(const PyVar& other) const {
return memcmp(this, &other, sizeof(PyVar)) != 0;
}
bool operator==(std::nullptr_t) const { return !type; }
bool operator!=(std::nullptr_t) const { return type; }
PyObject* get() const { return as<PyObject*>(); }
i64 hash() const { return as<i64>(); }
PyObject* operator->() const { return as<PyObject*>(); }
};
static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);
} // namespace pkpy

View File

@ -18,7 +18,7 @@ struct Dict{
int next;
};
static constexpr int __Capacity = 8;
static constexpr int __Capacity = 4;
static constexpr float __LoadFactor = 0.67f;
static_assert(sizeof(Item) * __Capacity <= 128);
static_assert(sizeof(ItemNode) * __Capacity <= 64);

View File

@ -97,7 +97,7 @@ struct CodeEmitContext{
bool is_compiling_class = false;
int base_stack_size = 0;
std::map<void*, int> _co_consts_nonstring_dedup_map;
std::map<PyVar, int> _co_consts_nonstring_dedup_map;
std::map<std::string, int, std::less<>> _co_consts_string_dedup_map;
int get_loop() const;

View File

@ -132,7 +132,7 @@ struct LinkedFrame{
};
struct CallStack{
static_assert(sizeof(LinkedFrame) <= 64 && std::is_trivially_destructible_v<LinkedFrame>);
static_assert(sizeof(LinkedFrame) <= 128 && std::is_trivially_destructible_v<LinkedFrame>);
LinkedFrame* _tail;
int _size;
@ -144,7 +144,7 @@ struct CallStack{
template<typename... Args>
void emplace(Args&&... args){
_tail = new(pool64_alloc<LinkedFrame>()) LinkedFrame(_tail, std::forward<Args>(args)...);
_tail = new(pool128_alloc<LinkedFrame>()) LinkedFrame(_tail, std::forward<Args>(args)...);
++_size;
}
@ -152,7 +152,7 @@ struct CallStack{
PK_DEBUG_ASSERT(!empty())
LinkedFrame* p = _tail;
_tail = p->f_back;
pool64_dealloc(p);
pool128_dealloc(p);
--_size;
}

View File

@ -42,7 +42,8 @@ struct ManagedHeap{
PyVar gcnew(Type type, Args&&... args){
using __T = Py_<std::decay_t<T>>;
// https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
PyVar obj = new(pool64_alloc<__T>()) Py_<std::decay_t<T>>(type, std::forward<Args>(args)...);
PyObject* p = new(pool64_alloc<__T>()) Py_<std::decay_t<T>>(std::forward<Args>(args)...);
PyVar obj(type, p);
gen.push_back(obj);
gc_counter++;
return obj;
@ -52,7 +53,8 @@ struct ManagedHeap{
PyVar _new(Type type, Args&&... args){
using __T = Py_<std::decay_t<T>>;
// https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
PyVar obj = new(pool64_alloc<__T>()) Py_<std::decay_t<T>>(type, std::forward<Args>(args)...);
PyObject* p = new(pool64_alloc<__T>()) Py_<std::decay_t<T>>(std::forward<Args>(args)...);
PyVar obj(type, p);
obj->gc_enabled = false;
_no_gc.push_back(obj);
return obj;

View File

@ -10,6 +10,9 @@ void pool64_dealloc(void*) noexcept;
void* pool128_alloc(size_t) noexcept;
void pool128_dealloc(void*) noexcept;
void* pool256_alloc(size_t) noexcept;
void pool256_dealloc(void*) noexcept;
template<typename T>
void* pool64_alloc() noexcept{
return pool64_alloc(sizeof(T));
@ -20,9 +23,15 @@ void* pool128_alloc() noexcept{
return pool128_alloc(sizeof(T));
}
template<typename T>
void* pool256_alloc() noexcept{
return pool256_alloc(sizeof(T));
}
void pools_shrink_to_fit() noexcept;
std::string pool64_info() noexcept;
std::string pool128_info() noexcept;
std::string pool256_info() noexcept;
}; // namespace pkpy

View File

@ -8,12 +8,12 @@ namespace pkpy{
template<typename T>
constexpr T default_invalid_value(){
if constexpr(std::is_pointer_v<T>) return nullptr;
if constexpr(std::is_same_v<PyVar, T>) return nullptr;
else if constexpr(std::is_same_v<int, T>) return -1;
else return Discarded();
}
#define PK_SMALL_NAME_DICT_CAPACITY 8
#define PK_SMALL_NAME_DICT_CAPACITY 6
#define PK_SMALL_NAME_DICT_LOOP(B) for(int i=0; i<PK_SMALL_NAME_DICT_CAPACITY; i++) { B }
template<typename V>

View File

@ -96,7 +96,6 @@ struct Slice {
struct PyObject{
bool gc_enabled; // whether this object is managed by GC
bool gc_marked; // whether this object is marked
Type type;
NameDict* _attr;
bool is_attr_valid() const noexcept { return _attr != nullptr; }
@ -114,7 +113,7 @@ struct PyObject{
virtual void _obj_gc_mark() = 0;
virtual ~PyObject();
PyObject(Type type) : gc_enabled(true), gc_marked(false), type(type), _attr(nullptr) {}
PyObject() : gc_enabled(true), gc_marked(false), _attr(nullptr) {}
void _enable_instance_dict() {
_attr = new(pool128_alloc<NameDict>()) NameDict();
@ -128,15 +127,13 @@ struct PyObject{
const int kTpIntIndex = 2;
const int kTpFloatIndex = 3;
inline bool is_tagged(PyVar p) noexcept { return (PK_BITS(p) & 0b11) != 0b00; }
inline bool is_small_int(PyVar p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; }
inline bool is_heap_int(PyVar p) noexcept { return !is_tagged(p) && p->type.index == kTpIntIndex; }
inline bool is_float(PyVar p) noexcept { return !is_tagged(p) && p->type.index == kTpFloatIndex; }
inline bool is_int(PyVar p) noexcept { return is_small_int(p) || is_heap_int(p); }
inline bool is_tagged(PyVar p) noexcept { return p.is_sso; }
inline bool is_float(PyVar p) noexcept { return p.type.index == kTpFloatIndex; }
inline bool is_int(PyVar p) noexcept { return p.type.index == kTpIntIndex; }
inline bool is_type(PyVar obj, Type type) {
PK_DEBUG_ASSERT(obj != nullptr)
return is_small_int(obj) ? type.index == kTpIntIndex : obj->type == type;
return obj.type == type;
}
template <typename, typename=void> struct has_gc_marker : std::false_type {};
@ -154,7 +151,7 @@ struct Py_ final: PyObject {
}
template <typename... Args>
Py_(Type type, Args&&... args) : PyObject(type), _value(std::forward<Args>(args)...) { }
Py_(Args&&... args) : PyObject(), _value(std::forward<Args>(args)...) { }
};
struct MappingProxy{
@ -169,7 +166,7 @@ template<typename T> T to_void_p(VM*, PyVar);
PyVar from_void_p(VM*, void*);
#define PK_OBJ_GET(T, obj) (((Py_<T>*)(obj))->_value)
#define PK_OBJ_GET(T, obj) (obj.is_sso ? obj.as<T>() : (((Py_<T>*)(obj.get()))->_value))
#define PK_OBJ_MARK(obj) \
if(!is_tagged(obj) && !(obj)->gc_marked) { \
@ -186,30 +183,19 @@ PyVar from_void_p(VM*, void*);
#define CAST_DEFAULT(T, x, default_value) (x != vm->None) ? py_cast<T>(vm, x) : (default_value)
/*****************************************************************/
template<>
struct Py_<i64> final: PyObject {
i64 _value;
Py_(Type type, i64 val): PyObject(type), _value(val) {}
void _obj_gc_mark() override {}
};
inline bool try_cast_int(PyVar obj, i64* val) noexcept {
if(is_small_int(obj)){
*val = PK_BITS(obj) >> 2;
if(is_int(obj)){
*val = obj.as<i64>();
return true;
}else if(is_heap_int(obj)){
*val = PK_OBJ_GET(i64, obj);
return true;
}else{
return false;
}
return false;
}
template<>
struct Py_<List> final: PyObject {
List _value;
Py_(Type type, List&& val): PyObject(type), _value(std::move(val)) {}
Py_(Type type, const List& val): PyObject(type), _value(val) {}
Py_(List&& val): PyObject(), _value(std::move(val)) {}
Py_(const List& val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
for(PyVar obj: _value) PK_OBJ_MARK(obj);
@ -219,8 +205,8 @@ struct Py_<List> final: PyObject {
template<>
struct Py_<Tuple> final: PyObject {
Tuple _value;
Py_(Type type, Tuple&& val): PyObject(type), _value(std::move(val)) {}
Py_(Type type, const Tuple& val): PyObject(type), _value(val) {}
Py_(Tuple&& val): PyObject(), _value(std::move(val)) {}
Py_(const Tuple& val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
for(PyVar obj: _value) PK_OBJ_MARK(obj);
@ -230,7 +216,7 @@ struct Py_<Tuple> final: PyObject {
template<>
struct Py_<MappingProxy> final: PyObject {
MappingProxy _value;
Py_(Type type, MappingProxy val): PyObject(type), _value(val) {}
Py_(MappingProxy val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.obj);
}
@ -239,7 +225,7 @@ struct Py_<MappingProxy> final: PyObject {
template<>
struct Py_<BoundMethod> final: PyObject {
BoundMethod _value;
Py_(Type type, BoundMethod val): PyObject(type), _value(val) {}
Py_(BoundMethod val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.self);
PK_OBJ_MARK(_value.func);
@ -249,7 +235,7 @@ struct Py_<BoundMethod> final: PyObject {
template<>
struct Py_<StarWrapper> final: PyObject {
StarWrapper _value;
Py_(Type type, StarWrapper val): PyObject(type), _value(val) {}
Py_(StarWrapper val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.obj);
}
@ -258,7 +244,7 @@ struct Py_<StarWrapper> final: PyObject {
template<>
struct Py_<StaticMethod> final: PyObject {
StaticMethod _value;
Py_(Type type, StaticMethod val): PyObject(type), _value(val) {}
Py_(StaticMethod val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.func);
}
@ -267,7 +253,7 @@ struct Py_<StaticMethod> final: PyObject {
template<>
struct Py_<ClassMethod> final: PyObject {
ClassMethod _value;
Py_(Type type, ClassMethod val): PyObject(type), _value(val) {}
Py_(ClassMethod val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.func);
}
@ -276,7 +262,7 @@ struct Py_<ClassMethod> final: PyObject {
template<>
struct Py_<Property> final: PyObject {
Property _value;
Py_(Type type, Property val): PyObject(type), _value(val) {}
Py_(Property val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.getter);
PK_OBJ_MARK(_value.setter);
@ -286,7 +272,7 @@ struct Py_<Property> final: PyObject {
template<>
struct Py_<Slice> final: PyObject {
Slice _value;
Py_(Type type, Slice val): PyObject(type), _value(val) {}
Py_(Slice val): PyObject(), _value(val) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.start);
PK_OBJ_MARK(_value.stop);
@ -298,7 +284,7 @@ template<>
struct Py_<Super> final: PyObject {
Super _value;
template<typename... Args>
Py_(Type type, Args&&... args): PyObject(type), _value(std::forward<Args>(args)...) {}
Py_(Args&&... args): PyObject(), _value(std::forward<Args>(args)...) {}
void _obj_gc_mark() override {
PK_OBJ_MARK(_value.first);
}
@ -306,16 +292,14 @@ struct Py_<Super> final: PyObject {
template<>
struct Py_<DummyInstance> final: PyObject {
Py_(Type type): PyObject(type) {
_enable_instance_dict();
}
Py_(): PyObject() { _enable_instance_dict(); }
void _obj_gc_mark() override {}
};
template<>
struct Py_<Type> final: PyObject {
Type _value;
Py_(Type type, Type val): PyObject(type), _value(val) {
Py_(Type val): PyObject(), _value(val) {
_enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
}
void _obj_gc_mark() override {}
@ -323,7 +307,7 @@ struct Py_<Type> final: PyObject {
template<>
struct Py_<DummyModule> final: PyObject {
Py_(Type type): PyObject(type) {
Py_(): PyObject() {
_enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
}
void _obj_gc_mark() override {}

View File

@ -11,7 +11,7 @@ using List = pod_vector<PyVar, 4>;
struct Tuple {
PyVar* _args;
PyVar _inlined[3];
PyVar _inlined[4];
int _size;
Tuple(int n);

View File

@ -8,9 +8,9 @@ namespace pkpy{
template<typename T, int Growth=2>
struct pod_vector{
static constexpr int SizeT = sizeof(T);
static constexpr int N = 64 / SizeT;
static constexpr int N = 128 / SizeT;
// static_assert(64 % SizeT == 0);
// static_assert(128 % SizeT == 0);
static_assert(is_pod_v<T>);
static_assert(N >= 4);
@ -21,21 +21,21 @@ struct pod_vector{
using size_type = int;
pod_vector(): _size(0), _capacity(N) {
_data = (T*)pool64_alloc(_capacity * SizeT);
_data = (T*)pool128_alloc(_capacity * SizeT);
}
// support initializer list
pod_vector(std::initializer_list<T> il): _size(il.size()), _capacity(std::max(N, _size)) {
_data = (T*)pool64_alloc(_capacity * SizeT);
_data = (T*)pool128_alloc(_capacity * SizeT);
for(int i=0; i<_size; i++) _data[i] = *(il.begin() + i);
}
pod_vector(int size): _size(size), _capacity(std::max(N, size)) {
_data = (T*)pool64_alloc(_capacity * SizeT);
_data = (T*)pool128_alloc(_capacity * SizeT);
}
pod_vector(const pod_vector& other): _size(other._size), _capacity(other._capacity) {
_data = (T*)pool64_alloc(_capacity * SizeT);
_data = (T*)pool128_alloc(_capacity * SizeT);
memcpy(_data, other._data, SizeT * _size);
}
@ -47,7 +47,7 @@ struct pod_vector{
}
pod_vector& operator=(pod_vector&& other) noexcept {
if(_data!=nullptr) pool64_dealloc(_data);
if(_data!=nullptr) pool128_dealloc(_data);
_size = other._size;
_capacity = other._capacity;
_data = other._data;
@ -74,10 +74,10 @@ struct pod_vector{
if(cap <= _capacity) return;
_capacity = cap;
T* old_data = _data;
_data = (T*)pool64_alloc(_capacity * SizeT);
_data = (T*)pool128_alloc(_capacity * SizeT);
if(old_data != nullptr){
memcpy(_data, old_data, SizeT * _size);
pool64_dealloc(old_data);
pool128_dealloc(old_data);
}
}
@ -139,7 +139,7 @@ struct pod_vector{
}
~pod_vector() {
if(_data != nullptr) pool64_dealloc(_data);
if(_data != nullptr) pool128_dealloc(_data);
}
};

View File

@ -365,7 +365,7 @@ public:
void check_type(PyVar obj, Type type){ if(!is_type(obj, type)) TypeError(type, _tp(obj)); }
void check_compatible_type(PyVar obj, Type type){ if(!isinstance(obj, type)) TypeError(type, _tp(obj)); }
Type _tp(PyVar obj){ return is_small_int(obj) ? tp_int : obj->type; }
Type _tp(PyVar obj){ return obj.type; }
const PyTypeInfo* _tp_info(PyVar obj) { return &_all_types[_tp(obj)]; }
const PyTypeInfo* _tp_info(Type type) { return &_all_types[type]; }
PyVar _t(PyVar obj){ return _all_types[_tp(obj)].obj; }
@ -480,17 +480,14 @@ PyVar py_var(VM* vm, __T&& value){
return value ? vm->True : vm->False;
}else if constexpr(is_integral_v<T>){
// int
i64 val = static_cast<i64>(std::forward<__T>(value));
if(val >= Number::kMinSmallInt && val <= Number::kMaxSmallInt){
val = (val << 2) | 0b10;
return reinterpret_cast<PyVar>(val);
}else{
return vm->heap.gcnew<i64>(vm->tp_int, val);
}
PyVar retval(VM::tp_int, true);
retval.as<i64>() = static_cast<i64>(value);
return retval;
}else if constexpr(is_floating_point_v<T>){
// float
f64 val = static_cast<f64>(std::forward<__T>(value));
return vm->heap.gcnew<f64>(vm->tp_float, val);
PyVar retval(VM::tp_float, true);
retval.as<f64>() = static_cast<f64>(value);
return retval;
}else if constexpr(std::is_pointer_v<T>){
return from_void_p(vm, (void*)value);
}else{
@ -529,19 +526,17 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
static_assert(!std::is_reference_v<__T>);
// int
if constexpr(with_check){
if(is_small_int(obj)) return (T)(PK_BITS(obj) >> 2);
if(is_heap_int(obj)) return (T)PK_OBJ_GET(i64, obj);
if(is_int(obj)) return (T)obj.as<i64>();
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
}else{
if(is_small_int(obj)) return (T)(PK_BITS(obj) >> 2);
return (T)PK_OBJ_GET(i64, obj);
return (T)obj.as<i64>();
}
}else if constexpr(is_floating_point_v<T>){
static_assert(!std::is_reference_v<__T>);
// float
if(is_float(obj)) return PK_OBJ_GET(f64, obj);
if(is_float(obj)) return (T)obj.as<f64>();
i64 bits;
if(try_cast_int(obj, &bits)) return (float)bits;
if(try_cast_int(obj, &bits)) return (T)bits;
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
}else if constexpr(std::is_enum_v<T>){
static_assert(!std::is_reference_v<__T>);

View File

@ -3,15 +3,16 @@
namespace pkpy{
#define PREDICT_INT_OP(op) \
if(is_small_int(_0) && is_small_int(_1)){ \
TOP() = VAR((PK_BITS(_0)>>2) op (PK_BITS(_1)>>2)); \
if(is_int(_0) && is_int(_1)){ \
TOP() = VAR(_0.as<i64>() op _1.as<i64>()); \
DISPATCH() \
}
#define PREDICT_INT_DIV_OP(op) \
if(is_small_int(_0) && is_small_int(_1)){ \
if(_1 == (PyVar)0b10) ZeroDivisionError(); \
TOP() = VAR((PK_BITS(_0)>>2) op (PK_BITS(_1)>>2)); \
if(is_int(_0) && is_int(_1)){ \
i64 divisor = _1.as<i64>(); \
if(_1.as<i64>() == 0) ZeroDivisionError(); \
TOP() = VAR(_0.as<i64>() op divisor); \
DISPATCH() \
}
@ -145,7 +146,7 @@ __NEXT_STEP:;
case OP_LOAD_TRUE: PUSH(True); DISPATCH()
case OP_LOAD_FALSE: PUSH(False); DISPATCH()
/*****************************************/
case OP_LOAD_SMALL_INT: PUSH((PyVar)(uintptr_t)byte.arg); DISPATCH()
case OP_LOAD_SMALL_INT: PUSH(VAR((int16_t)byte.arg)); DISPATCH()
/*****************************************/
case OP_LOAD_ELLIPSIS: PUSH(Ellipsis); DISPATCH()
case OP_LOAD_FUNCTION: {
@ -243,7 +244,7 @@ __NEXT_STEP:;
}
} DISPATCH()
case OP_LOAD_SUBSCR_SMALL_INT:{
PyVar _1 = (PyVar)(uintptr_t)byte.arg;
PyVar _1 = VAR((int16_t)byte.arg);
PyVar _0 = TOP(); // a
auto _ti = _tp_info(_0);
if(_ti->m__getitem__){
@ -604,7 +605,7 @@ __NEXT_STEP:;
case OP_IS_OP:{
PyVar _1 = POPX(); // rhs
PyVar _0 = TOP(); // lhs
TOP() = VAR(static_cast<bool>((_0==_1) ^ byte.arg));
TOP() = VAR(static_cast<bool>((uint16_t)(_0==_1) ^ byte.arg));
} DISPATCH()
case OP_CONTAINS_OP:{
// a in b -> b __contains__ a

View File

@ -184,7 +184,7 @@ void add_module_c(VM* vm){
vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args){
VoidP& ptr = CAST(VoidP&, args[0]);
void* value = *reinterpret_cast<void**>(ptr.ptr);
return vm->heap.gcnew<VoidP>(args[0]->type, value);
return vm->heap.gcnew<VoidP>(args[0].type, value);
});
PyVar type;
@ -226,13 +226,13 @@ void add_module_c(VM* vm){
VoidP& voidp = PK_OBJ_GET(VoidP, lhs); \
i64 offset = CAST(i64, rhs); \
T* target = (T*)voidp.ptr; \
return vm->heap.gcnew<VoidP>(lhs->type, target + offset); \
return vm->heap.gcnew<VoidP>(lhs.type, target + offset); \
}); \
vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \
VoidP& voidp = PK_OBJ_GET(VoidP, lhs); \
i64 offset = CAST(i64, rhs); \
T* target = (T*)voidp.ptr; \
return vm->heap.gcnew<VoidP>(lhs->type, target - offset); \
return vm->heap.gcnew<VoidP>(lhs.type, target - offset); \
}); \
vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str{ \
VoidP& self = _CAST(VoidP&, obj); \

View File

@ -13,11 +13,11 @@ namespace pkpy{
}
struct PySignalObject: PyObject {
PySignalObject() : PyObject(Type(0)) { gc_enabled = false; }
PySignalObject() : PyObject() { gc_enabled = false; }
void _obj_gc_mark() override {}
};
PyVar const PY_NULL = new PySignalObject();
PyVar const PY_OP_CALL = new PySignalObject();
PyVar const PY_OP_YIELD = new PySignalObject();
PyVar const PY_NULL(Type(), new PySignalObject());
PyVar const PY_OP_CALL(Type(), new PySignalObject());
PyVar const PY_OP_YIELD(Type(), new PySignalObject());
} // namespace pkpy

View File

@ -10,7 +10,7 @@ namespace pkpy{
}
inline bool is_small_int(i64 value){
return value >= 0 && value < 1024;
return value >= INT16_MIN && value <= INT16_MAX;
}
int CodeEmitContext::get_loop() const {
@ -91,7 +91,6 @@ namespace pkpy{
int CodeEmitContext::emit_int(i64 value, int line){
if(is_small_int(value)){
value = (value << 2) | 0b10;
return emit_(OP_LOAD_SMALL_INT, (uint16_t)value, line);
}else{
return emit_(OP_LOAD_CONST, add_const(VAR(value)), line);

View File

@ -10,11 +10,11 @@ namespace pkpy{
alive.push_back(obj);
}else{
#if PK_DEBUG_GC_STATS
deleted[obj->type] += 1;
deleted[obj.type] += 1;
#endif
if(_gc_on_delete) _gc_on_delete(vm, obj);
obj->~PyObject();
pool64_dealloc(obj);
pool64_dealloc(obj.get());
}
}
@ -55,8 +55,8 @@ namespace pkpy{
}
ManagedHeap::~ManagedHeap(){
for(PyVar obj: _no_gc) { obj->~PyObject(); pool64_dealloc(obj); }
for(PyVar obj: gen) { obj->~PyObject(); pool64_dealloc(obj); }
for(PyVar obj: _no_gc) { obj->~PyObject(); pool64_dealloc(obj.get()); }
for(PyVar obj: gen) { obj->~PyObject(); pool64_dealloc(obj.get()); }
}

View File

@ -121,7 +121,7 @@ struct DoubleLinkedList{
}
};
template<int __BlockSize=128>
template<int __BlockSize>
struct MemoryPool{
static const int __MaxBlocks = 256*1024 / __BlockSize;
static const int __MinArenaCount = PK_GC_MIN_THRESHOLD*100 / (256*1024);
@ -269,6 +269,7 @@ struct MemoryPool{
static MemoryPool<64> pool64;
static MemoryPool<128> pool128;
static MemoryPool<256> pool256;
void* pool64_alloc(size_t size) noexcept { return pool64.alloc(size); }
void pool64_dealloc(void* p) noexcept { pool64.dealloc(p); }
@ -276,12 +277,17 @@ void pool64_dealloc(void* p) noexcept { pool64.dealloc(p); }
void* pool128_alloc(size_t size) noexcept { return pool128.alloc(size); }
void pool128_dealloc(void* p) noexcept { pool128.dealloc(p); }
void* pool256_alloc(size_t size) noexcept { return pool256.alloc(size); }
void pool256_dealloc(void* p) noexcept { pool256.dealloc(p); }
void pools_shrink_to_fit() noexcept {
pool64.shrink_to_fit();
pool128.shrink_to_fit();
pool256.shrink_to_fit();
}
std::string pool64_info() noexcept { return pool64.info(); }
std::string pool128_info() noexcept { return pool128.info(); }
std::string pool256_info() noexcept { return pool256.info(); }
}

View File

@ -173,7 +173,7 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) {
PyVar obj = args[0];
if(is_tagged(obj)) return vm->None;
return VAR(PK_BITS(obj));
return VAR(reinterpret_cast<i64>(obj.get()));
});
_vm->bind_func(_vm->builtins, "callable", 1, [](VM* vm, ArgsView args) {
@ -331,7 +331,7 @@ void __init_builtins(VM* _vm) {
if(is_tagged(obj)) PK_FATAL_ERROR();
SStream ss;
ss << "<" << _type_name(vm, vm->_tp(obj)) << " object at ";
ss.write_hex(obj);
ss.write_hex(obj.get());
ss << ">";
return ss.str();
});
@ -1482,7 +1482,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__repr__(VM::tp_exception, [](VM* vm, PyVar _0) -> Str {
Exception& self = _CAST(Exception&, _0);
return _S(_type_name(vm, _0->type), '(', self.msg.escape(), ')');
return _S(_type_name(vm, _0.type), '(', self.msg.escape(), ')');
});
_vm->bind__str__(VM::tp_exception, [](VM* vm, PyVar _0) -> Str{

View File

@ -6,7 +6,7 @@ Tuple::Tuple(int n){
if(n <= 3){
this->_args = _inlined;
}else{
this->_args = (PyVar*)pool64_alloc(n * sizeof(void*));
this->_args = (PyVar*)pool128_alloc(n * sizeof(void*));
}
this->_size = n;
}
@ -51,7 +51,7 @@ Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2, PyVar _3): Tuple(4){
_args[3] = _3;
}
Tuple::~Tuple(){ if(!is_inlined()) pool64_dealloc(_args); }
Tuple::~Tuple(){ if(!is_inlined()) pool128_dealloc(_args); }
List ArgsView::to_list() const{
List ret(size());

View File

@ -501,7 +501,7 @@ i64 VM::py_hash(PyVar obj){
return CAST(i64, ret);
}
// if it is trivial `object`, return PK_BITS
if(ti == &_all_types[tp_object]) return PK_BITS(obj);
if(ti == &_all_types[tp_object]) return obj.hash();
// otherwise, we check if it has a custom __eq__ other than object.__eq__
bool has_custom_eq = false;
if(ti->m__eq__) has_custom_eq = true;
@ -513,7 +513,7 @@ i64 VM::py_hash(PyVar obj){
TypeError(_S("unhashable type: ", ti->name.escape()));
PK_UNREACHABLE()
}else{
return PK_BITS(obj);
return obj.hash();
}
}
@ -715,8 +715,6 @@ static std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){
case OP_LOAD_FUNCTION:
argStr += _S(" (", co->func_decls[byte.arg]->code->name, ")").sv();
break;
case OP_LOAD_SMALL_INT: case OP_LOAD_SUBSCR_SMALL_INT:
argStr += _S(" (", (int)(byte.arg >> 2), ")").sv();
}
return argStr;
}
@ -1168,12 +1166,12 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err){
// handle instance __dict__
if(!is_tagged(obj) && obj->is_attr_valid()){
PyVar val;
if(obj->type == tp_type){
if(obj.type == tp_type){
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
if(val != nullptr){
if(is_tagged(val)) return val;
if(val->type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, val).func;
if(val->type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, val).func));
if(val.type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, val).func;
if(val.type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, val).func));
return val;
}
}else{
@ -1184,7 +1182,7 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err){
if(cls_var != nullptr){
// bound method is non-data descriptor
if(!is_tagged(cls_var)){
switch(cls_var->type){
switch(cls_var.type){
case tp_function.index:
return VAR(BoundMethod(obj, cls_var));
case tp_native_func.index:
@ -1234,12 +1232,12 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
// handle instance __dict__
if(!is_tagged(obj) && obj->is_attr_valid()){
PyVar val;
if(obj->type == tp_type){
if(obj.type == tp_type){
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
if(val != nullptr){
if(is_tagged(val)) return val;
if(val->type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, val).func;
if(val->type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, val).func));
if(val.type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, val).func;
if(val.type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, val).func));
return val;
}
}else{
@ -1251,7 +1249,7 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
if(cls_var != nullptr){
if(!is_tagged(cls_var)){
switch(cls_var->type){
switch(cls_var.type){
case tp_function.index:
*self = obj;
break;