blueloveTH 1 an în urmă
părinte
comite
aaf7a84a3a

+ 36 - 0
include/pocketpy/interpreter/typeinfo.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include "pocketpy/pocketpy.h"
+#include "pocketpy/objects/object.h"
+
+typedef struct py_TypeInfo {
+    py_Name name;
+    py_Type base;
+
+    py_TValue self;
+    py_TValue module;  // the module where the type is defined
+
+    bool is_python;  // is it a python class? (not derived from c object)
+    bool is_sealed;  // can it be subclassed?
+
+    void (*dtor)(void*);
+
+    py_TValue annotations;  // type annotations
+
+    void (*on_end_subclass)(struct py_TypeInfo*);  // backdoor for enum module
+    void (*gc_mark)(void* ud);
+
+    /* Magic Slots */
+    py_TValue magic[64];
+} py_TypeInfo;
+
+typedef struct TypeList {
+    int length;
+    py_TypeInfo* chunks[256];
+} TypeList;
+
+void TypeList__ctor(TypeList* self);
+void TypeList__dtor(TypeList* self);
+py_TypeInfo* TypeList__get(TypeList* self, py_Type index);
+py_TypeInfo* TypeList__emplace(TypeList* self);
+void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx);

+ 3 - 22
include/pocketpy/interpreter/vm.h

@@ -5,6 +5,7 @@
 #include "pocketpy/interpreter/heap.h"
 #include "pocketpy/interpreter/frame.h"
 #include "pocketpy/interpreter/modules.h"
+#include "pocketpy/interpreter/typeinfo.h"
 
 // TODO:
 // 1. __eq__ and __ne__ fallbacks
@@ -15,32 +16,11 @@
 // 6. py_TypeInfo
 // 7. Direct assignment of py_NIL, py_True, py_False, py_None. They are slow.
 
-typedef struct py_TypeInfo {
-    py_Name name;
-    py_Type base;
-
-    py_TValue self;
-    py_TValue module;  // the module where the type is defined
-
-    bool is_python;  // is it a python class? (not derived from c object)
-    bool is_sealed;  // can it be subclassed?
-
-    void (*dtor)(void*);
-
-    py_TValue annotations;  // type annotations
-
-    void (*on_end_subclass)(struct py_TypeInfo*);  // backdoor for enum module
-    void (*gc_mark)(void* ud);
-
-    /* Magic Slots */
-    py_TValue magic[64];
-} py_TypeInfo;
-
 typedef struct VM {
     Frame* top_frame;
 
     ModuleDict modules;
-    c11_vector /*T=py_TypeInfo*/ types;
+    TypeList types;
 
     py_TValue builtins;  // builtins module
     py_TValue main;      // __main__ module
@@ -74,6 +54,7 @@ void pk__mark_value(py_TValue*);
 void pk__mark_namedict(NameDict*);
 void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*));
 bool pk__object_new(int argc, py_Ref argv);
+py_TypeInfo* pk__type_info(py_Type type);
 
 bool pk_wrapper__self(int argc, py_Ref argv);
 bool pk_wrapper__NotImplementedError(int argc, py_Ref argv);

+ 1 - 1
include/pocketpy/objects/namedict.h

@@ -24,4 +24,4 @@ void ModuleDict__ctor(ModuleDict* self, const char* path, py_TValue module);
 void ModuleDict__dtor(ModuleDict* self);
 void ModuleDict__set(ModuleDict* self, const char* key, py_TValue val);
 py_TValue* ModuleDict__try_get(ModuleDict* self, const char* path);
-bool ModuleDict__contains(ModuleDict* self, const char* path);
+bool ModuleDict__contains(ModuleDict* self, const char* path);

+ 5 - 5
include/pocketpy/pocketpy.h

@@ -250,18 +250,18 @@ PK_EXPORT bool py_isinstance(py_Ref obj, py_Type type);
 /// Check if the derived type is a subclass of the base type.
 PK_EXPORT bool py_issubclass(py_Type derived, py_Type base);
 
+/// Get the magic method from the given type only.
+/// The returned reference is always valid. However, its value may be `nil`.
+PK_EXPORT py_GlobalRef py_tpgetmagic(py_Type type, py_Name name);
 /// Search the magic method from the given type to the base type.
 /// Return `NULL` if not found.
