Procházet zdrojové kódy

reduce type's memory cost

blueloveTH před 1 rokem
rodič
revize
9914c4838c

+ 11 - 2
include/pocketpy/interpreter/typeinfo.h

@@ -3,6 +3,10 @@
 #include "pocketpy/pocketpy.h"
 #include "pocketpy/objects/object.h"
 
+#define PK_MAGIC_SLOTS_COMMON_LENGTH (__missing__ - __xor__)
+#define PK_MAGIC_SLOTS_UNCOMMON_LENGTH (__xor__ + 1)
+#define PK_MAX_CHUNK_LENGTH 256
+
 typedef struct py_TypeInfo {
     py_Name name;
     py_Type base;
@@ -22,12 +26,13 @@ typedef struct py_TypeInfo {
     void (*gc_mark)(void* ud);
 
     /* Magic Slots */
-    py_TValue magic[64];
+    py_TValue magic_0[PK_MAGIC_SLOTS_COMMON_LENGTH];  // common magic slots
+    py_TValue* magic_1;                               // uncommon magic slots
 } py_TypeInfo;
 
 typedef struct TypeList {
     int length;
-    py_TypeInfo* chunks[256];
+    py_TypeInfo* chunks[PK_MAX_CHUNK_LENGTH];
 } TypeList;
 
 void TypeList__ctor(TypeList* self);
@@ -35,3 +40,7 @@ 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);
+py_TValue* TypeList__magic(py_TypeInfo* self, unsigned index);
+py_TValue* TypeList__magic_readonly_nullable(py_TypeInfo* self, unsigned index);
+
+#define TypeList__magic_common(ti, index) ((ti)->magic_0 + ((index)-PK_MAGIC_SLOTS_UNCOMMON_LENGTH))

+ 5 - 5
src/interpreter/ceval.c

@@ -1008,11 +1008,11 @@ FrameResult VM__run_top_frame(VM* self) {
                         py_TypeInfo* base_ti = ti->base_ti;
                         if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
                     }
-                    if(!py_isnil(&ti->magic[__eq__])) {
-                        if(py_isnil(&ti->magic[__ne__])) {
-                            TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name);
-                            goto __ERROR;
-                        }
+                    py_TValue* slot_eq = TypeList__magic_common(ti, __eq__);
+                    py_TValue* slot_ne = TypeList__magic_common(ti, __ne__);
+                    if(!py_isnil(slot_eq) && py_isnil(slot_ne)) {
+                        TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name);
+                        goto __ERROR;
                     }
                 }
                 // class with decorator is unsafe currently

+ 39 - 5
src/interpreter/typeinfo.c

@@ -1,4 +1,5 @@
 #include "pocketpy/interpreter/typeinfo.h"
+#include "pocketpy/common/utils.h"
 
 #define CHUNK_SIZE 128
 #define LOG2_CHUNK_SIZE 7
