Commit 0eb28782 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Starting to add traverse and clear functions

parent 99ff28d1
...@@ -382,6 +382,13 @@ subtract_refs(PyGC_Head *containers) ...@@ -382,6 +382,13 @@ subtract_refs(PyGC_Head *containers)
PyGC_Head *gc = containers->gc.gc_next; PyGC_Head *gc = containers->gc.gc_next;
for (; gc != containers; gc=gc->gc.gc_next) { for (; gc != containers; gc=gc->gc.gc_next) {
traverse = Py_TYPE(FROM_GC(gc))->tp_traverse; traverse = Py_TYPE(FROM_GC(gc))->tp_traverse;
// Pyston addition: some extra checking for our transition
#ifndef NDEBUG
if (!traverse) {
fprintf(stderr, "%s needs a tp_traverse\n", Py_TYPE(FROM_GC(gc))->tp_name);
assert(0);
}
#endif
(void) traverse(FROM_GC(gc), (void) traverse(FROM_GC(gc),
(visitproc)visit_decref, (visitproc)visit_decref,
NULL); NULL);
......
...@@ -62,6 +62,32 @@ public: ...@@ -62,6 +62,32 @@ public:
return boxString(s); return boxString(s);
return None; return None;
} }
static void dealloc(Box* _o) noexcept {
BoxedCApiFunction* o = (BoxedCApiFunction*)_o;
_PyObject_GC_UNTRACK(o);
Py_XDECREF(o->module);
Py_XDECREF(o->passthrough);
o->cls->tp_free(o);
}
static int traverse(Box* _o, visitproc visit, void* arg) noexcept {
BoxedCApiFunction* o = (BoxedCApiFunction*)_o;
Py_VISIT(o->module);
Py_VISIT(o->passthrough);
return 0;
}
static int clear(Box* _o) noexcept {
BoxedCApiFunction* o = (BoxedCApiFunction*)_o;
Py_CLEAR(o->module);
Py_CLEAR(o->passthrough);
return 0;
}
}; };
static_assert(sizeof(BoxedCApiFunction) == sizeof(PyCFunctionObject), ""); static_assert(sizeof(BoxedCApiFunction) == sizeof(PyCFunctionObject), "");
static_assert(offsetof(BoxedCApiFunction, method_def) == offsetof(PyCFunctionObject, m_ml), ""); static_assert(offsetof(BoxedCApiFunction, method_def) == offsetof(PyCFunctionObject, m_ml), "");
......
...@@ -590,11 +590,25 @@ public: ...@@ -590,11 +590,25 @@ public:
AttrList* attr_list; AttrList* attr_list;
HCAttrs(HiddenClass* hcls = root_hcls) : hcls(hcls), attr_list(nullptr) {} HCAttrs(HiddenClass* hcls = root_hcls) : hcls(hcls), attr_list(nullptr) {}
int traverse(visitproc visit, void* arg) noexcept;
}; };
static_assert(sizeof(HCAttrs) == sizeof(struct _hcattrs), ""); static_assert(sizeof(HCAttrs) == sizeof(struct _hcattrs), "");
#define Py_VISIT_HCATTRS(hcattrs) \
do { \
int vret = hcattrs.traverse(visit, arg); \
if (vret) \
return vret; \
} while (0)
extern std::vector<BoxedClass*> classes; extern std::vector<BoxedClass*> classes;
// Debugging helper: pass this as a tp_clear function to say that you have explicitly verified
// that you don't need a tp_clear (as opposed to haven't added one yet)
#define NOCLEAR ((inquiry)-1)
class BoxedDict; class BoxedDict;
class BoxedString; class BoxedString;
......
...@@ -712,7 +712,8 @@ void setupSys() { ...@@ -712,7 +712,8 @@ void setupSys() {
sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX)); sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX));
sys_module->giveAttr("maxsize", boxInt(PY_SSIZE_T_MAX)); sys_module->giveAttr("maxsize", boxInt(PY_SSIZE_T_MAX));
sys_flags_cls = BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedSysFlags), false, "flags"); sys_flags_cls
= BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedSysFlags), false, "flags", NULL, NULL, false);
sys_flags_cls->giveAttr( sys_flags_cls->giveAttr(
"__new__", new BoxedFunction(FunctionMetadata::create((void*)BoxedSysFlags::__new__, UNKNOWN, 1, true, true))); "__new__", new BoxedFunction(FunctionMetadata::create((void*)BoxedSysFlags::__new__, UNKNOWN, 1, true, true)));
sys_flags_cls->tp_dealloc = (destructor)BoxedSysFlags::dealloc; sys_flags_cls->tp_dealloc = (destructor)BoxedSysFlags::dealloc;
......
...@@ -430,6 +430,38 @@ Box* BoxedMethodDescriptor::descr_get(BoxedMethodDescriptor* self, Box* inst, Bo ...@@ -430,6 +430,38 @@ Box* BoxedMethodDescriptor::descr_get(BoxedMethodDescriptor* self, Box* inst, Bo
return boxInstanceMethod(inst, self, self->type); return boxInstanceMethod(inst, self, self->type);
} }
void BoxedMethodDescriptor::dealloc(Box* _self) noexcept {
BoxedMethodDescriptor* self = static_cast<BoxedMethodDescriptor*>(_self);
PyObject_GC_UnTrack(self);
Py_XDECREF(self->type);
self->cls->tp_free(self);
}
int BoxedMethodDescriptor::traverse(Box* _self, visitproc visit, void *arg) noexcept {
BoxedMethodDescriptor* self = static_cast<BoxedMethodDescriptor*>(_self);
Py_VISIT(self->type);
return 0;
}
void BoxedWrapperObject::dealloc(Box* _self) noexcept {
BoxedWrapperObject* self = static_cast<BoxedWrapperObject*>(_self);
PyObject_GC_UnTrack(self);
Py_XDECREF(self->obj);
Py_XDECREF(self->descr);
self->cls->tp_free(self);
}
int BoxedWrapperObject::traverse(Box* _self, visitproc visit, void *arg) noexcept {
BoxedWrapperObject* self = static_cast<BoxedWrapperObject*>(_self);
Py_VISIT(self->obj);
Py_VISIT(self->descr);
return 0;
}
Box* BoxedWrapperDescriptor::descr_get(Box* _self, Box* inst, Box* owner) noexcept { Box* BoxedWrapperDescriptor::descr_get(Box* _self, Box* inst, Box* owner) noexcept {
STAT_TIMER(t0, "us_timer_boxedwrapperdescriptor_descr_get", 20); STAT_TIMER(t0, "us_timer_boxedwrapperdescriptor_descr_get", 20);
......
...@@ -763,6 +763,23 @@ void BoxedDict::dealloc(Box* b) noexcept { ...@@ -763,6 +763,23 @@ void BoxedDict::dealloc(Box* b) noexcept {
static_cast<BoxedDict*>(b)->d.freeAllMemory(); static_cast<BoxedDict*>(b)->d.freeAllMemory();
} }
int BoxedDict::traverse(PyObject* op, visitproc visit, void* arg) noexcept {
Py_ssize_t i = 0;
PyObject* pk;
PyObject* pv;
while (PyDict_Next(op, &i, &pk, &pv)) {
Py_VISIT(pk);
Py_VISIT(pv);
}
return 0;
}
int BoxedDict::clear(PyObject* op) noexcept {
PyDict_Clear(op);
return 0;
}
extern "C" void _PyDict_MaybeUntrack(PyObject* op) noexcept { extern "C" void _PyDict_MaybeUntrack(PyObject* op) noexcept {
PyDictObject* mp; PyDictObject* mp;
PyObject* value; PyObject* value;
......
...@@ -1258,6 +1258,63 @@ extern "C" int PyList_SetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, P ...@@ -1258,6 +1258,63 @@ extern "C" int PyList_SetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, P
} }
} }
void BoxedList::dealloc(Box* b) noexcept {
BoxedList* op = static_cast<BoxedList*>(b);
Py_ssize_t i;
PyObject_GC_UnTrack(op);
Py_TRASHCAN_SAFE_BEGIN(op)
if (op->elts != NULL) {
/* Do it backwards, for Christian Tismer.
There's a simple test case where somehow this reduces
thrashing when a *very* large list is created and
immediately deleted. */
i = Py_SIZE(op);
while (--i >= 0) {
Py_XDECREF(op->elts->elts[i]);
}
//PyMem_FREE(op->elts);
}
#if 0
if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
free_list[numfree++] = op;
else
#endif
Py_TYPE(op)->tp_free((PyObject*)op);
Py_TRASHCAN_SAFE_END(op)
}
int BoxedList::traverse(Box* _o, visitproc visit, void* arg) noexcept {
PyListObject* o = (PyListObject*)_o;
Py_ssize_t i;
for (i = Py_SIZE(o); --i >= 0; )
Py_VISIT(o->ob_item[i]);
return 0;
}
int BoxedList::clear(Box* _a) noexcept {
PyListObject* a = (PyListObject*)_a;
Py_ssize_t i;
PyObject **item = a->ob_item;
if (item != NULL) {
/* Because XDECREF can recursively invoke operations on
this list, we make it empty first. */
i = Py_SIZE(a);
Py_SIZE(a) = 0;
a->ob_item = NULL;
a->allocated = 0;
while (--i >= 0) {
Py_XDECREF(item[i]);
}
PyMem_FREE(item);
}
/* Never fails; the return value can be ignored.
Note that there is no guarantee that the list is actually empty
at this point, because XDECREF may have populated it again! */
return 0;
}
void setupList() { void setupList() {
static PySequenceMethods list_as_sequence; static PySequenceMethods list_as_sequence;
list_cls->tp_as_sequence = &list_as_sequence; list_cls->tp_as_sequence = &list_as_sequence;
......
...@@ -400,7 +400,8 @@ void BoxedClass::freeze() { ...@@ -400,7 +400,8 @@ void BoxedClass::freeze() {
std::vector<BoxedClass*> classes; std::vector<BoxedClass*> classes;
BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset, int instance_size, bool is_user_defined, BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset, int instance_size, bool is_user_defined,
const char* name, destructor dealloc, freefunc free, bool is_gc) const char* name, destructor dealloc, freefunc free, bool is_gc, traverseproc traverse,
inquiry clear)
: attrs(HiddenClass::makeSingleton()), : attrs(HiddenClass::makeSingleton()),
attrs_offset(attrs_offset), attrs_offset(attrs_offset),
is_constant(false), is_constant(false),
...@@ -410,6 +411,15 @@ BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset, ...@@ -410,6 +411,15 @@ BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset,
has_instancecheck(false), has_instancecheck(false),
tpp_call(NULL, NULL) { tpp_call(NULL, NULL) {
bool ok_noclear = (clear == NOCLEAR);
if (ok_noclear)
clear = NULL;
if (is_gc) {
ASSERT(traverse, "%s", name);
ASSERT(dealloc, "%s", name);
}
ASSERT(((bool)traverse == (bool)clear) || ok_noclear, "%s", name);
classes.push_back(this); classes.push_back(this);
// Zero out the CPython tp_* slots: // Zero out the CPython tp_* slots:
...@@ -453,6 +463,22 @@ BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset, ...@@ -453,6 +463,22 @@ BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset,
assert(cls == type_cls || PyType_Check(this)); assert(cls == type_cls || PyType_Check(this));
} }
tp_traverse = traverse;
tp_clear = clear;
if (base && !PyType_IS_GC(this) & PyType_IS_GC(base) && !traverse && !tp_clear) {
assert(tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE);
tp_flags |= Py_TPFLAGS_HAVE_GC;
assert(tp_free != PyObject_Del);
if (!tp_traverse)
tp_traverse = base->tp_traverse;
if (!tp_clear)
tp_clear = base->tp_clear;
}
ASSERT((bool)tp_traverse == PyType_IS_GC(this), "%s missing traverse", tp_name);
ASSERT(((bool)tp_clear == PyType_IS_GC(this)) || ok_noclear, "%s missing clear", tp_name);
if (dealloc) if (dealloc)
tp_dealloc = dealloc; tp_dealloc = dealloc;
else { else {
...@@ -470,9 +496,6 @@ BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset, ...@@ -470,9 +496,6 @@ BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset,
this->tp_free = PyObject_GC_Del; this->tp_free = PyObject_GC_Del;
} }
if (PyType_IS_GC(this))
assert(tp_free != PyObject_Del);
assert(tp_dealloc); assert(tp_dealloc);
assert(tp_free); assert(tp_free);
...@@ -500,10 +523,10 @@ BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset, ...@@ -500,10 +523,10 @@ BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset,
BoxedClass* BoxedClass::create(BoxedClass* metaclass, BoxedClass* base, int attrs_offset, int weaklist_offset, BoxedClass* BoxedClass::create(BoxedClass* metaclass, BoxedClass* base, int attrs_offset, int weaklist_offset,
int instance_size, bool is_user_defined, const char* name, destructor dealloc, int instance_size, bool is_user_defined, const char* name, destructor dealloc,
freefunc free, bool is_gc) { freefunc free, bool is_gc, traverseproc traverse, inquiry clear) {
assert(!is_user_defined); assert(!is_user_defined);
BoxedClass* made = new (metaclass, 0) BoxedClass* made = new (metaclass, 0) BoxedClass(base, attrs_offset, weaklist_offset, instance_size,
BoxedClass(base, attrs_offset, weaklist_offset, instance_size, is_user_defined, name, dealloc, free, is_gc); is_user_defined, name, dealloc, free, is_gc, traverse, clear);
// While it might be ok if these were set, it'd indicate a difference in // While it might be ok if these were set, it'd indicate a difference in
// expectations as to who was going to calculate them: // expectations as to who was going to calculate them:
...@@ -518,13 +541,6 @@ BoxedClass* BoxedClass::create(BoxedClass* metaclass, BoxedClass* base, int attr ...@@ -518,13 +541,6 @@ BoxedClass* BoxedClass::create(BoxedClass* metaclass, BoxedClass* base, int attr
} }
void BoxedClass::finishInitialization() { void BoxedClass::finishInitialization() {
assert(!tp_traverse);
assert(!tp_clear);
if (tp_base) {
tp_traverse = tp_base->tp_traverse;
tp_clear = tp_base->tp_clear;
}
assert(!this->tp_dict); assert(!this->tp_dict);
this->tp_dict = incref(this->getAttrWrapper()); this->tp_dict = incref(this->getAttrWrapper());
......
...@@ -403,6 +403,32 @@ static void functionDtor(Box* b) { ...@@ -403,6 +403,32 @@ static void functionDtor(Box* b) {
Py_XDECREF(self->defaults); Py_XDECREF(self->defaults);
} }
static int func_traverse(BoxedFunction* f, visitproc visit, void* arg) noexcept {
//Py_VISIT(f->func_code);
Py_VISIT(f->globals);
Py_VISIT(f->modname);
Py_VISIT(f->defaults);
Py_VISIT(f->doc);
Py_VISIT(f->name);
Py_VISIT(f->closure);
//Py_VISIT(f->func_dict);
Py_VISIT_HCATTRS(f->attrs);
return 0;
}
static int builtin_func_traverse(BoxedBuiltinFunctionOrMethod* f, visitproc visit, void* arg) noexcept {
//Py_VISIT(f->func_code);
Py_VISIT(f->globals);
Py_VISIT(f->modname);
Py_VISIT(f->defaults);
Py_VISIT(f->doc);
Py_VISIT(f->name);
Py_VISIT(f->closure);
return 0;
}
std::string BoxedModule::name() { std::string BoxedModule::name() {
static BoxedString* name_str = internStringImmortal("__name__"); static BoxedString* name_str = internStringImmortal("__name__");
Box* name = this->getattr(name_str); Box* name = this->getattr(name_str);
...@@ -2441,6 +2467,16 @@ public: ...@@ -2441,6 +2467,16 @@ public:
static Box* ne(Box* _self, Box* _other) { return eq(_self, _other) == True ? False : True; } static Box* ne(Box* _self, Box* _other) { return eq(_self, _other) == True ? False : True; }
static void tp_dealloc(Box* self) noexcept {
Py_FatalError("unimplemented");
}
static int tp_traverse(Box* self, visitproc visit, void *arg) noexcept {
Py_FatalError("unimplemented");
}
static int tp_clear(Box* self) noexcept {
Py_FatalError("unimplemented");
}
friend class AttrWrapperIter; friend class AttrWrapperIter;
}; };
...@@ -3330,9 +3366,37 @@ done: ...@@ -3330,9 +3366,37 @@ done:
Py_TRASHCAN_SAFE_END(op) Py_TRASHCAN_SAFE_END(op)
} }
static int
tupletraverse(PyTupleObject *o, visitproc visit, void *arg)
{
Py_ssize_t i;
for (i = Py_SIZE(o); --i >= 0; )
Py_VISIT(o->ob_item[i]);
return 0;
}
void BoxedModule::dealloc(Box* b) noexcept { void BoxedModule::dealloc(Box* b) noexcept {
BoxedModule* self = static_cast<BoxedModule*>(b); BoxedModule* self = static_cast<BoxedModule*>(b);
self->clearAttrs(); self->clearAttrs();
b->cls->tp_free(b);
}
void BoxedSlice::dealloc(Box* b) noexcept {
BoxedSlice* self = static_cast<BoxedSlice*>(b);
Py_DECREF(self->step);
Py_DECREF(self->start);
Py_DECREF(self->stop);
PyObject_Del(b);
}
int BoxedModule::traverse(Box* _m, visitproc visit, void* arg) noexcept {
BoxedModule* m = static_cast<BoxedModule*>(_m);
Py_VISIT_HCATTRS(m->attrs);
return 0;
} }
void BoxedInstanceMethod::dealloc(Box* b) noexcept { void BoxedInstanceMethod::dealloc(Box* b) noexcept {
...@@ -3361,30 +3425,12 @@ void BoxedInstanceMethod::dealloc(Box* b) noexcept { ...@@ -3361,30 +3425,12 @@ void BoxedInstanceMethod::dealloc(Box* b) noexcept {
#endif #endif
} }
void BoxedList::dealloc(Box* b) noexcept { int BoxedInstanceMethod::traverse(Box* _im, visitproc visit, void* arg) noexcept {
BoxedList* op = static_cast<BoxedList*>(b); BoxedInstanceMethod* im = static_cast<BoxedInstanceMethod*>(_im);
Py_VISIT(im->func);
Py_ssize_t i; Py_VISIT(im->obj);
PyObject_GC_UnTrack(op); Py_VISIT(im->im_class);
Py_TRASHCAN_SAFE_BEGIN(op) return 0;
if (op->elts != NULL) {
/* Do it backwards, for Christian Tismer.
There's a simple test case where somehow this reduces
thrashing when a *very* large list is created and
immediately deleted. */
i = Py_SIZE(op);
while (--i >= 0) {
Py_XDECREF(op->elts->elts[i]);
}
//PyMem_FREE(op->elts);
}
#if 0
if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
free_list[numfree++] = op;
else
#endif
Py_TYPE(op)->tp_free((PyObject*)op);
Py_TRASHCAN_SAFE_END(op)
} }
void BoxedClass::dealloc(Box* b) noexcept { void BoxedClass::dealloc(Box* b) noexcept {
...@@ -3423,6 +3469,71 @@ static void object_dealloc(PyObject* self) { ...@@ -3423,6 +3469,71 @@ static void object_dealloc(PyObject* self) {
Py_TYPE(self)->tp_free(self); Py_TYPE(self)->tp_free(self);
} }
static int
type_traverse(PyTypeObject *type, visitproc visit, void *arg)
{
/* Because of type_is_gc(), the collector only calls this
for heaptypes. */
assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
Py_VISIT(type->tp_dict);
Py_VISIT(type->tp_cache);
Py_VISIT(type->tp_mro);
Py_VISIT(type->tp_bases);
Py_VISIT(type->tp_base);
/* There's no need to visit type->tp_subclasses or
((PyHeapTypeObject *)type)->ht_slots, because they can't be involved
in cycles; tp_subclasses is a list of weak references,
and slots is a tuple of strings. */
return 0;
}
static int
type_clear(PyTypeObject *type)
{
/* Because of type_is_gc(), the collector only calls this
for heaptypes. */
assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
/* We need to invalidate the method cache carefully before clearing
the dict, so that other objects caught in a reference cycle
don't start calling destroyed methods.
Otherwise, the only field we need to clear is tp_mro, which is
part of a hard cycle (its first element is the class itself) that
won't be broken otherwise (it's a tuple and tuples don't have a
tp_clear handler). None of the other fields need to be
cleared, and here's why:
tp_cache:
Not used; if it were, it would be a dict.
tp_bases, tp_base:
If these are involved in a cycle, there must be at least
one other, mutable object in the cycle, e.g. a base
class's dict; the cycle will be broken that way.
tp_subclasses:
A list of weak references can't be part of a cycle; and
lists have their own tp_clear.
slots (in PyHeapTypeObject):
A tuple of strings can't be part of a cycle.
*/
PyType_Modified(type);
if (type->tp_dict)
PyDict_Clear(type->tp_dict);
Py_CLEAR(type->tp_mro);
return 0;
}
int HCAttrs::traverse(visitproc visit, void* arg) noexcept {
Py_FatalError("unimplemented");
}
#ifndef Py_REF_DEBUG #ifndef Py_REF_DEBUG
#define PRINT_TOTAL_REFS() #define PRINT_TOTAL_REFS()
...@@ -3450,7 +3561,8 @@ void setupRuntime() { ...@@ -3450,7 +3561,8 @@ void setupRuntime() {
PyObject_INIT(type_cls, type_cls); PyObject_INIT(type_cls, type_cls);
::new (object_cls) BoxedClass(NULL, 0, 0, sizeof(Box), false, "object", object_dealloc, PyObject_Del, /* is_gc */ false); ::new (object_cls) BoxedClass(NULL, 0, 0, sizeof(Box), false, "object", object_dealloc, PyObject_Del, /* is_gc */ false);
::new (type_cls) BoxedClass(object_cls, offsetof(BoxedClass, attrs), offsetof(BoxedClass, tp_weaklist), ::new (type_cls) BoxedClass(object_cls, offsetof(BoxedClass, attrs), offsetof(BoxedClass, tp_weaklist),
sizeof(BoxedHeapClass), false, "type", BoxedClass::dealloc, PyObject_GC_Del); sizeof(BoxedHeapClass), false, "type", BoxedClass::dealloc, PyObject_GC_Del, true,
(traverseproc)type_traverse, (inquiry)type_clear);
type_cls->has_safe_tp_dealloc = false; type_cls->has_safe_tp_dealloc = false;
type_cls->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS; type_cls->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS;
...@@ -3495,24 +3607,27 @@ void setupRuntime() { ...@@ -3495,24 +3607,27 @@ void setupRuntime() {
// Not sure why CPython defines sizeof(PyTupleObject) to include one element, // Not sure why CPython defines sizeof(PyTupleObject) to include one element,
// but we copy that, which means we have to subtract that extra pointer to get the tp_basicsize: // but we copy that, which means we have to subtract that extra pointer to get the tp_basicsize:
tuple_cls = new (0) tuple_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedTuple) - sizeof(Box*), false, "tuple",
BoxedClass(object_cls, 0, 0, sizeof(BoxedTuple) - sizeof(Box*), false, "tuple", (destructor)tupledealloc, NULL); (destructor)tupledealloc, NULL, true, (traverseproc)tupletraverse, NOCLEAR);
tuple_cls->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS; tuple_cls->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS;
tuple_cls->tp_itemsize = sizeof(Box*); tuple_cls->tp_itemsize = sizeof(Box*);
tuple_cls->tp_mro = BoxedTuple::create({ tuple_cls, object_cls }); tuple_cls->tp_mro = BoxedTuple::create({ tuple_cls, object_cls });
EmptyTuple = BoxedTuple::create({}); EmptyTuple = BoxedTuple::create({});
constants.push_back(EmptyTuple); constants.push_back(EmptyTuple);
list_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedList), false, "list", BoxedList::dealloc, NULL); list_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedList), false, "list", BoxedList::dealloc, NULL, true,
BoxedList::traverse, BoxedList::clear);
list_cls->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS; list_cls->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS;
pyston_getset_cls = new (0) pyston_getset_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedGetsetDescriptor), false, "getset_descriptor",
BoxedClass(object_cls, 0, 0, sizeof(BoxedGetsetDescriptor), false, "getset_descriptor", NULL, NULL); NULL, NULL, false);
attrwrapper_cls = new (0) attrwrapper_cls = new (0)
BoxedClass(object_cls, 0, 0, sizeof(AttrWrapper), false, "attrwrapper", NULL, NULL); BoxedClass(object_cls, 0, 0, sizeof(AttrWrapper), false, "attrwrapper", AttrWrapper::tp_dealloc, NULL, true,
dict_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedDict), false, "dict", BoxedDict::dealloc, NULL); AttrWrapper::tp_traverse, AttrWrapper::tp_clear);
dict_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedDict), false, "dict", BoxedDict::dealloc, NULL, true,
BoxedDict::traverse, BoxedDict::clear);
dict_cls->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS; dict_cls->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
file_cls = new (0) BoxedClass(object_cls, 0, offsetof(BoxedFile, weakreflist), file_cls = new (0) BoxedClass(object_cls, 0, offsetof(BoxedFile, weakreflist),
sizeof(BoxedFile), false, "file", file_dealloc, NULL); sizeof(BoxedFile), false, "file", file_dealloc, NULL, false);
int_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedInt), false, "int", NULL, NULL, false); int_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedInt), false, "int", NULL, NULL, false);
int_cls->tp_flags |= Py_TPFLAGS_INT_SUBCLASS; int_cls->tp_flags |= Py_TPFLAGS_INT_SUBCLASS;
bool_cls = new (0) BoxedClass(int_cls, 0, 0, sizeof(BoxedBool), false, "bool", NULL, NULL, false); bool_cls = new (0) BoxedClass(int_cls, 0, 0, sizeof(BoxedBool), false, "bool", NULL, NULL, false);
...@@ -3521,25 +3636,28 @@ void setupRuntime() { ...@@ -3521,25 +3636,28 @@ void setupRuntime() {
long_cls->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS; long_cls->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS;
float_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedFloat), false, "float", NULL, NULL, false); float_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedFloat), false, "float", NULL, NULL, false);
function_cls = new (0) function_cls = new (0)
BoxedClass(object_cls, offsetof(BoxedFunction, attrs), BoxedClass(object_cls, offsetof(BoxedFunction, attrs), offsetof(BoxedFunction, weakreflist),
offsetof(BoxedFunction, weakreflist), sizeof(BoxedFunction), false, "function", functionDtor, NULL); sizeof(BoxedFunction), false, "function", functionDtor, NULL, true, (traverseproc)func_traverse, NOCLEAR);
builtin_function_or_method_cls = new (0) builtin_function_or_method_cls = new (0) BoxedClass(
BoxedClass(object_cls, 0, offsetof(BoxedBuiltinFunctionOrMethod, weakreflist), object_cls, 0, offsetof(BoxedBuiltinFunctionOrMethod, weakreflist), sizeof(BoxedBuiltinFunctionOrMethod), false,
sizeof(BoxedBuiltinFunctionOrMethod), false, "builtin_function_or_method", functionDtor, NULL); "builtin_function_or_method", functionDtor, NULL, true, (traverseproc)builtin_func_traverse, NOCLEAR);
function_cls->has_safe_tp_dealloc = builtin_function_or_method_cls->has_safe_tp_dealloc = true; function_cls->has_safe_tp_dealloc = builtin_function_or_method_cls->has_safe_tp_dealloc = true;
module_cls = new (0) BoxedClass(object_cls, offsetof(BoxedModule, attrs), 0, module_cls = new (0) BoxedClass(object_cls, offsetof(BoxedModule, attrs), 0, sizeof(BoxedModule), false, "module",
sizeof(BoxedModule), false, "module", BoxedModule::dealloc, NULL); BoxedModule::dealloc, NULL, true, BoxedModule::traverse, NOCLEAR);
member_descriptor_cls = new (0) member_descriptor_cls = new (0)
BoxedClass(object_cls, 0, 0, sizeof(BoxedMemberDescriptor), false, "member_descriptor", NULL, NULL); BoxedClass(object_cls, 0, 0, sizeof(BoxedMemberDescriptor), false, "member_descriptor", NULL, NULL, false);
capifunc_cls = new (0) capifunc_cls = new (0)
BoxedClass(object_cls, 0, 0, sizeof(BoxedCApiFunction), false, "capifunc", NULL, NULL); BoxedClass(object_cls, 0, 0, sizeof(BoxedCApiFunction), false, "capifunc", BoxedCApiFunction::dealloc, NULL,
method_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedMethodDescriptor), true, BoxedCApiFunction::traverse, BoxedCApiFunction::clear);
false, "method_descriptor", NULL, NULL); method_cls = new (0)
wrapperobject_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedWrapperObject), BoxedClass(object_cls, 0, 0, sizeof(BoxedMethodDescriptor), false, "method_descriptor",
false, "method-wrapper", NULL, NULL); BoxedMethodDescriptor::dealloc, NULL, true, BoxedMethodDescriptor::traverse, NOCLEAR);
wrapperobject_cls = new (0)
BoxedClass(object_cls, 0, 0, sizeof(BoxedWrapperObject), false, "method-wrapper", BoxedWrapperObject::dealloc,
NULL, true, BoxedWrapperObject::traverse, NOCLEAR);
wrapperdescr_cls = new (0) BoxedClass(object_cls, 0, 0, wrapperdescr_cls = new (0) BoxedClass(object_cls, 0, 0,
sizeof(BoxedWrapperDescriptor), false, "wrapper_descriptor", NULL, NULL); sizeof(BoxedWrapperDescriptor), false, "wrapper_descriptor", NULL, NULL, false);
EmptyString = new (0) BoxedString(""); EmptyString = new (0) BoxedString("");
constants.push_back(EmptyString); constants.push_back(EmptyString);
...@@ -3645,12 +3763,12 @@ void setupRuntime() { ...@@ -3645,12 +3763,12 @@ void setupRuntime() {
type_cls->giveAttr("__dict__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeDict, NULL, NULL)); type_cls->giveAttr("__dict__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeDict, NULL, NULL));
instancemethod_cls = BoxedClass::create(type_cls, object_cls, 0, instancemethod_cls = BoxedClass::create(type_cls, object_cls, 0, offsetof(BoxedInstanceMethod, im_weakreflist),
offsetof(BoxedInstanceMethod, im_weakreflist), sizeof(BoxedInstanceMethod), sizeof(BoxedInstanceMethod), false, "instancemethod",
false, "instancemethod", BoxedInstanceMethod::dealloc); BoxedInstanceMethod::dealloc, NULL, true, BoxedInstanceMethod::traverse, NOCLEAR);
slice_cls slice_cls
= BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedSlice), false, "slice"); = BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedSlice), false, "slice", BoxedSlice::dealloc, NULL, false);
set_cls = BoxedClass::create(type_cls, object_cls, 0, offsetof(BoxedSet, weakreflist), set_cls = BoxedClass::create(type_cls, object_cls, 0, offsetof(BoxedSet, weakreflist),
sizeof(BoxedSet), false, "set"); sizeof(BoxedSet), false, "set");
frozenset_cls = BoxedClass::create(type_cls, object_cls, 0, offsetof(BoxedSet, weakreflist), frozenset_cls = BoxedClass::create(type_cls, object_cls, 0, offsetof(BoxedSet, weakreflist),
......
...@@ -277,10 +277,12 @@ public: ...@@ -277,10 +277,12 @@ public:
// These should only be used for builtin types: // These should only be used for builtin types:
static BoxedClass* create(BoxedClass* metatype, BoxedClass* base, int attrs_offset, int weaklist_offset, static BoxedClass* create(BoxedClass* metatype, BoxedClass* base, int attrs_offset, int weaklist_offset,
int instance_size, bool is_user_defined, const char* name, destructor dealloc = NULL, int instance_size, bool is_user_defined, const char* name, destructor dealloc = NULL,
freefunc free = NULL, bool is_gc = true); freefunc free = NULL, bool is_gc = true, traverseproc traverse = NULL,
inquiry clear = NULL);
BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset, int instance_size, BoxedClass(BoxedClass* base, int attrs_offset, int weaklist_offset, int instance_size, bool is_user_defined,
bool is_user_defined, const char* name, destructor dealloc, freefunc free, bool is_gc = true); const char* name, destructor dealloc, freefunc free, bool is_gc = true, traverseproc traverse = NULL,
inquiry clear = NULL);
DEFAULT_CLASS_VAR(type_cls, sizeof(SlotOffset)); DEFAULT_CLASS_VAR(type_cls, sizeof(SlotOffset));
...@@ -498,6 +500,7 @@ public: ...@@ -498,6 +500,7 @@ public:
DEFAULT_CLASS_SIMPLE(instancemethod_cls, true); DEFAULT_CLASS_SIMPLE(instancemethod_cls, true);
static void dealloc(Box* self) noexcept; static void dealloc(Box* self) noexcept;
static int traverse(Box* self, visitproc visit, void *arg) noexcept;
}; };
class GCdArray { class GCdArray {
...@@ -534,6 +537,8 @@ public: ...@@ -534,6 +537,8 @@ public:
DEFAULT_CLASS_SIMPLE(list_cls, true); DEFAULT_CLASS_SIMPLE(list_cls, true);
static void dealloc(Box* self) noexcept; static void dealloc(Box* self) noexcept;
static int traverse(Box* self, visitproc visit, void *arg) noexcept;
static int clear(Box* self) noexcept;
}; };
static_assert(sizeof(BoxedList) <= sizeof(PyListObject), ""); static_assert(sizeof(BoxedList) <= sizeof(PyListObject), "");
static_assert(sizeof(BoxedList) >= sizeof(PyListObject), ""); static_assert(sizeof(BoxedList) >= sizeof(PyListObject), "");
...@@ -824,6 +829,8 @@ public: ...@@ -824,6 +829,8 @@ public:
iterator end() { return iterator(d.end()); } iterator end() { return iterator(d.end()); }
static void dealloc(Box* b) noexcept; static void dealloc(Box* b) noexcept;
static int traverse(Box* self, visitproc visit, void *arg) noexcept;
static int clear(Box* self) noexcept;
}; };
static_assert(sizeof(BoxedDict) == sizeof(PyDictObject), ""); static_assert(sizeof(BoxedDict) == sizeof(PyDictObject), "");
...@@ -896,6 +903,7 @@ public: ...@@ -896,6 +903,7 @@ public:
Box* getLongConstant(llvm::StringRef s); Box* getLongConstant(llvm::StringRef s);
static void dealloc(Box* b) noexcept; static void dealloc(Box* b) noexcept;
static int traverse(Box* self, visitproc visit, void *arg) noexcept;
private: private:
ContiguousMap<llvm::StringRef, BoxedString*, llvm::StringMap<int>> str_constants; ContiguousMap<llvm::StringRef, BoxedString*, llvm::StringMap<int>> str_constants;
...@@ -920,6 +928,8 @@ public: ...@@ -920,6 +928,8 @@ public:
Box* start, *stop, *step; Box* start, *stop, *step;
BoxedSlice(Box* lower, Box* upper, Box* step) : start(lower), stop(upper), step(step) {} BoxedSlice(Box* lower, Box* upper, Box* step) : start(lower), stop(upper), step(step) {}
static void dealloc(Box* b) noexcept;
DEFAULT_CLASS_SIMPLE(slice_cls, true); DEFAULT_CLASS_SIMPLE(slice_cls, true);
}; };
static_assert(sizeof(BoxedSlice) == sizeof(PySliceObject), ""); static_assert(sizeof(BoxedSlice) == sizeof(PySliceObject), "");
...@@ -959,7 +969,7 @@ public: ...@@ -959,7 +969,7 @@ public:
BoxedMemberDescriptor(PyMemberDef* member) BoxedMemberDescriptor(PyMemberDef* member)
: type((MemberType)member->type), offset(member->offset), readonly(member->flags & READONLY) {} : type((MemberType)member->type), offset(member->offset), readonly(member->flags & READONLY) {}
DEFAULT_CLASS_SIMPLE(member_descriptor_cls, true); DEFAULT_CLASS_SIMPLE(member_descriptor_cls, false);
}; };
class BoxedGetsetDescriptor : public Box { class BoxedGetsetDescriptor : public Box {
...@@ -971,6 +981,9 @@ public: ...@@ -971,6 +981,9 @@ public:
BoxedGetsetDescriptor(Box* (*get)(Box*, void*), void (*set)(Box*, Box*, void*), void* closure) BoxedGetsetDescriptor(Box* (*get)(Box*, void*), void (*set)(Box*, Box*, void*), void* closure)
: get(get), set(set), closure(closure) {} : get(get), set(set), closure(closure) {}
static void dealloc(Box* b) noexcept;
static int traverse(Box* self, visitproc visit, void *arg) noexcept;
// No DEFAULT_CLASS annotation here -- force callers to explicitly specifiy pyston_getset_cls or capi_getset_cls // No DEFAULT_CLASS annotation here -- force callers to explicitly specifiy pyston_getset_cls or capi_getset_cls
}; };
...@@ -1097,6 +1110,9 @@ public: ...@@ -1097,6 +1110,9 @@ public:
template <ExceptionStyle S> template <ExceptionStyle S>
static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI); Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI);
static void dealloc(Box* self) noexcept;
static int traverse(Box* self, visitproc visit, void *arg) noexcept;
}; };
class BoxedMethodDescriptor : public Box { class BoxedMethodDescriptor : public Box {
...@@ -1113,6 +1129,9 @@ public: ...@@ -1113,6 +1129,9 @@ public:
template <ExceptionStyle S> template <ExceptionStyle S>
static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI); Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI);
static void dealloc(Box* self) noexcept;
static int traverse(Box* self, visitproc visit, void *arg) noexcept;
}; };
Box* objectSetattr(Box* obj, Box* attr, Box* value); Box* objectSetattr(Box* obj, Box* attr, Box* value);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment