This commit is contained in:
blueloveTH 2024-08-19 13:04:38 +08:00
parent f70d5af07f
commit aaf7a84a3a
13 changed files with 144 additions and 81 deletions

View File

@ -0,0 +1,36 @@
#pragma once
#include "pocketpy/pocketpy.h"
#include "pocketpy/objects/object.h"
typedef struct py_TypeInfo {
py_Name name;
py_Type base;
py_TValue self;
py_TValue module; // the module where the type is defined
bool is_python; // is it a python class? (not derived from c object)
bool is_sealed; // can it be subclassed?
void (*dtor)(void*);
py_TValue annotations; // type annotations
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
void (*gc_mark)(void* ud);
/* Magic Slots */
py_TValue magic[64];
} py_TypeInfo;
typedef struct TypeList {
int length;
py_TypeInfo* chunks[256];
} TypeList;
void TypeList__ctor(TypeList* self);
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);

View File

@ -5,6 +5,7 @@
#include "pocketpy/interpreter/heap.h"
#include "pocketpy/interpreter/frame.h"
#include "pocketpy/interpreter/modules.h"
#include "pocketpy/interpreter/typeinfo.h"
// TODO:
// 1. __eq__ and __ne__ fallbacks
@ -15,32 +16,11 @@
// 6. py_TypeInfo
// 7. Direct assignment of py_NIL, py_True, py_False, py_None. They are slow.
typedef struct py_TypeInfo {
py_Name name;
py_Type base;
py_TValue self;
py_TValue module; // the module where the type is defined
bool is_python; // is it a python class? (not derived from c object)
bool is_sealed; // can it be subclassed?
void (*dtor)(void*);
py_TValue annotations; // type annotations
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
void (*gc_mark)(void* ud);
/* Magic Slots */
py_TValue magic[64];
} py_TypeInfo;
typedef struct VM {
Frame* top_frame;
ModuleDict modules;
c11_vector /*T=py_TypeInfo*/ types;
TypeList types;
py_TValue builtins; // builtins module
py_TValue main; // __main__ module
@ -74,6 +54,7 @@ void pk__mark_value(py_TValue*);
void pk__mark_namedict(NameDict*);
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*));
bool pk__object_new(int argc, py_Ref argv);
py_TypeInfo* pk__type_info(py_Type type);
bool pk_wrapper__self(int argc, py_Ref argv);
bool pk_wrapper__NotImplementedError(int argc, py_Ref argv);

View File

@ -250,18 +250,18 @@ PK_EXPORT bool py_isinstance(py_Ref obj, py_Type type);
/// Check if the derived type is a subclass of the base type.
PK_EXPORT 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_EXPORT 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_EXPORT py_ItemRef py_tpfindmagic(py_Type, py_Name name);
PK_EXPORT py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
/// Search the name from the given type to the base type.
/// Return `NULL` if not found.
PK_EXPORT py_ItemRef py_tpfindname(py_Type, py_Name name);
/// Get the magic method from the given type only.
/// The returned reference is always valid. However, its value may be `nil`.
PK_EXPORT py_ItemRef py_tpgetmagic(py_Type type, py_Name name);
/// Get the type object of the given type.
PK_EXPORT py_ItemRef py_tpobject(py_Type type);
PK_EXPORT py_GlobalRef py_tpobject(py_Type type);
/// Get the type name.
PK_EXPORT const char* py_tpname(py_Type type);
/// Call a type to create a new instance.

View File