-PK_EXPORT py_ItemRef py_tpfindmagic(py_Type, py_Name name);
+PK_EXPORT py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
 /// Search the name from the given type to the base type.
 /// Return `NULL` if not found.
 PK_EXPORT py_ItemRef py_tpfindname(py_Type, py_Name name);
-/// Get the magic method from the given type only.
-/// The returned reference is always valid. However, its value may be `nil`.
-PK_EXPORT py_ItemRef py_tpgetmagic(py_Type type, py_Name name);
 
 /// Get the type object of the given type.
-PK_EXPORT py_ItemRef py_tpobject(py_Type type);
+PK_EXPORT py_GlobalRef py_tpobject(py_Type type);
 /// Get the type name.
 PK_EXPORT const char* py_tpname(py_Type type);
 /// Call a type to create a new instance.

+ 4 - 4
src/interpreter/ceval.c

@@ -871,7 +871,7 @@ FrameResult VM__run_top_frame(VM* self) {
                 }
                 POP();
 
-                py_TypeInfo* base_ti = c11__at(py_TypeInfo, &self->types, base);
+                py_TypeInfo* base_ti = TypeList__get(&self->types, base);
                 if(base_ti->is_sealed) {
                     TypeError("type '%t' is not an acceptable base type", base);
                     goto __ERROR;
@@ -892,9 +892,9 @@ FrameResult VM__run_top_frame(VM* self) {
 
                 if(py_istype(TOP(), tp_type)) {
                     // call on_end_subclass
-                    py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, py_totype(TOP()));
+                    py_TypeInfo* ti = TypeList__get(&self->types, py_totype(TOP()));
                     if(ti->base != tp_object) {
-                        py_TypeInfo* base_ti = c11__at(py_TypeInfo, &self->types, ti->base);
+                        py_TypeInfo* base_ti = TypeList__get(&self->types, ti->base);
                         if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
                     }
                 }
@@ -915,7 +915,7 @@ FrameResult VM__run_top_frame(VM* self) {
             case OP_ADD_CLASS_ANNOTATION: {
                 // [type_hint string]
                 py_Type type = py_totype(self->__curr_class);
-                py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, type);
+                py_TypeInfo* ti = TypeList__get(&self->types, type);
                 if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations);
                 bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(byte.arg), TOP());
                 if(!ok) goto __ERROR;

+ 44 - 0
src/interpreter/typeinfo.c

@@ -0,0 +1,44 @@
+#include "pocketpy/interpreter/typeinfo.h"
+
+#define CHUNK_SIZE 128
+#define LOG2_CHUNK_SIZE 7
+
+static py_TypeInfo firstChunk[CHUNK_SIZE];
+
+void TypeList__ctor(TypeList* self) {
+    self->length = 0;
+    memset(self->chunks, 0, sizeof(self->chunks));
+    self->chunks[0] = firstChunk;
+}
+
+void TypeList__dtor(TypeList* self) {
+    for (int i = 1; i < self->length; i++) {
+        if(self->chunks[i]) free(self->chunks[i]);
+    }
+}
+
+py_TypeInfo* TypeList__get(TypeList* self, py_Type index) {
+    assert(index < self->length);
+    int chunk = index >> LOG2_CHUNK_SIZE;
+    int offset = index & (CHUNK_SIZE - 1);
+    return self->chunks[chunk] + offset;
+}
+
+py_TypeInfo* TypeList__emplace(TypeList* self){
+    int chunk = self->length >> LOG2_CHUNK_SIZE;
+    int offset = self->length & (CHUNK_SIZE - 1);
+    assert(chunk < 256);
+    if(self->chunks[chunk] == NULL){
+        self->chunks[chunk] = malloc(sizeof(py_TypeInfo) * CHUNK_SIZE);
+        memset(self->chunks[chunk], 0, sizeof(py_TypeInfo) * CHUNK_SIZE);
+    }
+    self->length++;
+    return self->chunks[chunk] + offset;
+}
+
+void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx) {
+    for (int i = 0; i < self->length; i++) {
+        py_TypeInfo* info = TypeList__get(self, i);
+        f(info, ctx);
+    }
+}

+ 21 - 17
src/interpreter/vm.c

@@ -4,6 +4,7 @@
 #include "pocketpy/common/utils.h"
 #include "pocketpy/interpreter/generator.h"
 #include "pocketpy/interpreter/modules.h"
+#include "pocketpy/interpreter/typeinfo.h"
 #include "pocketpy/objects/base.h"
 #include "pocketpy/common/_generated.h"
 #include "pocketpy/pocketpy.h"