@@ -9,7 +10,11 @@ void TypeList__ctor(TypeList* self) {
 }
 
 void TypeList__dtor(TypeList* self) {
-    for (int i = 0; i < self->length; i++) {
+    for(py_Type t = 0; t < self->length; t++) {
+        py_TypeInfo* info = TypeList__get(self, t);
+        if(info->magic_1) PK_FREE(info->magic_1);
+    }
+    for(int i = 0; i < PK_MAX_CHUNK_LENGTH; i++) {
         if(self->chunks[i]) PK_FREE(self->chunks[i]);
     }
 }
@@ -21,11 +26,13 @@ py_TypeInfo* TypeList__get(TypeList* self, py_Type index) {
     return self->chunks[chunk] + offset;
 }
 
-py_TypeInfo* TypeList__emplace(TypeList* self){
+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){
+    if(self->chunks[chunk] == NULL) {
+        if(chunk >= PK_MAX_CHUNK_LENGTH) {
+            c11__abort("TypeList__emplace(): max chunk length exceeded");
+        }
         self->chunks[chunk] = PK_MALLOC(sizeof(py_TypeInfo) * CHUNK_SIZE);
         memset(self->chunks[chunk], 0, sizeof(py_TypeInfo) * CHUNK_SIZE);
     }
@@ -34,11 +41,38 @@ py_TypeInfo* TypeList__emplace(TypeList* self){
 }
 
 void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx) {
-    for (int i = 0; i < self->length; i++) {
+    for(int i = 0; i < self->length; i++) {
         py_TypeInfo* info = TypeList__get(self, i);
         f(info, ctx);
     }
 }
 
+py_TValue* TypeList__magic(py_TypeInfo* self, unsigned index) {
+    if(index > __xor__) {
+        // common magic slots
+        return TypeList__magic_common(self, index);
+    }
+    // uncommon magic slots
+    if(self->magic_1 == NULL) {
+        self->magic_1 = PK_MALLOC(sizeof(py_TValue) * PK_MAGIC_SLOTS_UNCOMMON_LENGTH);
+        memset(self->magic_1, 0, sizeof(py_TValue) * PK_MAGIC_SLOTS_UNCOMMON_LENGTH);
+    }
+    return self->magic_1 + index;
+}
+
+py_TValue* TypeList__magic_readonly_nullable(py_TypeInfo* self, unsigned index) {
+    if(index > __xor__) {
+        // common magic slots
+        py_TValue* slot = TypeList__magic_common(self, index);
+        if(py_isnil(slot)) return NULL;
+        return slot;
+    }
+    // uncommon magic slots
+    if(self->magic_1 == NULL) return NULL;
+    py_TValue* slot = self->magic_1 + index;
+    if(py_isnil(slot)) return NULL;
+    return slot;
+}
+
 #undef CHUNK_SIZE
 #undef LOG2_CHUNK_SIZE

+ 11 - 3
src/interpreter/vm.c

@@ -649,12 +649,20 @@ void ManagedHeap__mark(ManagedHeap* self) {
     // 0-th type is placeholder
     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 = ti->magic + j;
+        // mark common magic slots
+        for(int j = 0; j < PK_MAGIC_SLOTS_COMMON_LENGTH; j++) {
+            py_TValue* slot = ti->magic_0 + j;
             if(py_isnil(slot)) continue;
             pk__mark_value(slot);
         }
+        // mark uncommon magic slots
+        if(ti->magic_1) {
+            for(int j = 0; j < PK_MAGIC_SLOTS_UNCOMMON_LENGTH; j++) {
+                py_TValue* slot = ti->magic_1 + j;
+                if(py_isnil(slot)) continue;
+                pk__mark_value(slot);
+            }
+        }
         // mark type annotations
         pk__mark_value(&ti->annotations);
     }

+ 4 - 3
src/public/internal.c

@@ -225,8 +225,8 @@ py_Ref py_tpfindmagic(py_Type t, py_Name name) {
     assert(py_ismagicname(name));
     py_TypeInfo* ti = pk__type_info(t);
     do {
-        py_Ref f = &ti->magic[name];
-        if(!py_isnil(f)) return f;
+        py_Ref f = TypeList__magic_readonly_nullable(ti, name);
+        if(f != NULL) return f;
         ti = ti->base_ti;
     } while(ti);
     return NULL;
@@ -244,7 +244,8 @@ py_Ref py_tpfindname(py_Type t, py_Name name) {
 
 py_Ref py_tpgetmagic(py_Type type, py_Name name) {
     assert(py_ismagicname(name));
-    return pk__type_info(type)->magic + name;
+    py_TypeInfo* ti = pk__type_info(type);
+    return TypeList__magic(ti, name);
 }
 
 py_Ref py_tpobject(py_Type type) {

+ 6 - 6
src/public/py_ops.c

@@ -47,12 +47,12 @@ int py_bool(py_Ref val) {
 bool py_hash(py_Ref val, int64_t* out) {
     py_TypeInfo* ti = pk__type_info(val->type);
     do {
-        py_Ref _hash = &ti->magic[__hash__];
-        if(py_isnone(_hash)) break;
-        py_Ref _eq = &ti->magic[__eq__];
-        if(!py_isnil(_eq)) {
-            if(py_isnil(_hash)) break;
-            if(!py_call(_hash, 1, val)) return false;
+        py_Ref slot_hash = TypeList__magic_common(ti, __hash__);
+        if(py_isnone(slot_hash)) break;
+        py_Ref slot_eq = TypeList__magic_common(ti, __eq__);
+        if(!py_isnil(slot_eq)) {
+            if(py_isnil(slot_hash)) break;
+            if(!py_call(slot_hash, 1, val)) return false;
             if(!py_checkint(py_retval())) return false;
             *out = py_toint(py_retval());
             return true;