@ -871,7 +871,7 @@ FrameResult VM__run_top_frame(VM* self) {
}
POP();
py_TypeInfo* base_ti = c11__at(py_TypeInfo, &self->types, base);
py_TypeInfo* base_ti = TypeList__get(&self->types, base);
if(base_ti->is_sealed) {
TypeError("type '%t' is not an acceptable base type", base);
goto __ERROR;
@ -892,9 +892,9 @@ FrameResult VM__run_top_frame(VM* self) {
if(py_istype(TOP(), tp_type)) {
// call on_end_subclass
py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, py_totype(TOP()));
py_TypeInfo* ti = TypeList__get(&self->types, py_totype(TOP()));
if(ti->base != tp_object) {
py_TypeInfo* base_ti = c11__at(py_TypeInfo, &self->types, ti->base);
py_TypeInfo* base_ti = TypeList__get(&self->types, ti->base);
if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
}
}
@ -915,7 +915,7 @@ FrameResult VM__run_top_frame(VM* self) {
case OP_ADD_CLASS_ANNOTATION: {
// [type_hint string]
py_Type type = py_totype(self->__curr_class);
py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, type);
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());
if(!ok) goto __ERROR;

View File

@ -0,0 +1,44 @@
#include "pocketpy/interpreter/typeinfo.h"
#define CHUNK_SIZE 128
#define LOG2_CHUNK_SIZE 7
static py_TypeInfo firstChunk[CHUNK_SIZE];
void TypeList__ctor(TypeList* self) {
self->length = 0;
memset(self->chunks, 0, sizeof(self->chunks));
self->chunks[0] = firstChunk;
}
void TypeList__dtor(TypeList* self) {
for (int i = 1; i < self->length; i++) {
if(self->chunks[i]) free(self->chunks[i]);
}
}
py_TypeInfo* TypeList__get(TypeList* self, py_Type index) {
assert(index < self->length);
int chunk = index >> LOG2_CHUNK_SIZE;
int offset = index & (CHUNK_SIZE - 1);
return self->chunks[chunk] + offset;
}
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){
self->chunks[chunk] = malloc(sizeof(py_TypeInfo) * CHUNK_SIZE);
memset(self->chunks[chunk], 0, sizeof(py_TypeInfo) * CHUNK_SIZE);
}
self->length++;
return self->chunks[chunk] + offset;
}
void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx) {
for (int i = 0; i < self->length; i++) {
py_TypeInfo* info = TypeList__get(self, i);
f(info, ctx);
}
}

View File

