diff --git a/include/pocketpy/common/namedict.h b/include/pocketpy/common/namedict.h deleted file mode 100644 index 623b5be3..00000000 --- a/include/pocketpy/common/namedict.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -typedef struct NameDict { - -} NameDict; \ No newline at end of file diff --git a/include/pocketpy/common/utils.h b/include/pocketpy/common/utils.h index cd842498..795081c6 100644 --- a/include/pocketpy/common/utils.h +++ b/include/pocketpy/common/utils.h @@ -23,6 +23,9 @@ abort(); \ } while(0) +#define c11__rtassert(cond) \ + if(!(cond)) c11__abort("Runtime assertion failed: %s", #cond) + #define c11__min(a, b) ((a) < (b) ? (a) : (b)) #define c11__max(a, b) ((a) > (b) ? (a) : (b)) @@ -42,4 +45,3 @@ typedef struct RefCounted { PK_FREE(obj); \ } \ } while(0) - diff --git a/include/pocketpy/config.h b/include/pocketpy/config.h index 6f3a6bcd..75c4733c 100644 --- a/include/pocketpy/config.h +++ b/include/pocketpy/config.h @@ -60,6 +60,12 @@ #define PK_M_DEG2RAD 0.017453292519943295 #define PK_M_RAD2DEG 57.29577951308232 +// Hash table load factor (smaller ones mean less collision but more memory) +// For class instance +#define PK_INST_ATTR_LOAD_FACTOR 0.67 +// For class itself +#define PK_TYPE_ATTR_LOAD_FACTOR 0.5 + #ifdef _WIN32 #define PK_PLATFORM_SEP '\\' #else diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index 2475a477..8b0fcf22 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/include/pocketpy/interpreter/frame.h @@ -1,9 +1,7 @@ #pragma once -#include "pocketpy/common/memorypool.h" #include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/namedict.h" -#include "pocketpy/objects/object.h" #include "pocketpy/pocketpy.h" void FastLocals__to_dict(py_TValue* locals, const CodeObject* co) PY_RETURN; diff --git a/include/pocketpy/interpreter/typeinfo.h b/include/pocketpy/interpreter/typeinfo.h index 2f7cc63e..6594c702 100644 --- a/include/pocketpy/interpreter/typeinfo.h +++ b/include/pocketpy/interpreter/typeinfo.h @@ -3,8 +3,6 @@ #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 { @@ -25,8 +23,7 @@ typedef struct py_TypeInfo { void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module /* Magic Slots */ - py_TValue magic_0[PK_MAGIC_SLOTS_COMMON_LENGTH]; // common magic slots - py_TValue* magic_1; // uncommon magic slots + // (deleted) } py_TypeInfo; typedef struct TypeList { diff --git a/include/pocketpy/objects/namedict.h b/include/pocketpy/objects/namedict.h index 5a168f82..41311c80 100644 --- a/include/pocketpy/objects/namedict.h +++ b/include/pocketpy/objects/namedict.h @@ -1,16 +1,8 @@ #pragma once #include "pocketpy/common/vector.h" -#include "pocketpy/common/str.h" #include "pocketpy/objects/base.h" -#include - -#define SMALLMAP_T__HEADER -#define K uint16_t -#define V py_TValue -#define NAME NameDict -#include "pocketpy/xmacros/smallmap.h" -#undef SMALLMAP_T__HEADER +#include "pocketpy/pocketpy.h" /* A simple binary tree for storing modules. */ typedef struct ModuleDict { @@ -26,3 +18,29 @@ 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); void ModuleDict__apply_mark(ModuleDict* self, c11_vector* p_stack); + +/////////////////// NameDict /////////////////// + +typedef struct NameDict_KV { + py_Name key; + py_TValue value; +} NameDict_KV; + +// https://github.com/pocketpy/pocketpy/blob/v1.x/include/pocketpy/namedict.h +typedef struct NameDict { + int length; + float load_factor; + int capacity; + int critical_size; + uintptr_t mask; + NameDict_KV* items; +} NameDict; + +NameDict* NameDict__new(float load_factor); +void NameDict__ctor(NameDict* self, float load_factor); +void NameDict__dtor(NameDict* self); +py_TValue* NameDict__try_get(NameDict* self, py_Name key); +bool NameDict__contains(NameDict* self, py_Name key); +void NameDict__set(NameDict* self, py_Name key, py_TValue* value); +bool NameDict__del(NameDict* self, py_Name key); +void NameDict__clear(NameDict* self); \ No newline at end of file diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index b47e2834..d0ebb0eb 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -70,7 +70,7 @@ static bool unpack_dict_to_buffer(py_Ref key, py_Ref val, void* ctx) { py_TValue** p = ctx; if(py_isstr(key)) { py_Name name = py_namev(py_tosv(key)); - py_newint(*p, name); + py_newint(*p, (uintptr_t)name); py_assign(*p + 1, val); (*p) += 2; return true; @@ -80,7 +80,8 @@ static bool unpack_dict_to_buffer(py_Ref key, py_Ref val, void* ctx) { FrameResult VM__run_top_frame(VM* self) { py_Frame* frame = self->top_frame; - Bytecode* codes; + Bytecode* co_codes; + py_Name* co_names; const py_Frame* base_frame = frame; @@ -91,11 +92,12 @@ FrameResult VM__run_top_frame(VM* self) { py_exception(tp_RecursionError, "maximum recursion depth exceeded"); goto __ERROR; } - codes = frame->co->codes.data; + co_codes = frame->co->codes.data; + co_names = frame->co->names.data; frame->ip++; __NEXT_STEP: - byte = codes[frame->ip]; + byte = co_codes[frame->ip]; if(self->trace_info.func) { SourceLocation loc = Frame__source_location(frame); @@ -195,7 +197,7 @@ FrameResult VM__run_top_frame(VM* self) { ud->closure = FastLocals__to_namedict(frame->locals, frame->co); py_Name name = py_name(decl->code.name->data); // capture itself to allow recursion - NameDict__set(ud->closure, name, *SP()); + NameDict__set(ud->closure, name, SP()); } SP()++; DISPATCH(); @@ -217,7 +219,7 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_LOAD_NAME: { assert(frame->is_locals_special); - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; // locals switch(frame->locals->type) { case tp_locals: { @@ -261,7 +263,7 @@ FrameResult VM__run_top_frame(VM* self) { goto __ERROR; } case OP_LOAD_NONLOCAL: { - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; py_Ref tmp = Frame__getclosure(frame, name); if(tmp != NULL) { PUSH(tmp); @@ -283,7 +285,7 @@ FrameResult VM__run_top_frame(VM* self) { goto __ERROR; } case OP_LOAD_GLOBAL: { - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; int res = Frame__getglobal(frame, name); if(res == 1) { PUSH(&self->last_retval); @@ -299,7 +301,8 @@ FrameResult VM__run_top_frame(VM* self) { goto __ERROR; } case OP_LOAD_ATTR: { - if(py_getattr(TOP(), byte.arg)) { + py_Name name = co_names[byte.arg]; + if(py_getattr(TOP(), name)) { py_assign(TOP(), py_retval()); } else { goto __ERROR; @@ -308,7 +311,7 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_LOAD_CLASS_GLOBAL: { assert(self->curr_class); - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; py_Ref tmp = py_getdict(self->curr_class, name); if(tmp) { PUSH(tmp); @@ -331,10 +334,11 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_LOAD_METHOD: { // [self] -> [unbound, self] - bool ok = py_pushmethod(byte.arg); + py_Name name = co_names[byte.arg]; + bool ok = py_pushmethod(name); if(!ok) { // fallback to getattr - if(py_getattr(TOP(), byte.arg)) { + if(py_getattr(TOP(), name)) { py_assign(TOP(), py_retval()); py_newnil(SP()++); } else { @@ -368,7 +372,7 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_STORE_NAME: { assert(frame->is_locals_special); - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; switch(frame->locals->type) { case tp_locals: { py_Frame* noproxy = frame->locals->_ptr; @@ -395,13 +399,15 @@ FrameResult VM__run_top_frame(VM* self) { } } case OP_STORE_GLOBAL: { - if(!Frame__setglobal(frame, byte.arg, TOP())) goto __ERROR; + py_Name name = co_names[byte.arg]; + if(!Frame__setglobal(frame, name, TOP())) goto __ERROR; POP(); DISPATCH(); } case OP_STORE_ATTR: { // [val, a] -> a.b = val - if(!py_setattr(TOP(), byte.arg, SECOND())) goto __ERROR; + py_Name name = co_names[byte.arg]; + if(!py_setattr(TOP(), name, SECOND())) goto __ERROR; STACK_SHRINK(2); DISPATCH(); } @@ -435,7 +441,7 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_DELETE_NAME: { assert(frame->is_locals_special); - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; switch(frame->locals->type) { case tp_locals: { py_Frame* noproxy = frame->locals->_ptr; @@ -464,7 +470,7 @@ FrameResult VM__run_top_frame(VM* self) { } } case OP_DELETE_GLOBAL: { - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; int res = Frame__delglobal(frame, name); if(res == 1) DISPATCH(); if(res == -1) goto __ERROR; @@ -473,7 +479,7 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_DELETE_ATTR: { - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; if(!py_delattr(TOP(), name)) goto __ERROR; DISPATCH(); } @@ -896,8 +902,8 @@ FrameResult VM__run_top_frame(VM* self) { } } else { for(int i = 0; i < dict->length; i++) { - NameDict_KV* kv = c11__at(NameDict_KV, dict, i); - if(!kv->key) continue; + NameDict_KV* kv = &dict->items[i]; + if(kv->key == NULL) continue; c11_sv name = py_name2sv(kv->key); if(name.size == 0 || name.data[0] == '_') continue; if(!Frame__setglobal(frame, kv->key, &kv->value)) goto __ERROR; @@ -1000,7 +1006,7 @@ FrameResult VM__run_top_frame(VM* self) { /////////// case OP_BEGIN_CLASS: { // [base] - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; py_Type base; if(py_isnone(TOP())) { base = tp_object; @@ -1028,7 +1034,7 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_END_CLASS: { // [cls or decorated] - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; if(!Frame__setglobal(frame, name, TOP())) goto __ERROR; if(py_istype(TOP(), tp_type)) { @@ -1038,9 +1044,9 @@ 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); } - 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)) { + py_TValue* slot_eq = py_getdict(&ti->self, __eq__); + py_TValue* slot_ne = py_getdict(&ti->self, __ne__); + if(slot_eq && !slot_ne) { TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name); goto __ERROR; } @@ -1053,7 +1059,7 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_STORE_CLASS_ATTR: { assert(self->curr_class); - py_Name name = c11__getitem(py_Name, &frame->co->names, byte.arg); + py_Name name = co_names[byte.arg]; // TOP() can be a function, classmethod or custom decorator py_Ref actual_func = TOP(); if(actual_func->type == tp_classmethod) { @@ -1073,7 +1079,8 @@ FrameResult VM__run_top_frame(VM* self) { py_Type type = py_totype(self->curr_class); 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()); + py_Name name = co_names[byte.arg]; + bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP()); if(!ok) goto __ERROR; POP(); DISPATCH(); @@ -1212,7 +1219,7 @@ FrameResult VM__run_top_frame(VM* self) { return RES_ERROR; } frame = self->top_frame; - codes = frame->co->codes.data; + co_codes = frame->co->codes.data; goto __ERROR; } } @@ -1221,30 +1228,28 @@ FrameResult VM__run_top_frame(VM* self) { } const char* pk_op2str(py_Name op) { - switch(op) { - case __eq__: return "=="; - case __ne__: return "!="; - case __lt__: return "<"; - case __le__: return "<="; - case __gt__: return ">"; - case __ge__: return ">="; - case __add__: return "+"; - case __sub__: return "-"; - case __mul__: return "*"; - case __truediv__: return "/"; - case __floordiv__: return "//"; - case __mod__: return "%"; - case __pow__: return "**"; - case __lshift__: return "<<"; - case __rshift__: return ">>"; - case __and__: return "&"; - case __or__: return "|"; - case __xor__: return "^"; - case __neg__: return "-"; - case __invert__: return "~"; - case __matmul__: return "@"; - default: return py_name2str(op); - } + if(__eq__ == op) return "=="; + if(__ne__ == op) return "!="; + if(__lt__ == op) return "<"; + if(__le__ == op) return "<="; + if(__gt__ == op) return ">"; + if(__ge__ == op) return ">="; + if(__add__ == op) return "+"; + if(__sub__ == op) return "-"; + if(__mul__ == op) return "*"; + if(__truediv__ == op) return "/"; + if(__floordiv__ == op) return "//"; + if(__mod__ == op) return "%"; + if(__pow__ == op) return "**"; + if(__lshift__ == op) return "<<"; + if(__rshift__ == op) return ">>"; + if(__and__ == op) return "&"; + if(__or__ == op) return "|"; + if(__xor__ == op) return "^"; + if(__neg__ == op) return "-"; + if(__invert__ == op) return "~"; + if(__matmul__ == op) return "@"; + return py_name2str(op); } bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) { diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index 40ecfb2a..7a63827e 100644 --- a/src/interpreter/frame.c +++ b/src/interpreter/frame.c @@ -29,10 +29,10 @@ void FastLocals__to_dict(py_TValue* locals, const CodeObject* co) { } NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) { - NameDict* dict = NameDict__new(); + NameDict* dict = NameDict__new(PK_INST_ATTR_LOAD_FACTOR); c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) { - py_TValue value = locals[entry->value]; - if(!py_isnil(&value)) NameDict__set(dict, entry->key, value); + py_Ref val = &locals[entry->value]; + if(!py_isnil(val)) NameDict__set(dict, entry->key, val); } return dict; } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 627b9b76..01e84a98 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -653,20 +653,6 @@ void ManagedHeap__mark(ManagedHeap* self) { py_TypeInfo* ti = TypeList__get(&vm->types, i); // mark type object pk__mark_value(&ti->self); - // 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); } @@ -701,7 +687,8 @@ void ManagedHeap__mark(ManagedHeap* self) { } else if(obj->slots == -1) { NameDict* namedict = PyObject__dict(obj); for(int i = 0; i < namedict->length; i++) { - NameDict_KV* kv = c11__at(NameDict_KV, namedict, i); + NameDict_KV* kv = &namedict->items[i]; + if(kv->key == NULL) continue; pk__mark_value(&kv->value); } } diff --git a/src/modules/pickle.c b/src/modules/pickle.c index cc0112c9..258294b2 100644 --- a/src/modules/pickle.c +++ b/src/modules/pickle.c @@ -375,7 +375,8 @@ static bool pkl__write_object(PickleObject* buf, py_TValue* obj) { if(ti->is_python) { NameDict* dict = PyObject__dict(obj->_obj); for(int i = dict->length - 1; i >= 0; i--) { - NameDict_KV* kv = c11__at(NameDict_KV, dict, i); + NameDict_KV* kv = &dict->items[i]; + if(kv->key == NULL) continue; if(!pkl__write_object(buf, &kv->value)) return false; } pkl__emit_op(buf, PKL_OBJECT); @@ -383,7 +384,8 @@ static bool pkl__write_object(PickleObject* buf, py_TValue* obj) { buf->used_types[obj->type] = true; pkl__emit_int(buf, dict->length); for(int i = 0; i < dict->length; i++) { - NameDict_KV* kv = c11__at(NameDict_KV, dict, i); + NameDict_KV* kv = &dict->items[i]; + if(kv->key == NULL) continue; c11_sv field = py_name2sv(kv->key); // include '\0' PickleObject__write_bytes(buf, field.data, field.size + 1); @@ -685,7 +687,7 @@ bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_ for(int i = 0; i < dict_length; i++) { py_StackRef value = py_peek(-1); c11_sv field = {(const char*)p, strlen((const char*)p)}; - NameDict__set(dict, py_namev(field), *value); + NameDict__set(dict, py_namev(field), value); py_pop(); p += field.size + 1; } diff --git a/src/objects/namedict.c b/src/objects/namedict.c index a7e6a4ae..feb7afeb 100644 --- a/src/objects/namedict.c +++ b/src/objects/namedict.c @@ -1,12 +1,8 @@ #include "pocketpy/objects/namedict.h" +#include "pocketpy/common/utils.h" #include "pocketpy/objects/object.h" - -#define SMALLMAP_T__SOURCE -#define K uint16_t -#define V py_TValue -#define NAME NameDict -#include "pocketpy/xmacros/smallmap.h" -#undef SMALLMAP_T__SOURCE +#include "pocketpy/pocketpy.h" +#include void ModuleDict__ctor(ModuleDict* self, const char* path, py_TValue module) { assert(path != NULL); @@ -90,3 +86,122 @@ void ModuleDict__apply_mark(ModuleDict* self, c11_vector* p_stack) { if(self->left) ModuleDict__apply_mark(self->left, p_stack); if(self->right) ModuleDict__apply_mark(self->right, p_stack); } + +/////////////////// NameDict /////////////////// + +#define HASH_PROBE_1(__k, ok, i) \ + ok = false; \ + i = (uintptr_t)(__k) & self->mask; \ + while(self->items[i].key != NULL) { \ + if(self->items[i].key == (__k)) { \ + ok = true; \ + break; \ + } \ + i = (i + 1) & self->mask; \ + } + +#define HASH_PROBE_0 HASH_PROBE_1 + +static void NameDict__set_capacity_and_alloc_items(NameDict* self, int val) { + self->capacity = val; + self->critical_size = val * self->load_factor; + self->mask = (uintptr_t)val - 1; + + self->items = PK_MALLOC(self->capacity * sizeof(NameDict_KV)); + memset(self->items, 0, self->capacity * sizeof(NameDict_KV)); +} + +static void NameDict__rehash_2x(NameDict* self) { + NameDict_KV* old_items = self->items; + int old_capacity = self->capacity; + NameDict__set_capacity_and_alloc_items(self, self->capacity * 2); + for(int i = 0; i < old_capacity; i++) { + if(old_items[i].key == NULL) continue; + bool ok; + uintptr_t j; + HASH_PROBE_1(old_items[i].key, ok, j); + c11__rtassert(!ok); + self->items[j] = old_items[i]; + } + PK_FREE(old_items); +} + +NameDict* NameDict__new(float load_factor) { + NameDict* p = PK_MALLOC(sizeof(NameDict)); + NameDict__ctor(p, load_factor); + return p; +} + +void NameDict__ctor(NameDict* self, float load_factor) { + assert(load_factor > 0.0f && load_factor < 1.0f); + self->length = 0; + self->load_factor = load_factor; + NameDict__set_capacity_and_alloc_items(self, 4); +} + +void NameDict__dtor(NameDict* self) { PK_FREE(self->items); } + +py_TValue* NameDict__try_get(NameDict* self, py_Name key) { + bool ok; + uintptr_t i; + HASH_PROBE_0(key, ok, i); + if(!ok) return NULL; + return &self->items[i].value; +} + +bool NameDict__contains(NameDict* self, py_Name key) { + bool ok; + uintptr_t i; + HASH_PROBE_0(key, ok, i); + return ok; +} + +void NameDict__set(NameDict* self, py_Name key, py_TValue* val) { + bool ok; + uintptr_t i; + HASH_PROBE_1(key, ok, i); + if(!ok) { + self->length++; + if(self->length > self->critical_size) { + NameDict__rehash_2x(self); + HASH_PROBE_1(key, ok, i); + } + self->items[i].key = key; + } + self->items[i].value = *val; +} + +bool NameDict__del(NameDict* self, py_Name key) { + bool ok; + uintptr_t i; + HASH_PROBE_0(key, ok, i); + if(!ok) return false; + self->items[i].key = NULL; + self->items[i].value = *py_NIL(); + self->length--; + // tidy + uintptr_t pre_z = i; + uintptr_t z = (i + 1) & self->mask; + while(self->items[z].key != NULL) { + uintptr_t h = (uintptr_t)self->items[z].key & self->mask; + if(h != i) break; + // std::swap(_items[pre_z], _items[z]); + NameDict_KV tmp = self->items[pre_z]; + self->items[pre_z] = self->items[z]; + self->items[z] = tmp; + pre_z = z; + z = (z + 1) & self->mask; + } + return true; +} + +void NameDict__clear(NameDict* self) { + for(int i = 0; i < self->capacity; i++) { + self->items[i].key = NULL; + self->items[i].value = *py_NIL(); + } + self->length = 0; +} + +#undef HASH_PROBE_0 +#undef HASH_PROBE_1 \ No newline at end of file diff --git a/src/public/modules.c b/src/public/modules.c index bd47e3b3..a3359bde 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -617,7 +617,7 @@ static bool int max_index = -1; c11__foreach(Bytecode, &co->codes, bc) { if(bc->op == OP_LOAD_NAME) { - c11_sv name = py_name2sv(bc->arg); + c11_sv name = py_name2sv(c11__getitem(py_Name, &co->names, bc->arg)); if(name.data[0] != '_') continue; int index; if(name.size == 1) { @@ -766,7 +766,8 @@ void function__gc_mark(void* ud, c11_vector* p_stack) { if(func->closure) { NameDict* namedict = func->closure; for(int i = 0; i < namedict->length; i++) { - NameDict_KV* kv = c11__at(NameDict_KV, namedict, i); + NameDict_KV* kv = &namedict->items[i]; + if(kv->key == NULL) continue; pk__mark_value(&kv->value); } } diff --git a/src/public/py_mappingproxy.c b/src/public/py_mappingproxy.c index 805958d7..6e561793 100644 --- a/src/public/py_mappingproxy.c +++ b/src/public/py_mappingproxy.c @@ -52,29 +52,11 @@ static bool namedict_items(int argc, py_Ref argv) { py_Ref object = py_getslot(argv, 0); NameDict* dict = PyObject__dict(object->_obj); py_newlist(py_retval()); - if(object->type == tp_type) { - py_TypeInfo* ti = pk__type_info(py_totype(object)); - for(int j = 0; j < PK_MAGIC_SLOTS_COMMON_LENGTH; j++) { - if(py_isnil(ti->magic_0 + j)) continue; - py_Ref slot = py_list_emplace(py_retval()); - py_Ref p = py_newtuple(slot, 2); - p[0] = *py_name2ref(j + PK_MAGIC_SLOTS_UNCOMMON_LENGTH); - p[1] = ti->magic_0[j]; - } - if(ti->magic_1) { - for(int j = 0; j < PK_MAGIC_SLOTS_UNCOMMON_LENGTH; j++) { - if(py_isnil(ti->magic_1 + j)) continue; - py_Ref slot = py_list_emplace(py_retval()); - py_Ref p = py_newtuple(slot, 2); - p[0] = *py_name2ref(j); - p[1] = ti->magic_1[j]; - } - } - } for(int i = 0; i < dict->length; i++) { py_Ref slot = py_list_emplace(py_retval()); py_Ref p = py_newtuple(slot, 2); - NameDict_KV* kv = c11__at(NameDict_KV, dict, i); + NameDict_KV* kv = &dict->items[i]; + if(kv->key == NULL) continue; p[0] = *py_name2ref(kv->key); p[1] = kv->value; } diff --git a/src/public/stack_ops.c b/src/public/stack_ops.c index 055cf46d..c621b80a 100644 --- a/src/public/stack_ops.c +++ b/src/public/stack_ops.c @@ -10,23 +10,12 @@ void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; } py_Ref py_getdict(py_Ref self, py_Name name) { assert(self && self->is_ptr); - if(!py_ismagicname(name) || self->type != tp_type) { - return NameDict__try_get(PyObject__dict(self->_obj), name); - } else { - py_Type* ud = py_touserdata(self); - py_Ref slot = py_tpgetmagic(*ud, name); - return py_isnil(slot) ? NULL : slot; - } + return NameDict__try_get(PyObject__dict(self->_obj), name); } void py_setdict(py_Ref self, py_Name name, py_Ref val) { assert(self && self->is_ptr); - if(!py_ismagicname(name) || self->type != tp_type) { - NameDict__set(PyObject__dict(self->_obj), name, *val); - } else { - py_Type* ud = py_touserdata(self); - *py_tpgetmagic(*ud, name) = *val; - } + NameDict__set(PyObject__dict(self->_obj), name, val); } py_ItemRef py_emplacedict(py_Ref self, py_Name name) { @@ -38,7 +27,8 @@ bool py_applydict(py_Ref self, bool (*f)(py_Name, py_Ref, void*), void* ctx) { assert(self && self->is_ptr); NameDict* dict = PyObject__dict(self->_obj); for(int i = 0; i < dict->length; i++) { - NameDict_KV* kv = c11__at(NameDict_KV, dict, i); + NameDict_KV* kv = &dict->items[i]; + if(kv->key == NULL) continue; bool ok = f(kv->key, &kv->value, ctx); if(!ok) return false; } @@ -47,13 +37,7 @@ bool py_applydict(py_Ref self, bool (*f)(py_Name, py_Ref, void*), void* ctx) { bool py_deldict(py_Ref self, py_Name name) { assert(self && self->is_ptr); - if(!py_ismagicname(name) || self->type != tp_type) { - return NameDict__del(PyObject__dict(self->_obj), name); - } else { - py_Type* ud = py_touserdata(self); - py_newnil(py_tpgetmagic(*ud, name)); - return true; - } + return NameDict__del(PyObject__dict(self->_obj), name); } py_Ref py_getslot(py_Ref self, int i) { @@ -119,7 +103,7 @@ void py_pushnone() { void py_pushname(py_Name name) { VM* vm = pk_current_vm; - py_newint(vm->stack.sp++, name); + py_newint(vm->stack.sp++, (uintptr_t)name); } py_Ref py_pushtmp() {