diff --git a/include/pocketpy/common/str.h b/include/pocketpy/common/str.h index aab9a64f..f2efbcf7 100644 --- a/include/pocketpy/common/str.h +++ b/include/pocketpy/common/str.h @@ -22,6 +22,12 @@ typedef struct c11_string{ const char data[]; // flexible array member } c11_string; +/* bytes */ +typedef struct c11_bytes{ + int size; + unsigned char data[]; // flexible array member +} c11_bytes; + int c11_sv__cmp(c11_sv self, c11_sv other); int c11_sv__cmp2(c11_sv self, const char* other, int size); int c11_sv__cmp3(c11_sv self, const char* other); diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 2cce0e77..7aca8ec0 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -89,6 +89,8 @@ py_Type pk_VM__new_type(pk_VM* self, bool subclass_enabled); // type registration +py_Type pk_str__register(); +py_Type pk_bytes__register(); py_Type pk_list__register(); #ifdef __cplusplus diff --git a/include/pocketpy/objects/object.h b/include/pocketpy/objects/object.h index 99f3d6b0..ec1d005e 100644 --- a/include/pocketpy/objects/object.h +++ b/include/pocketpy/objects/object.h @@ -7,40 +7,29 @@ extern "C" { #endif -typedef struct PyObject{ - py_Type type; // we have a duplicated type here for convenience +typedef struct PyObject { + py_Type type; // we have a duplicated type here for convenience bool gc_is_large; bool gc_marked; - int slots; // number of slots in the object + int slots; // number of slots in the object + char flex[]; } PyObject; // slots >= 0, allocate N slots // slots == -1, allocate a dict -// | 8 bytes HEADER | | -// | 8 bytes HEADER | | - -static_assert(sizeof(PyObject) <= 8, "!(sizeof(PyObject) <= 8)"); +// | HEADER | | +// | HEADER | | py_TValue* PyObject__slots(PyObject* self); pk_NameDict* PyObject__dict(PyObject* self); -void* PyObject__value(PyObject* self); +void* PyObject__userdata(PyObject* self); -#define PK_OBJ_HEADER_SIZE(slots) ((slots)>=0 ? 8+sizeof(py_TValue)*(slots) : 8+sizeof(pk_NameDict)) +#define PK_OBJ_SLOTS_SIZE(slots) ((slots) >= 0 ? sizeof(py_TValue) * (slots) : sizeof(pk_NameDict)) PyObject* PyObject__new(py_Type type, int slots, int size); void PyObject__delete(PyObject* self); -PK_INLINE py_TValue PyVar__fromobj(PyObject* obj){ - if(!obj) return PY_NULL; - py_TValue retval = { - .type = obj->type, - .is_ptr = true, - ._obj = obj - }; - return retval; -} - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 8a658605..bdfef599 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -55,7 +55,7 @@ void py_newbool(py_Ref, bool); void py_newstr(py_Ref, const char*); void py_newstrn(py_Ref, const char*, int); // void py_newfstr(py_Ref, const char*, ...); -void py_newbytes(py_Ref, const unsigned char*, int); +unsigned char* py_newbytes(py_Ref, int); void py_newnone(py_Ref); void py_newnotimplemented(py_Ref out); void py_newellipsis(py_Ref out); @@ -104,7 +104,7 @@ bool py_tobool(const py_Ref); py_Type py_totype(const py_Ref); const char* py_tostr(const py_Ref); const char* py_tostrn(const py_Ref, int* size); -const unsigned char* py_tobytes(const py_Ref, int* size); +unsigned char* py_tobytes(const py_Ref, int* size); void* py_touserdata(const py_Ref); diff --git a/src/common/str.c b/src/common/str.c index cdb36bdf..6a88a34f 100644 --- a/src/common/str.c +++ b/src/common/str.c @@ -8,6 +8,7 @@ #include #include + c11_string* c11_string__new(const char* data) { return c11_string__new2(data, strlen(data)); } c11_string* c11_string__new2(const char* data, int size) { diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index c73a056c..0ed26dc7 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -1354,7 +1354,7 @@ int Ctx__add_const_string(Ctx* self, c11_sv key) { c11_vector__push(py_TValue, &self->co->consts, tmp); int index = self->co->consts.count - 1; c11_smallmap_s2n__set(&self->co_consts_string_dedup_map, - c11_string__sv(PyObject__value(tmp._obj)), + c11_string__sv(PyObject__userdata(tmp._obj)), index); return index; } diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index d0be6c63..324b8f49 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -426,9 +426,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { case OP_BUILD_BYTES: { int size; const char* data = py_tostrn(TOP(), &size); - unsigned char* p = (unsigned char*)malloc(size); + unsigned char* p = py_newbytes(TOP(), size); memcpy(p, data, size); - py_newbytes(TOP(), p, size); DISPATCH(); } case OP_BUILD_TUPLE: { diff --git a/src/interpreter/gc.c b/src/interpreter/gc.c index 7a0888ef..6ff11607 100644 --- a/src/interpreter/gc.c +++ b/src/interpreter/gc.c @@ -1,5 +1,6 @@ #include "pocketpy/interpreter/gc.h" #include "pocketpy/common/memorypool.h" +#include "pocketpy/objects/base.h" void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pk_VM *vm){ c11_vector__ctor(&self->no_gc, sizeof(PyObject*)); @@ -104,7 +105,8 @@ PyObject* pk_ManagedHeap__gcnew(pk_ManagedHeap *self, py_Type type, int slots, i PyObject* PyObject__new(py_Type type, int slots, int size){ assert(slots >= 0 || slots == -1); PyObject* self; - size += PK_OBJ_HEADER_SIZE(slots); + // header + slots + udsize + size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + size; if(size <= kPoolObjectBlockSize){ self = PoolObject_alloc(); self->gc_is_large = false; diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 93d46b0b..d19eee9b 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -38,7 +38,11 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self, // create type object with __dict__ pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* typeobj = pk_ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type)); - self->self = PyVar__fromobj(typeobj); + self->self = (py_TValue){ + .type = typeobj->type, + .is_ptr = true, + ._obj = typeobj, + }; self->module = module ? *module : PY_NULL; self->subclass_enabled = subclass_enabled; @@ -84,7 +88,7 @@ void pk_VM__ctor(pk_VM* self) { validate(tp_int, pk_VM__new_type(self, "int", tp_object, NULL, false)); validate(tp_float, pk_VM__new_type(self, "float", tp_object, NULL, false)); validate(tp_bool, pk_VM__new_type(self, "bool", tp_object, NULL, false)); - validate(tp_str, pk_VM__new_type(self, "str", tp_object, NULL, false)); + validate(tp_str, pk_str__register()); validate(tp_list, pk_list__register()); validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false)); @@ -99,7 +103,7 @@ void pk_VM__ctor(pk_VM* self) { validate(tp_super, pk_VM__new_type(self, "super", tp_object, NULL, false)); validate(tp_exception, pk_VM__new_type(self, "Exception", tp_object, NULL, true)); - validate(tp_bytes, pk_VM__new_type(self, "bytes", tp_object, NULL, false)); + validate(tp_bytes, pk_bytes__register()); validate(tp_mappingproxy, pk_VM__new_type(self, "mappingproxy", tp_object, NULL, false)); validate(tp_dict, pk_VM__new_type(self, "dict", tp_object, NULL, true)); @@ -191,7 +195,7 @@ py_Type pk_VM__new_type(pk_VM* self, /****************************************/ void PyObject__delete(PyObject* self) { pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, self->type); - if(ti->dtor) ti->dtor(PyObject__value(self)); + if(ti->dtor) ti->dtor(PyObject__userdata(self)); if(self->slots == -1) pk_NameDict__dtor(PyObject__dict(self)); if(self->gc_is_large) { free(self); diff --git a/src/objects/object.c b/src/objects/object.c index 37dd801b..15365a3f 100644 --- a/src/objects/object.c +++ b/src/objects/object.c @@ -2,16 +2,14 @@ #include "pocketpy/pocketpy.h" #include -void* PyObject__value(PyObject* self){ - return (char*)self + PK_OBJ_HEADER_SIZE(self->slots); -} +void* PyObject__userdata(PyObject* self) { return self->flex + PK_OBJ_SLOTS_SIZE(self->slots); } -pk_NameDict* PyObject__dict(PyObject* self){ +pk_NameDict* PyObject__dict(PyObject* self) { assert(self->slots == -1); - return (pk_NameDict*)((char*)self + 8); + return (pk_NameDict*)(self->flex); } -py_TValue* PyObject__slots(PyObject* self){ +py_TValue* PyObject__slots(PyObject* self) { assert(self->slots >= 0); - return (py_TValue*)((char*)self + 8); + return (py_TValue*)(self->flex); } \ No newline at end of file diff --git a/src/public/cast.c b/src/public/cast.c index 3c38cc3b..a4972b49 100644 --- a/src/public/cast.c +++ b/src/public/cast.c @@ -1,3 +1,4 @@ +#include "pocketpy/common/str.h" #include "pocketpy/pocketpy.h" #include "pocketpy/common/utils.h" @@ -33,29 +34,9 @@ py_Type py_totype(const py_Ref self) { return *ud; } -const char* py_tostr(const py_Ref self) { - assert(self->type == tp_str); - c11_string* ud = PyObject__value(self->_obj); - return ud->data; -} - -const char* py_tostrn(const py_Ref self, int* size) { - assert(self->type == tp_str); - c11_string* ud = PyObject__value(self->_obj); - *size = ud->size; - return ud->data; -} - -const unsigned char* py_tobytes(const py_Ref self, int* size) { - assert(self->type == tp_bytes); - int* ud = PyObject__value(self->_obj); - *size = *ud; - return (unsigned char*)(ud + 1); -} - void* py_touserdata(const py_Ref self) { assert(self && self->is_ptr); - return PyObject__value(self->_obj); + return PyObject__userdata(self->_obj); } bool py_istype(const py_Ref self, py_Type type) { return self->type == type; } diff --git a/src/public/modules.c b/src/public/modules.c index fba0b1b2..9feefe37 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -4,19 +4,23 @@ #include "pocketpy/objects/object.h" #include "pocketpy/interpreter/vm.h" -py_Ref py_getmodule(const char *name){ +py_Ref py_getmodule(const char* name) { pk_VM* vm = pk_current_vm; return pk_NameDict__try_get(&vm->modules, py_name(name)); } -py_Ref py_newmodule(const char *name, const char *package){ +py_Ref py_newmodule(const char* name, const char* package) { pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_module, -1, 0); py_Ref r0 = py_pushtmp(); py_Ref r1 = py_pushtmp(); - *r0 = PyVar__fromobj(obj); + *r0 = (py_TValue){ + .type = obj->type, + .is_ptr = true, + ._obj = obj, + }; py_newstr(r1, name); py_setdict(r0, __name__, r1); @@ -27,7 +31,7 @@ py_Ref py_newmodule(const char *name, const char *package){ py_setdict(r0, __package__, r1); // convert to fullname - if(package[0] != '\0'){ + if(package[0] != '\0') { // package.name char buf[256]; snprintf(buf, sizeof(buf), "%s.%s", package, name); diff --git a/src/public/py_list.c b/src/public/py_list.c index ccc34e17..5c28db68 100644 --- a/src/public/py_list.c +++ b/src/public/py_list.c @@ -17,7 +17,7 @@ py_Type pk_list__register() { void py_newlist(py_Ref out) { pk_VM* vm = pk_current_vm; PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_list, 0, sizeof(List)); - List* userdata = PyObject__value(obj); + List* userdata = PyObject__userdata(obj); c11_vector__ctor(userdata, sizeof(py_TValue)); out->type = tp_list; out->is_ptr = true; diff --git a/src/public/py_str.c b/src/public/py_str.c new file mode 100644 index 00000000..07ddc4a3 --- /dev/null +++ b/src/public/py_str.c @@ -0,0 +1,68 @@ +#include "pocketpy/common/str.h" +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +py_Type pk_str__register() { + pk_VM* vm = pk_current_vm; + py_Type type = pk_VM__new_type(vm, "str", tp_object, NULL, false); + // no need to dtor because the memory is controlled by the object + return type; +} + +py_Type pk_bytes__register() { + pk_VM* vm = pk_current_vm; + py_Type type = pk_VM__new_type(vm, "bytes", tp_object, NULL, false); + // no need to dtor because the memory is controlled by the object + return type; +} + +void py_newstr(py_Ref out, const char* data) { + return py_newstrn(out, data, strlen(data)); +} + +void py_newstrn(py_Ref out, const char* data, int size) { + pk_ManagedHeap* heap = &pk_current_vm->heap; + int total_size = sizeof(c11_string) + size + 1; + PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, total_size); + c11_string* ud = PyObject__userdata(obj); + c11_string__ctor2(ud, data, size); + out->type = tp_str; + out->is_ptr = true; + out->_obj = obj; +} + +unsigned char* py_newbytes(py_Ref out, int size) { + pk_ManagedHeap* heap = &pk_current_vm->heap; + // 4 bytes size + data + PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(c11_bytes) + size); + c11_bytes* ud = PyObject__userdata(obj); + ud->size = size; + out->type = tp_bytes; + out->is_ptr = true; + out->_obj = obj; + return ud->data; +} + +const char* py_tostr(const py_Ref self) { + assert(self->type == tp_str); + c11_string* ud = PyObject__userdata(self->_obj); + return ud->data; +} + +const char* py_tostrn(const py_Ref self, int* size) { + assert(self->type == tp_str); + c11_string* ud = PyObject__userdata(self->_obj); + *size = ud->size; + return ud->data; +} + +unsigned char* py_tobytes(const py_Ref self, int* size) { + assert(self->type == tp_bytes); + c11_bytes* ud = PyObject__userdata(self->_obj); + *size = ud->size; + return ud->data; +} + diff --git a/src/public/values.c b/src/public/values.c index 621ae9ea..e6ac29da 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -1,3 +1,5 @@ +#include "pocketpy/common/str.h" +#include "pocketpy/common/vector.h" #include "pocketpy/pocketpy.h" #include "pocketpy/common/utils.h" @@ -37,35 +39,8 @@ void py_newellipsis(py_Ref out) { out->is_ptr = false; } - void py_newnull(py_Ref out) { out->type = 0; } -void py_newstr(py_Ref out, const char* data) { - return py_newstrn(out, data, strlen(data)); -} - -void py_newstrn(py_Ref out, const char* data, int size) { - pk_ManagedHeap* heap = &pk_current_vm->heap; - int total_size = sizeof(c11_string) + size + 1; - PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, total_size); - c11_string* ud = PyObject__value(obj); - c11_string__ctor2(ud, data, size); - out->type = tp_str; - out->is_ptr = true; - out->_obj = obj; -} - -void py_newbytes(py_Ref out, const unsigned char* data, int size) { - pk_ManagedHeap* heap = &pk_current_vm->heap; - // 4 bytes size + data - PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(int) + size); - int* psize = (int*)PyObject__value(obj); - *psize = size; - memcpy(psize + 1, data, size); - out->type = tp_bytes; - out->is_ptr = true; - out->_obj = obj; -} void py_newfunction(py_Ref out, py_CFunction f, const char* sig) { py_newfunction2(out, f, sig, BindType_FUNCTION, NULL, NULL);