@ -4,6 +4,7 @@
#include "pocketpy/common/utils.h"
#include "pocketpy/interpreter/generator.h"
#include "pocketpy/interpreter/modules.h"
#include "pocketpy/interpreter/typeinfo.h"
#include "pocketpy/objects/base.h"
#include "pocketpy/common/_generated.h"
#include "pocketpy/pocketpy.h"
@ -56,7 +57,7 @@ void VM__ctor(VM* self) {
self->top_frame = NULL;
ModuleDict__ctor(&self->modules, NULL, *py_NIL);
c11_vector__ctor(&self->types, sizeof(py_TypeInfo));
TypeList__ctor(&self->types);
self->builtins = *py_NIL;
self->main = *py_NIL;
@ -76,7 +77,7 @@ void VM__ctor(VM* self) {
/* Init Builtin Types */
// 0: unused
void* placeholder = c11_vector__emplace(&self->types);
void* placeholder = TypeList__emplace(&self->types);
memset(placeholder, 0, sizeof(py_TypeInfo));
#define validate(t, expr) \
@ -187,7 +188,7 @@ void VM__ctor(VM* self) {
};
for(int i = 0; i < c11__count_array(public_types); i++) {
py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, public_types[i]);
py_TypeInfo* ti = pk__type_info(public_types[i]);
py_setdict(&self->builtins, ti->name, &ti->self);
}
@ -228,7 +229,7 @@ void VM__dtor(VM* self) {
while(self->top_frame)
VM__pop_frame(self);
ModuleDict__dtor(&self->modules);
c11_vector__dtor(&self->types);
TypeList__dtor(&self->types);
ValueStack__clear(&self->stack);
}
@ -316,10 +317,9 @@ py_Type pk_newtype(const char* name,
void (*dtor)(void*),
bool is_python,
bool is_sealed) {
c11_vector* types = &pk_current_vm->types;
py_Type index = types->length;
py_TypeInfo* ti = c11_vector__emplace(types);
py_TypeInfo* base_ti = base ? c11__at(py_TypeInfo, types, base) : NULL;
py_Type index = pk_current_vm->types.length;
py_TypeInfo* ti = TypeList__emplace(&pk_current_vm->types);
py_TypeInfo* base_ti = base ? pk__type_info(base) : NULL;
if(base_ti && base_ti->is_sealed) {
c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name));
}
@ -540,7 +540,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
/****************************************/
void PyObject__delete(PyObject* self) {
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, self->type);
py_TypeInfo* ti = pk__type_info(self->type);
if(ti->dtor) ti->dtor(PyObject__userdata(self));
if(self->slots == -1) NameDict__dtor(PyObject__dict(self));
if(self->gc_is_large) {
@ -564,7 +564,7 @@ void pk__mark_namedict(NameDict* dict) {
}
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*)) {
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
py_TypeInfo* ti = pk__type_info(type);
assert(ti->gc_mark == NULL);
ti->gc_mark = gc_mark;
}
@ -582,8 +582,8 @@ static void mark_object(PyObject* obj) {
pk__mark_namedict(dict);
}
py_TypeInfo* types = c11__at(py_TypeInfo, &pk_current_vm->types, obj->type);
if(types->gc_mark) types->gc_mark(PyObject__userdata(obj));
py_TypeInfo* ti = pk__type_info(obj->type);
if(ti->gc_mark) ti->gc_mark(PyObject__userdata(obj));
}
void CodeObject__gc_mark(const CodeObject* self) {
@ -603,18 +603,18 @@ void ManagedHeap__mark(ManagedHeap* self) {
pk__mark_value(p);
}
// mark types
py_TypeInfo* types = vm->types.data;
int types_length = vm->types.length;
// 0-th type is placeholder
for(int i = 1; i < types_length; i++) {
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 = types[i].magic + j;
py_TValue* slot = ti->magic + j;
if(py_isnil(slot)) continue;
pk__mark_value(slot);
}
// mark type annotations
pk__mark_value(&types[i].annotations);
pk__mark_value(&ti->annotations);
}
// mark frame
for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) {
@ -696,3 +696,7 @@ bool pk_wrapper__self(int argc, py_Ref argv) {
bool pk_wrapper__NotImplementedError(int argc, py_Ref argv) {
return py_exception(tp_NotImplementedError, "");
}
py_TypeInfo* pk__type_info(py_Type type) {
return TypeList__get(&pk_current_vm->types, type);
}

View File

@ -86,6 +86,6 @@ void pk__add_module_enum() {
py_bindproperty(type, "name", Enum__name, NULL);
py_bindproperty(type, "value", Enum__value, NULL);
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
py_TypeInfo* ti = pk__type_info(type);
ti->on_end_subclass = Enum__on_end_subclass;
}

View File

@ -1,4 +1,5 @@
#include "pocketpy/common/str.h"
#include "pocketpy/objects/base.h"
#include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h"
@ -49,10 +50,10 @@ bool py_checktype(py_Ref self, py_Type type) {
bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); }
bool py_issubclass(py_Type derived, py_Type base) {
py_TypeInfo* types = pk_current_vm->types.data;
TypeList* types = &pk_current_vm->types;
do {
if(derived == base) return true;
derived = types[derived].base;
derived = TypeList__get(types, derived)->base;
} while(derived);
return false;
}

View File

@ -1,3 +1,4 @@
#include "pocketpy/interpreter/typeinfo.h"
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/sourcedata.h"
#include "pocketpy/pocketpy.h"
@ -178,7 +179,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
break;
case tp_classmethod:
self[0] = *py_getslot(cls_var, 0);
self[1] = c11__getitem(py_TypeInfo, &pk_current_vm->types, type).self;
self[1] = pk__type_info(type)->self;
break;
default: c11__unreachedable();
}
@ -189,41 +190,40 @@ 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* types = (py_TypeInfo*)pk_current_vm->types.data;
TypeList* types = &pk_current_vm->types;
do {
py_Ref f = &types[t].magic[name];
py_TypeInfo* ti = TypeList__get(types, t);
py_Ref f = &ti->magic[name];
if(!py_isnil(f)) return f;
t = types[t].base;
t = ti->base;
} while(t);
return NULL;
}
py_Ref py_tpfindname(py_Type t, py_Name name) {
py_TypeInfo* types = (py_TypeInfo*)pk_current_vm->types.data;
TypeList* types = &pk_current_vm->types;
do {
py_Ref res = py_getdict(&types[t].self, name);
py_TypeInfo* ti = TypeList__get(types, t);
py_Ref res = py_getdict(&ti->self, name);
if(res) return res;
t = types[t].base;
t = ti->base;
} while(t);
return NULL;
}
py_Ref py_tpgetmagic(py_Type type, py_Name name) {
assert(py_ismagicname(name));
VM* vm = pk_current_vm;
return &c11__at(py_TypeInfo, &vm->types, type)->magic[name];
return pk__type_info(type)->magic + name;
}
py_Ref py_tpobject(py_Type type) {
assert(type);
VM* vm = pk_current_vm;
return &c11__at(py_TypeInfo, &vm->types, type)->self;
return &pk__type_info(type)->self;
}
const char* py_tpname(py_Type type) {
if(!type) return "nil";
VM* vm = pk_current_vm;
py_Name name = c11__at(py_TypeInfo, &vm->types, type)->name;
py_Name name = pk__type_info(type)->name;
return py_name2str(name);
}