@@ -56,7 +57,7 @@ void VM__ctor(VM* self) {
     self->top_frame = NULL;
 
     ModuleDict__ctor(&self->modules, NULL, *py_NIL);
-    c11_vector__ctor(&self->types, sizeof(py_TypeInfo));
+    TypeList__ctor(&self->types);
 
     self->builtins = *py_NIL;
     self->main = *py_NIL;
@@ -76,7 +77,7 @@ void VM__ctor(VM* self) {
 
     /* Init Builtin Types */
     // 0: unused
-    void* placeholder = c11_vector__emplace(&self->types);
+    void* placeholder = TypeList__emplace(&self->types);
     memset(placeholder, 0, sizeof(py_TypeInfo));
 
 #define validate(t, expr)                                                                          \
@@ -187,7 +188,7 @@ void VM__ctor(VM* self) {
     };
 
     for(int i = 0; i < c11__count_array(public_types); i++) {
-        py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, public_types[i]);
+        py_TypeInfo* ti = pk__type_info(public_types[i]);
         py_setdict(&self->builtins, ti->name, &ti->self);
     }
 
@@ -228,7 +229,7 @@ void VM__dtor(VM* self) {
     while(self->top_frame)
         VM__pop_frame(self);
     ModuleDict__dtor(&self->modules);
-    c11_vector__dtor(&self->types);
+    TypeList__dtor(&self->types);
     ValueStack__clear(&self->stack);
 }
 
@@ -316,10 +317,9 @@ py_Type pk_newtype(const char* name,
                    void (*dtor)(void*),
                    bool is_python,
                    bool is_sealed) {
-    c11_vector* types = &pk_current_vm->types;
-    py_Type index = types->length;
-    py_TypeInfo* ti = c11_vector__emplace(types);
-    py_TypeInfo* base_ti = base ? c11__at(py_TypeInfo, types, base) : NULL;
+    py_Type index = pk_current_vm->types.length;
+    py_TypeInfo* ti = TypeList__emplace(&pk_current_vm->types);
+    py_TypeInfo* base_ti = base ? pk__type_info(base) : NULL;
     if(base_ti && base_ti->is_sealed) {
         c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name));
     }
@@ -540,7 +540,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
 
 /****************************************/
 void PyObject__delete(PyObject* self) {
-    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, self->type);
+    py_TypeInfo* ti = pk__type_info(self->type);
     if(ti->dtor) ti->dtor(PyObject__userdata(self));
     if(self->slots == -1) NameDict__dtor(PyObject__dict(self));
     if(self->gc_is_large) {
@@ -564,7 +564,7 @@ void pk__mark_namedict(NameDict* dict) {
 }
 
 void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*)) {
-    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
+    py_TypeInfo* ti = pk__type_info(type);
     assert(ti->gc_mark == NULL);
     ti->gc_mark = gc_mark;
 }
@@ -582,8 +582,8 @@ static void mark_object(PyObject* obj) {
         pk__mark_namedict(dict);
     }
 
