blueloveTH hai 1 ano
pai
achega
f5a4c37968

+ 1 - 1
include/pocketpy/cffi.h

@@ -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>

+ 2 - 2
include/pocketpy/codeobject.h

@@ -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 {

+ 41 - 4
include/pocketpy/common.h

@@ -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

+ 1 - 1
include/pocketpy/dict.h

@@ -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);

+ 1 - 1
include/pocketpy/expr.h

@@ -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;

+ 3 - 3
include/pocketpy/frame.h

@@ -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;
     }
 

+ 4 - 2
include/pocketpy/gc.h

@@ -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;

+ 9 - 0
include/pocketpy/memory.h

@@ -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

+ 2 - 2
include/pocketpy/namedict.h

@@ -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>

+ 25 - 41
include/pocketpy/obj.h

@@ -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;
-        return true;
-    }else if(is_heap_int(obj)){
-        *val = PK_OBJ_GET(i64, obj);
+    if(is_int(obj)){
+        *val = obj.as<i64>();
         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 {}

+ 1 - 1
include/pocketpy/tuplelist.h

@@ -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);

+ 10 - 10
include/pocketpy/vector.h

@@ -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);
     }
 };
 

+ 11 - 16
include/pocketpy/vm.h

@@ -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>);

+ 22 - 21
src/ceval.cpp

@@ -2,33 +2,34 @@
 
 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)); \
-        DISPATCH() \
+#define PREDICT_INT_OP(op)                          \
+    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)); \
-        DISPATCH() \
+#define PREDICT_INT_DIV_OP(op)                      \
+    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()                                  \
     }
 
 #define BINARY_F_COMPARE(func, op, rfunc)                           \
-        PyVar ret;                                              \
-        const PyTypeInfo* _ti = _tp_info(_0);                \
-        if(_ti->m##func){                               \
-            ret = _ti->m##func(this, _0, _1);           \
-        }else{                                          \
-            PyVar self;                                                     \
-            PyVar _2 = get_unbound_method(_0, func, &self, false);          \
+        PyVar ret;                                                  \
+        const PyTypeInfo* _ti = _tp_info(_0);                       \
+        if(_ti->m##func){                                           \
+            ret = _ti->m##func(this, _0, _1);                       \
+        }else{                                                      \
+            PyVar self;                                                         \
+            PyVar _2 = get_unbound_method(_0, func, &self, false);              \
             if(_2 != nullptr) ret = call_method(self, _2, _1);                  \
             else ret = NotImplemented;                                          \
         }                                                                       \
         if(ret == NotImplemented){                                              \
-            PyVar self;                                                     \
-            PyVar _2 = get_unbound_method(_1, rfunc, &self, false);         \
+            PyVar self;                                                         \
+            PyVar _2 = get_unbound_method(_1, rfunc, &self, false);             \
             if(_2 != nullptr) ret = call_method(self, _2, _0);                  \
             else BinaryOptError(op, _0, _1);                                    \
             if(ret == NotImplemented) BinaryOptError(op, _0, _1);               \
@@ -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

+ 3 - 3
src/cffi.cpp

@@ -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);                               \

+ 4 - 4
src/codeobject.cpp

@@ -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

+ 1 - 2
src/expr.cpp

@@ -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);

+ 4 - 4
src/gc.cpp

@@ -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()); }
     }
 
 

+ 7 - 1
src/memory.cpp

@@ -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(); }
 
 }

+ 3 - 3
src/pocketpy.cpp

@@ -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{

+ 2 - 2
src/tuplelist.cpp

@@ -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());

+ 10 - 12
src/vm.cpp

@@ -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;