reduce type's memory cost

This commit is contained in:
blueloveTH 2024-12-31 14:53:15 +08:00
parent 6edb757617
commit 9914c4838c
6 changed files with 76 additions and 24 deletions

View File

@ -3,6 +3,10 @@
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/objects/object.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 { typedef struct py_TypeInfo {
py_Name name; py_Name name;
py_Type base; py_Type base;
@ -22,12 +26,13 @@ typedef struct py_TypeInfo {
void (*gc_mark)(void* ud); void (*gc_mark)(void* ud);
/* Magic Slots */ /* 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; } py_TypeInfo;
typedef struct TypeList { typedef struct TypeList {
int length; int length;
py_TypeInfo* chunks[256]; py_TypeInfo* chunks[PK_MAX_CHUNK_LENGTH];
} TypeList; } TypeList;
void TypeList__ctor(TypeList* self); 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__get(TypeList* self, py_Type index);
py_TypeInfo* TypeList__emplace(TypeList* self); py_TypeInfo* TypeList__emplace(TypeList* self);
void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx); 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))

View File

@ -1008,13 +1008,13 @@ FrameResult VM__run_top_frame(VM* self) {
py_TypeInfo* base_ti = ti->base_ti; py_TypeInfo* base_ti = ti->base_ti;
if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti); if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
} }
if(!py_isnil(&ti->magic[__eq__])) { py_TValue* slot_eq = TypeList__magic_common(ti, __eq__);
if(py_isnil(&ti->magic[__ne__])) { 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); TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name);
goto __ERROR; goto __ERROR;
} }
} }
}
// class with decorator is unsafe currently // class with decorator is unsafe currently
// it skips the above check // it skips the above check
POP(); POP();

View File

@ -1,4 +1,5 @@
#include "pocketpy/interpreter/typeinfo.h" #include "pocketpy/interpreter/typeinfo.h"
#include "pocketpy/common/utils.h"
#define CHUNK_SIZE 128 #define CHUNK_SIZE 128
#define LOG2_CHUNK_SIZE 7 #define LOG2_CHUNK_SIZE 7
@ -9,7 +10,11 @@ void TypeList__ctor(TypeList* self) {
} }
void TypeList__dtor(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]); if(self->chunks[i]) PK_FREE(self->chunks[i]);
} }
} }
@ -24,8 +29,10 @@ py_TypeInfo* TypeList__get(TypeList* self, py_Type index) {
py_TypeInfo* TypeList__emplace(TypeList* self) { py_TypeInfo* TypeList__emplace(TypeList* self) {
int chunk = self->length >> LOG2_CHUNK_SIZE; int chunk = self->length >> LOG2_CHUNK_SIZE;
int offset = self->length & (CHUNK_SIZE - 1); 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); self->chunks[chunk] = PK_MALLOC(sizeof(py_TypeInfo) * CHUNK_SIZE);
memset(self->chunks[chunk], 0, sizeof(py_TypeInfo) * CHUNK_SIZE); memset(self->chunks[chunk], 0, sizeof(py_TypeInfo) * CHUNK_SIZE);
} }
@ -40,5 +47,32 @@ void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* 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 CHUNK_SIZE
#undef LOG2_CHUNK_SIZE #undef LOG2_CHUNK_SIZE

View File

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

View File

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

View File

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