-    py_TypeInfo* types = c11__at(py_TypeInfo, &pk_current_vm->types, obj->type);
-    if(types->gc_mark) types->gc_mark(PyObject__userdata(obj));
+    py_TypeInfo* ti = pk__type_info(obj->type);
+    if(ti->gc_mark) ti->gc_mark(PyObject__userdata(obj));
 }
 
 void CodeObject__gc_mark(const CodeObject* self) {
@@ -603,18 +603,18 @@ void ManagedHeap__mark(ManagedHeap* self) {
         pk__mark_value(p);
     }
     // mark types
-    py_TypeInfo* types = vm->types.data;
     int types_length = vm->types.length;
     // 0-th type is placeholder
-    for(int i = 1; i < types_length; i++) {
+    for(py_Type i = 1; i < types_length; i++) {
+        py_TypeInfo* ti = TypeList__get(&vm->types, i);
         // mark magic slots
         for(int j = 0; j <= __missing__; j++) {
-            py_TValue* slot = types[i].magic + j;
+            py_TValue* slot = ti->magic + j;
             if(py_isnil(slot)) continue;
             pk__mark_value(slot);
         }
         // mark type annotations
-        pk__mark_value(&types[i].annotations);
+        pk__mark_value(&ti->annotations);
     }
     // mark frame
     for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) {
@@ -695,4 +695,8 @@ bool pk_wrapper__self(int argc, py_Ref argv) {
 
 bool pk_wrapper__NotImplementedError(int argc, py_Ref argv) {
     return py_exception(tp_NotImplementedError, "");
-}
+}
+
+py_TypeInfo* pk__type_info(py_Type type) {
+    return TypeList__get(&pk_current_vm->types, type);
+}

+ 1 - 1
src/modules/enum.c

@@ -86,6 +86,6 @@ void pk__add_module_enum() {
     py_bindproperty(type, "name", Enum__name, NULL);
     py_bindproperty(type, "value", Enum__value, NULL);
 
-    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
+    py_TypeInfo* ti = pk__type_info(type);
     ti->on_end_subclass = Enum__on_end_subclass;
 }

+ 3 - 2
src/public/cast.c

@@ -1,4 +1,5 @@
 #include "pocketpy/common/str.h"
+#include "pocketpy/objects/base.h"
 #include "pocketpy/pocketpy.h"
 
 #include "pocketpy/common/utils.h"
@@ -49,10 +50,10 @@ bool py_checktype(py_Ref self, py_Type type) {
 bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); }
 
 bool py_issubclass(py_Type derived, py_Type base) {
-    py_TypeInfo* types = pk_current_vm->types.data;
+    TypeList* types = &pk_current_vm->types;
     do {
         if(derived == base) return true;
-        derived = types[derived].base;
+        derived = TypeList__get(types, derived)->base;
     } while(derived);
     return false;
 }

+ 13 - 13
src/public/internal.c

@@ -1,3 +1,4 @@
+#include "pocketpy/interpreter/typeinfo.h"
 #include "pocketpy/objects/codeobject.h"
 #include "pocketpy/objects/sourcedata.h"
 #include "pocketpy/pocketpy.h"
@@ -178,7 +179,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
                 break;
             case tp_classmethod:
                 self[0] = *py_getslot(cls_var, 0);
-                self[1] = c11__getitem(py_TypeInfo, &pk_current_vm->types, type).self;
+                self[1] = pk__type_info(type)->self;
                 break;
             default: c11__unreachedable();
         }
@@ -189,41 +190,40 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
 
 py_Ref py_tpfindmagic(py_Type t, py_Name name) {
     assert(py_ismagicname(name));
-    py_TypeInfo* types = (py_TypeInfo*)pk_current_vm->types.data;
+    TypeList* types = &pk_current_vm->types;
     do {
-        py_Ref f = &types[t].magic[name];
+        py_TypeInfo* ti = TypeList__get(types, t);
+        py_Ref f = &ti->magic[name];
         if(!py_isnil(f)) return f;
-        t = types[t].base;
+        t = ti->base;
     } while(t);
     return NULL;
 }
 
 py_Ref py_tpfindname(py_Type t, py_Name name) {
-    py_TypeInfo* types = (py_TypeInfo*)pk_current_vm->types.data;
+    TypeList* types = &pk_current_vm->types;
     do {
-        py_Ref res = py_getdict(&types[t].self, name);
+        py_TypeInfo* ti = TypeList__get(types, t);
+        py_Ref res = py_getdict(&ti->self, name);
         if(res) return res;
-        t = types[t].base;
+        t = ti->base;
     } while(t);
     return NULL;
 }
 
 py_Ref py_tpgetmagic(py_Type type, py_Name name) {
     assert(py_ismagicname(name));
-    VM* vm = pk_current_vm;
-    return &c11__at(py_TypeInfo, &vm->types, type)->magic[name];
+    return pk__type_info(type)->magic + name;
 }
 
 py_Ref py_tpobject(py_Type type) {
     assert(type);
-    VM* vm = pk_current_vm;
-    return &c11__at(py_TypeInfo, &vm->types, type)->self;
+    return &pk__type_info(type)->self;
 }
 
 const char* py_tpname(py_Type type) {
     if(!type) return "nil";
-    VM* vm = pk_current_vm;
-    py_Name name = c11__at(py_TypeInfo, &vm->types, type)->name;
+    py_Name name = pk__type_info(type)->name;
     return py_name2str(name);
 }
 

+ 1 - 2
src/public/modules.c

@@ -675,8 +675,7 @@ static bool super__new__(int argc, py_Ref argv) {
         return TypeError("super() takes 0 or 2 arguments");
     }
 
