diff --git a/include/pocketpy/export.h b/include/pocketpy/export.h index b7baee80..d60e9ca3 100644 --- a/include/pocketpy/export.h +++ b/include/pocketpy/export.h @@ -55,3 +55,9 @@ #else #define PK_IS_DESKTOP_PLATFORM 0 #endif + +#if defined(__GNUC__) || defined(__clang__) + #define PK_DEPRECATED [[deprecated]] +#else + #define PK_DEPRECATED +#endif \ No newline at end of file diff --git a/include/pocketpy/interpreter/typeinfo.h b/include/pocketpy/interpreter/typeinfo.h index 6594c702..e2901fa2 100644 --- a/include/pocketpy/interpreter/typeinfo.h +++ b/include/pocketpy/interpreter/typeinfo.h @@ -36,7 +36,4 @@ 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(py_TypeInfo* self, unsigned index); -#define TypeList__magic_common(ti, index) ((ti)->magic_0 + ((index)-PK_MAGIC_SLOTS_UNCOMMON_LENGTH)) diff --git a/include/pocketpy/objects/codeobject.h b/include/pocketpy/objects/codeobject.h index 74800e5e..3cef66ad 100644 --- a/include/pocketpy/objects/codeobject.h +++ b/include/pocketpy/objects/codeobject.h @@ -96,7 +96,7 @@ void CodeObject__gc_mark(const CodeObject* self, c11_vector* p_stack); typedef struct FuncDeclKwArg { int index; // index in co->varnames - uint16_t key; // name of this argument + py_Name key; // name of this argument py_TValue value; // default value } FuncDeclKwArg; diff --git a/include/pocketpy/objects/namedict.h b/include/pocketpy/objects/namedict.h index 41311c80..1ce2a735 100644 --- a/include/pocketpy/objects/namedict.h +++ b/include/pocketpy/objects/namedict.h @@ -37,6 +37,7 @@ typedef struct NameDict { } NameDict; NameDict* NameDict__new(float load_factor); +void NameDict__delete(NameDict* self); void NameDict__ctor(NameDict* self, float load_factor); void NameDict__dtor(NameDict* self); py_TValue* NameDict__try_get(NameDict* self, py_Name key); diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index a8eb86b6..f92f8146 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -242,8 +242,8 @@ PK_API py_GlobalRef py_name2ref(py_Name); PK_API py_Name py_namev(c11_sv); /// Convert a name to a `c11_sv`. PK_API c11_sv py_name2sv(py_Name); - -#define py_ismagicname(name) (name <= __missing__) +/// Check if the name matches the two underscores pattern. e.g. `__init__`, `__str__`, etc. +PK_API bool py_ismagicname(py_Name); /************* Meta Operations *************/ @@ -318,7 +318,7 @@ PK_API 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_API py_GlobalRef py_tpgetmagic(py_Type type, py_Name name); +PK_API PK_DEPRECATED 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_API py_GlobalRef py_tpfindmagic(py_Type, py_Name name); @@ -438,8 +438,8 @@ PK_API void py_bindfunc(py_Ref obj, const char* name, py_CFunction f); /// @param setter setter function. Use `NULL` if not needed. PK_API void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter); - -#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpgetmagic((type), __magic__), (f)) +/// Bind a magic method to type. +PK_API void py_bindmagic(py_Type type, py_Name name, py_CFunction f); #define PY_CHECK_ARGC(n) \ if(argc != n) return TypeError("expected %d arguments, got %d", n, argc) @@ -737,11 +737,11 @@ enum py_PredefinedType { tp_locals, tp_code, tp_dict, - tp_dict_iterator, // 1 slot - tp_property, // 2 slots (getter + setter) - tp_star_wrapper, // 1 slot + int level - tp_staticmethod, // 1 slot - tp_classmethod, // 1 slot + tp_dict_iterator, // 1 slot + tp_property, // 2 slots (getter + setter) + tp_star_wrapper, // 1 slot + int level + tp_staticmethod, // 1 slot + tp_classmethod, // 1 slot tp_NoneType, tp_NotImplementedType, tp_ellipsis, diff --git a/src/interpreter/heap.c b/src/interpreter/heap.c index 37b1d2ff..e50aaceb 100644 --- a/src/interpreter/heap.c +++ b/src/interpreter/heap.c @@ -44,7 +44,8 @@ void ManagedHeap__collect_if_needed(ManagedHeap* self) { const int lower = PK_GC_MIN_THRESHOLD / 2; float free_ratio = (float)avg_freed / self->gc_threshold; int new_threshold = self->gc_threshold * (1 / free_ratio); - // printf("gc_threshold=%d, avg_freed=%d, new_threshold=%d\n", self->gc_threshold, avg_freed, new_threshold); + // printf("gc_threshold=%d, avg_freed=%d, new_threshold=%d\n", self->gc_threshold, avg_freed, + // new_threshold); self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper); } @@ -98,7 +99,9 @@ PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int uds if(slots >= 0) { memset(obj->flex, 0, slots * sizeof(py_TValue)); } else { - NameDict__ctor((void*)obj->flex); + float load_factor = (type == tp_type || type == tp_module) ? PK_TYPE_ATTR_LOAD_FACTOR + : PK_INST_ATTR_LOAD_FACTOR; + NameDict__ctor((void*)obj->flex, load_factor); } self->gc_counter++; diff --git a/src/interpreter/typeinfo.c b/src/interpreter/typeinfo.c index 35178c6b..7d352ae6 100644 --- a/src/interpreter/typeinfo.c +++ b/src/interpreter/typeinfo.c @@ -12,7 +12,7 @@ void TypeList__ctor(TypeList* self) { void TypeList__dtor(TypeList* self) { 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); + (void)info; } for(int i = 0; i < PK_MAX_CHUNK_LENGTH; i++) { if(self->chunks[i]) PK_FREE(self->chunks[i]); @@ -47,28 +47,5 @@ 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(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) return py_NIL(); - return self->magic_1 + index; -} - #undef CHUNK_SIZE #undef LOG2_CHUNK_SIZE \ No newline at end of file diff --git a/src/objects/namedict.c b/src/objects/namedict.c index feb7afeb..d5f2cdbb 100644 --- a/src/objects/namedict.c +++ b/src/objects/namedict.c @@ -132,6 +132,11 @@ NameDict* NameDict__new(float load_factor) { return p; } +void NameDict__delete(NameDict* self) { + NameDict__dtor(self); + PK_FREE(self); +} + void NameDict__ctor(NameDict* self, float load_factor) { assert(load_factor > 0.0f && load_factor < 1.0f); self->length = 0; diff --git a/src/public/internal.c b/src/public/internal.c index 7bbe124b..cd7c5945 100644 --- a/src/public/internal.c +++ b/src/public/internal.c @@ -229,14 +229,7 @@ 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* ti = pk__type_info(t); - do { - py_Ref f = TypeList__magic_readonly(ti, name); - assert(f != NULL); - if(!py_isnil(f)) return f; - ti = ti->base_ti; - } while(ti); - return NULL; + return py_tpfindname(t, name); } py_Ref py_tpfindname(py_Type t, py_Name name) { @@ -249,10 +242,11 @@ py_Ref py_tpfindname(py_Type t, py_Name name) { return NULL; } -py_Ref py_tpgetmagic(py_Type type, py_Name name) { +PK_DEPRECATED py_Ref py_tpgetmagic(py_Type type, py_Name name) { assert(py_ismagicname(name)); py_TypeInfo* ti = pk__type_info(type); - return TypeList__magic(ti, name); + py_Ref retval = py_getdict(&ti->self, name); + return retval != NULL ? retval : py_NIL(); } py_Ref py_tpobject(py_Type type) { diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 71d13bb7..2be4d16c 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -54,11 +54,10 @@ 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 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; + py_Ref slot_hash = py_getdict(&ti->self, __hash__); + if(!slot_hash || py_isnone(slot_hash)) break; + py_Ref slot_eq = py_getdict(&ti->self, __eq__); + if(slot_eq) { if(!py_call(slot_hash, 1, val)) return false; if(!py_checkint(py_retval())) return false; *out = py_toint(py_retval()); diff --git a/src/public/values.c b/src/public/values.c index edb86f4e..a05abde6 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -83,14 +83,22 @@ void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFu py_setdict(py_tpobject(type), py_name(name), &tmp); } +void py_bindmagic(py_Type type, py_Name name, py_CFunction f) { + py_Ref tmp = py_emplacedict(py_tpobject(type), name); + py_newnativefunc(tmp, f); +} + void py_bind(py_Ref obj, const char* sig, py_CFunction f) { py_TValue tmp; py_Name name = py_newfunction(&tmp, sig, f, NULL, 0); py_setdict(obj, name, &tmp); } -py_Name - py_newfunction(py_OutRef out, const char* sig, py_CFunction f, const char* docstring, int slots) { +py_Name py_newfunction(py_OutRef out, + const char* sig, + py_CFunction f, + const char* docstring, + int slots) { char buffer[256]; snprintf(buffer, sizeof(buffer), "def %s: pass", sig); // fn(a, b, *c, d=1) -> None