View File

@ -675,8 +675,7 @@ static bool super__new__(int argc, py_Ref argv) {
return TypeError("super() takes 0 or 2 arguments");
}
py_TypeInfo* types = pk_current_vm->types.data;
*class_arg = types[*class_arg].base;
*class_arg = pk__type_info(*class_arg)->base;
if(*class_arg == 0) return RuntimeError("super(): base class is invalid");
py_setslot(py_retval(), 0, self_arg);

View File

@ -5,7 +5,7 @@
bool pk__object_new(int argc, py_Ref argv) {
if(argc == 0) return TypeError("object.__new__(): not enough arguments");
py_Type cls = py_totype(py_arg(0));
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, cls);
py_TypeInfo* ti = pk__type_info(cls);
if(!ti->is_python) {
return TypeError("object.__new__(%t) is not safe, use %t.__new__()", cls, cls);
}
@ -72,8 +72,7 @@ static bool type__new__(int argc, py_Ref argv) {
static bool type__base__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_Type type = py_totype(argv);
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
py_TypeInfo* ti = pk__type_info(py_totype(argv));
if(ti->base) {
py_assign(py_retval(), py_tpobject(ti->base));
} else {
@ -84,8 +83,7 @@ static bool type__base__(int argc, py_Ref argv) {
static bool type__name__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_Type type = py_totype(argv);
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
py_TypeInfo* ti = pk__type_info(py_totype(argv));
py_newstr(py_retval(), py_name2str(ti->name));
return true;
}
@ -97,8 +95,7 @@ static bool type__getitem__(int argc, py_Ref argv) {
static bool type__module__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_Type type = py_totype(argv);
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
py_TypeInfo* ti = pk__type_info(py_totype(argv));
if(py_isnil(&ti->module)) {
py_newnone(py_retval());
} else {
@ -110,8 +107,7 @@ static bool type__module__(int argc, py_Ref argv) {
static bool type__annotations__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_Type type = py_totype(argv);
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
py_TypeInfo* ti = pk__type_info(py_totype(argv));
if(py_isnil(&ti->annotations)) {
py_newdict(py_retval());
} else {

View File

@ -1,3 +1,4 @@
#include "pocketpy/interpreter/typeinfo.h"
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/objects/base.h"
#include "pocketpy/pocketpy.h"
@ -45,11 +46,12 @@ int py_bool(py_Ref val) {
bool py_hash(py_Ref val, int64_t* out) {
py_Type t = val->type;
py_TypeInfo* types = (py_TypeInfo*)pk_current_vm->types.data;
TypeList* types = &pk_current_vm->types;
do {
py_Ref _hash = &types[t].magic[__hash__];
py_TypeInfo* ti = TypeList__get(types, t);
py_Ref _hash = &ti->magic[__hash__];
if(py_isnone(_hash)) break;
py_Ref _eq = &types[t].magic[__eq__];
py_Ref _eq = &ti->magic[__eq__];
if(!py_isnil(_eq)) {
if(py_isnil(_hash)) break;
if(!py_call(_hash, 1, val)) return false;
@ -57,7 +59,7 @@ bool py_hash(py_Ref val, int64_t* out) {
*out = py_toint(py_retval());
return true;
}
t = types[t].base;
t = ti->base;
} while(t);
return TypeError("unhashable type: '%t'", val->type);
}