-    py_TypeInfo* types = pk_current_vm->types.data;
-    *class_arg = types[*class_arg].base;
+    *class_arg = pk__type_info(*class_arg)->base;
     if(*class_arg == 0) return RuntimeError("super(): base class is invalid");
 
     py_setslot(py_retval(), 0, self_arg);

+ 6 - 10
src/public/py_object.c

@@ -5,7 +5,7 @@
 bool pk__object_new(int argc, py_Ref argv) {
     if(argc == 0) return TypeError("object.__new__(): not enough arguments");
     py_Type cls = py_totype(py_arg(0));
-    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, cls);
+    py_TypeInfo* ti = pk__type_info(cls);
     if(!ti->is_python) {
         return TypeError("object.__new__(%t) is not safe, use %t.__new__()", cls, cls);
     }
@@ -72,8 +72,7 @@ static bool type__new__(int argc, py_Ref argv) {
 
 static bool type__base__(int argc, py_Ref argv) {
     PY_CHECK_ARGC(1);
-    py_Type type = py_totype(argv);
-    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
+    py_TypeInfo* ti = pk__type_info(py_totype(argv));
     if(ti->base) {
         py_assign(py_retval(), py_tpobject(ti->base));
     } else {
@@ -84,8 +83,7 @@ static bool type__base__(int argc, py_Ref argv) {
 
 static bool type__name__(int argc, py_Ref argv) {
     PY_CHECK_ARGC(1);
-    py_Type type = py_totype(argv);
-    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
+    py_TypeInfo* ti = pk__type_info(py_totype(argv));
     py_newstr(py_retval(), py_name2str(ti->name));
     return true;
 }
@@ -97,8 +95,7 @@ static bool type__getitem__(int argc, py_Ref argv) {
 
 static bool type__module__(int argc, py_Ref argv) {
     PY_CHECK_ARGC(1);
-    py_Type type = py_totype(argv);
-    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
+    py_TypeInfo* ti = pk__type_info(py_totype(argv));
     if(py_isnil(&ti->module)) {
         py_newnone(py_retval());
     } else {
@@ -110,8 +107,7 @@ static bool type__module__(int argc, py_Ref argv) {
 
 static bool type__annotations__(int argc, py_Ref argv) {
     PY_CHECK_ARGC(1);
-    py_Type type = py_totype(argv);
-    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
+    py_TypeInfo* ti = pk__type_info(py_totype(argv));
     if(py_isnil(&ti->annotations)) {
         py_newdict(py_retval());
     } else {
@@ -128,7 +124,7 @@ void pk_object__register() {
     py_bindmagic(tp_object, __eq__, object__eq__);
     py_bindmagic(tp_object, __ne__, object__ne__);
     py_bindmagic(tp_object, __repr__, object__repr__);
-    
+
     py_bindmagic(tp_type, __repr__, type__repr__);
     py_bindmagic(tp_type, __new__, type__new__);
     py_bindmagic(tp_type, __getitem__, type__getitem__);

+ 6 - 4
src/public/py_ops.c

@@ -1,3 +1,4 @@
+#include "pocketpy/interpreter/typeinfo.h"
 #include "pocketpy/interpreter/vm.h"
 #include "pocketpy/objects/base.h"
 #include "pocketpy/pocketpy.h"
@@ -45,11 +46,12 @@ int py_bool(py_Ref val) {
 
 bool py_hash(py_Ref val, int64_t* out) {
     py_Type t = val->type;
-    py_TypeInfo* types = (py_TypeInfo*)pk_current_vm->types.data;
+    TypeList* types = &pk_current_vm->types;
     do {
-        py_Ref _hash = &types[t].magic[__hash__];
+        py_TypeInfo* ti = TypeList__get(types, t);
+        py_Ref _hash = &ti->magic[__hash__];
         if(py_isnone(_hash)) break;
-        py_Ref _eq = &types[t].magic[__eq__];
+        py_Ref _eq = &ti->magic[__eq__];
         if(!py_isnil(_eq)) {
             if(py_isnil(_hash)) break;
             if(!py_call(_hash, 1, val)) return false;
@@ -57,7 +59,7 @@ bool py_hash(py_Ref val, int64_t* out) {
             *out = py_toint(py_retval());
             return true;
         }
-        t = types[t].base;
+        t = ti->base;
     } while(t);
     return TypeError("unhashable type: '%t'", val->type);
 }