Commit 22b388e9 authored by Rudi Chen's avatar Rudi Chen

Store simple_destructor in tp_dealloc.

Replace the function pointer to the simple_destructor with a boolean
indicating that the tp_dealloc function is safe to call whenever the
simple_destructor used to be instead.

A few additional classes are also specified to have a safe_tp_dealloc.

For exceptions, use a hack where we look for the creation of exception
classes and store them in a list so we can set their destructor at the
same time as other classes.
parent d9840980
...@@ -135,6 +135,13 @@ PyObject* PyGC_AddRoot(PyObject*) PYSTON_NOEXCEPT; ...@@ -135,6 +135,13 @@ PyObject* PyGC_AddRoot(PyObject*) PYSTON_NOEXCEPT;
// to reduce any chances of compiler reorderings or a GC somehow happening between the assignment // to reduce any chances of compiler reorderings or a GC somehow happening between the assignment
// to the static slot and the call to PyGC_AddRoot. // to the static slot and the call to PyGC_AddRoot.
// Pyston change : expose these type objects
extern PyTypeObject Pattern_Type;
extern PyTypeObject Match_Type;
extern PyTypeObject Scanner_Type;
extern PyTypeObject* Itertool_SafeDealloc_Types[];
#define PyDoc_VAR(name) static char name[] #define PyDoc_VAR(name) static char name[]
#define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str) #define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str)
#define PyDoc_STR(str) str #define PyDoc_STR(str) str
......
...@@ -456,9 +456,8 @@ struct _typeobject { ...@@ -456,9 +456,8 @@ struct _typeobject {
void* _hcattrs; void* _hcattrs;
char _ics[32]; char _ics[32];
void* _gcvisit_func; void* _gcvisit_func;
void* _dtor;
int _attrs_offset; int _attrs_offset;
bool _flags[3]; bool _flags[4];
void* _tpp_descr_get; void* _tpp_descr_get;
void* _tpp_hasnext; void* _tpp_hasnext;
void* _tpp_call; void* _tpp_call;
......
...@@ -2685,7 +2685,7 @@ static PyMemberDef pattern_members[] = { ...@@ -2685,7 +2685,7 @@ static PyMemberDef pattern_members[] = {
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
statichere PyTypeObject Pattern_Type = { PyTypeObject Pattern_Type = {
PyObject_HEAD_INIT(NULL) PyObject_HEAD_INIT(NULL)
0, "_" SRE_MODULE ".SRE_Pattern", 0, "_" SRE_MODULE ".SRE_Pattern",
sizeof(PatternObject), sizeof(SRE_CODE), sizeof(PatternObject), sizeof(SRE_CODE),
...@@ -3729,7 +3729,7 @@ static PyMemberDef match_members[] = { ...@@ -3729,7 +3729,7 @@ static PyMemberDef match_members[] = {
/* FIXME: implement setattr("string", None) as a special case (to /* FIXME: implement setattr("string", None) as a special case (to
detach the associated string, if any */ detach the associated string, if any */
static PyTypeObject Match_Type = { PyTypeObject Match_Type = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"_" SRE_MODULE ".SRE_Match", "_" SRE_MODULE ".SRE_Match",
sizeof(MatchObject), sizeof(Py_ssize_t), sizeof(MatchObject), sizeof(Py_ssize_t),
...@@ -3913,7 +3913,7 @@ static PyMemberDef scanner_members[] = { ...@@ -3913,7 +3913,7 @@ static PyMemberDef scanner_members[] = {
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
statichere PyTypeObject Scanner_Type = { PyTypeObject Scanner_Type = {
PyObject_HEAD_INIT(NULL) PyObject_HEAD_INIT(NULL)
0, "_" SRE_MODULE ".SRE_Scanner", 0, "_" SRE_MODULE ".SRE_Scanner",
sizeof(ScannerObject), 0, sizeof(ScannerObject), 0,
......
...@@ -4080,6 +4080,34 @@ static PyMethodDef module_methods[] = { ...@@ -4080,6 +4080,34 @@ static PyMethodDef module_methods[] = {
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
// Pyston change: These are types defined in this file that I manually
// checked. The ones that aren't commented out have a `tp_dealloc` that
// doesn't do anything in Pyston as we switched to garbage collection and
// the finalizer logic in Pyston wants to know that for optimization purposes.
PyTypeObject* Itertool_SafeDealloc_Types[] = {
// &combinations_type,
// &cwr_type,
&cycle_type,
&dropwhile_type,
&takewhile_type,
&islice_type,
&starmap_type,
&imap_type,
&chain_type,
&compress_type,
&ifilter_type,
&ifilterfalse_type,
&count_type,
&izip_type,
&iziplongest_type,
// &permutations_type,
// &product_type,
&repeat_type,
&groupby_type,
NULL
};
PyMODINIT_FUNC PyMODINIT_FUNC
inititertools(void) inititertools(void)
{ {
......
...@@ -3132,6 +3132,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { ...@@ -3132,6 +3132,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
// this should get automatically initialized to 0 on this path: // this should get automatically initialized to 0 on this path:
assert(cls->attrs_offset == 0); assert(cls->attrs_offset == 0);
if (Py_TPFLAGS_BASE_EXC_SUBCLASS & cls->tp_flags) {
exception_types.push_back(cls);
}
return 0; return 0;
} }
......
...@@ -1886,7 +1886,8 @@ BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr) { ...@@ -1886,7 +1886,8 @@ BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr) {
void setupInterpreter() { void setupInterpreter() {
astinterpreter_cls = BoxedHeapClass::create(type_cls, object_cls, ASTInterpreter::gcHandler, 0, 0, astinterpreter_cls = BoxedHeapClass::create(type_cls, object_cls, ASTInterpreter::gcHandler, 0, 0,
sizeof(ASTInterpreter), false, "astinterpreter"); sizeof(ASTInterpreter), false, "astinterpreter");
astinterpreter_cls->simple_destructor = ASTInterpreter::simpleDestructor; astinterpreter_cls->tp_dealloc = ASTInterpreter::simpleDestructor;
astinterpreter_cls->has_safe_tp_dealloc = true;
astinterpreter_cls->freeze(); astinterpreter_cls->freeze();
} }
} }
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "core/common.h" #include "core/common.h"
#include "core/util.h" #include "core/util.h"
#include "gc/gc_alloc.h" #include "gc/gc_alloc.h"
#include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
#ifndef NVALGRIND #ifndef NVALGRIND
...@@ -124,6 +125,8 @@ void _bytesAllocatedTripped() { ...@@ -124,6 +125,8 @@ void _bytesAllocatedTripped() {
Heap global_heap; Heap global_heap;
__attribute__((always_inline)) bool _doFree(GCAllocation* al, std::vector<Box*>* weakly_referenced) { __attribute__((always_inline)) bool _doFree(GCAllocation* al, std::vector<Box*>* weakly_referenced) {
static StatCounter gc_safe_destructors("gc_safe_destructor_calls");
#ifndef NVALGRIND #ifndef NVALGRIND
VALGRIND_DISABLE_ERROR_REPORTING; VALGRIND_DISABLE_ERROR_REPORTING;
#endif #endif
...@@ -151,13 +154,10 @@ __attribute__((always_inline)) bool _doFree(GCAllocation* al, std::vector<Box*>* ...@@ -151,13 +154,10 @@ __attribute__((always_inline)) bool _doFree(GCAllocation* al, std::vector<Box*>*
} }
} }
// XXX: we are currently ignoring destructors (tp_dealloc) for extension objects, since we have if (b->cls->tp_dealloc != dealloc_null && b->cls->has_safe_tp_dealloc) {
// historically done that (whoops) and there are too many to be worth changing for now as long gc_safe_destructors.log();
// as we can get real destructor support soon. b->cls->tp_dealloc(b);
ASSERT(b->cls->tp_dealloc == NULL || alloc_kind == GCKind::CONSERVATIVE_PYTHON, "%s", getTypeName(b)); }
if (b->cls->simple_destructor)
b->cls->simple_destructor(b);
} }
return true; return true;
} }
......
...@@ -1757,7 +1757,8 @@ void BoxedFile::gcHandler(GCVisitor* v, Box* b) { ...@@ -1757,7 +1757,8 @@ void BoxedFile::gcHandler(GCVisitor* v, Box* b) {
} }
void setupFile() { void setupFile() {
file_cls->simple_destructor = fileDestructor; file_cls->tp_dealloc = fileDestructor;
file_cls->has_safe_tp_dealloc = true;
file_cls->giveAttr("read", file_cls->giveAttr("read",
new BoxedFunction(boxRTFunction((void*)fileRead, STR, 2, 1, false, false), { boxInt(-1) })); new BoxedFunction(boxRTFunction((void*)fileRead, STR, 2, 1, false, false), { boxInt(-1) }));
......
...@@ -152,7 +152,8 @@ Box* getFrame(int depth) { ...@@ -152,7 +152,8 @@ Box* getFrame(int depth) {
void setupFrame() { void setupFrame() {
frame_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false, frame_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false,
"frame"); "frame");
frame_cls->simple_destructor = BoxedFrame::simpleDestructor; frame_cls->tp_dealloc = BoxedFrame::simpleDestructor;
frame_cls->has_safe_tp_dealloc = true;
frame_cls->giveAttr("f_code", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::code, NULL, NULL)); frame_cls->giveAttr("f_code", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::code, NULL, NULL));
frame_cls->giveAttr("f_locals", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::locals, NULL, NULL)); frame_cls->giveAttr("f_locals", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::locals, NULL, NULL));
......
...@@ -436,7 +436,8 @@ void setupGenerator() { ...@@ -436,7 +436,8 @@ void setupGenerator() {
generator_cls generator_cls
= BoxedHeapClass::create(type_cls, object_cls, &generatorGCHandler, 0, offsetof(BoxedGenerator, weakreflist), = BoxedHeapClass::create(type_cls, object_cls, &generatorGCHandler, 0, offsetof(BoxedGenerator, weakreflist),
sizeof(BoxedGenerator), false, "generator"); sizeof(BoxedGenerator), false, "generator");
generator_cls->simple_destructor = generatorDestructor; generator_cls->tp_dealloc = generatorDestructor;
generator_cls->has_safe_tp_dealloc = true;
generator_cls->giveAttr("__iter__", generator_cls->giveAttr("__iter__",
new BoxedFunction(boxRTFunction((void*)generatorIter, typeFromClass(generator_cls), 1))); new BoxedFunction(boxRTFunction((void*)generatorIter, typeFromClass(generator_cls), 1)));
......
...@@ -340,6 +340,16 @@ extern "C" Box** unpackIntoArray(Box* obj, int64_t expected_size) { ...@@ -340,6 +340,16 @@ extern "C" Box** unpackIntoArray(Box* obj, int64_t expected_size) {
return &elts[0]; return &elts[0];
} }
void dealloc_null(Box* box) {
assert(box->cls->tp_del == NULL);
}
// We don't need CPython's version of tp_free since we have GC.
// We still need to set tp_free to something and not a NULL pointer,
// because C extensions might still call tp_free from tp_dealloc.
void default_free(void*) {
}
void BoxedClass::freeze() { void BoxedClass::freeze() {
assert(!is_constant); assert(!is_constant);
assert(tp_name); // otherwise debugging will be very hard assert(tp_name); // otherwise debugging will be very hard
...@@ -358,7 +368,6 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset ...@@ -358,7 +368,6 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
int instance_size, bool is_user_defined) int instance_size, bool is_user_defined)
: attrs(HiddenClass::makeSingleton()), : attrs(HiddenClass::makeSingleton()),
gc_visit(gc_visit), gc_visit(gc_visit),
simple_destructor(NULL),
attrs_offset(attrs_offset), attrs_offset(attrs_offset),
is_constant(false), is_constant(false),
is_user_defined(is_user_defined), is_user_defined(is_user_defined),
...@@ -4960,15 +4969,16 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) { ...@@ -4960,15 +4969,16 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
else else
made->tp_alloc = PyType_GenericAlloc; made->tp_alloc = PyType_GenericAlloc;
assert(!made->simple_destructor); assert(!made->has_safe_tp_dealloc);
for (auto b : *bases) { for (auto b : *bases) {
if (!isSubclass(b->cls, type_cls)) BoxedClass* base = static_cast<BoxedClass*>(b);
if (!isSubclass(base->cls, type_cls))
continue; continue;
BoxedClass* b_cls = static_cast<BoxedClass*>(b); if (base->has_safe_tp_dealloc) {
RELEASE_ASSERT(made->simple_destructor == base->simple_destructor || made->simple_destructor == NULL made->tp_dealloc = base->tp_dealloc;
|| base->simple_destructor == NULL, made->has_safe_tp_dealloc = true;
"Conflicting simple destructors!"); break;
made->simple_destructor = base->simple_destructor; }
} }
return made; return made;
......
...@@ -40,6 +40,10 @@ void _printStacktrace(); ...@@ -40,6 +40,10 @@ void _printStacktrace();
extern "C" Box* deopt(AST_expr* expr, Box* value); extern "C" Box* deopt(AST_expr* expr, Box* value);
// Finalizer-related
void default_free(void*);
void dealloc_null(Box* box);
// helper function for raising from the runtime: // helper function for raising from the runtime:
void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__)); void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__));
void raiseExcHelper(BoxedClass*, Box* arg) __attribute__((__noreturn__)); void raiseExcHelper(BoxedClass*, Box* arg) __attribute__((__noreturn__));
......
...@@ -94,6 +94,8 @@ void setupGC(); ...@@ -94,6 +94,8 @@ void setupGC();
bool IN_SHUTDOWN = false; bool IN_SHUTDOWN = false;
std::vector<BoxedClass*> exception_types;
void FrameInfo::gcVisit(GCVisitor* visitor) { void FrameInfo::gcVisit(GCVisitor* visitor) {
visitor->visit(boxedLocals); visitor->visit(boxedLocals);
visitor->visit(exc.traceback); visitor->visit(exc.traceback);
...@@ -2929,6 +2931,59 @@ extern "C" PyUnicodeObject* _PyUnicode_New(Py_ssize_t length) noexcept { ...@@ -2929,6 +2931,59 @@ extern "C" PyUnicodeObject* _PyUnicode_New(Py_ssize_t length) noexcept {
return unicode; return unicode;
} }
// Normally we don't call the Python tp_ slots that are present to support
// CPython's reference-counted garbage collection. However, for a few types
// like weak references, we still rely on reference-counting to some extent.
static void setTypeGCProxy(BoxedClass* cls) {
cls->tp_alloc = PystonType_GenericAlloc;
cls->gc_visit = proxy_to_tp_traverse;
// We can't use the original tp_dealloc here, the dealloc method of some
// types like ProxyType explicitely frees itself without using tp_free.
cls->tp_dealloc = proxy_to_tp_clear;
cls->has_safe_tp_dealloc = true;
cls->is_pyston_class = true;
}
// By calling this function on a class we assign it Pyston's GC handling
// and no finalizers.
static void setTypeGCNone(BoxedClass* cls) {
cls->tp_alloc = PystonType_GenericAlloc;
cls->tp_free = default_free;
cls->tp_dealloc = dealloc_null;
cls->has_safe_tp_dealloc = true;
cls->is_pyston_class = true;
}
static void setupDefaultClassGCParticipation() {
// some additional setup to ensure weakrefs participate in our GC
setTypeGCProxy(&_PyWeakref_RefType);
setTypeGCProxy(&_PyWeakref_ProxyType);
setTypeGCProxy(&_PyWeakref_CallableProxyType);
// This is an optimization to speed up the handling of unicode objects,
// exception objects, regular expression objects, etc in garbage collection.
// There's no reason to have them part of finalizer ordering.
//
// This is important in tests like django-template which allocates
// hundreds of thousands of unicode strings.
setTypeGCNone(unicode_cls);
unicode_cls->gc_visit = unicode_visit;
for (BoxedClass* cls : exception_types) {
setTypeGCNone(cls);
}
for (int i = 0; Itertool_SafeDealloc_Types[i] != NULL; i++) {
setTypeGCNone(Itertool_SafeDealloc_Types[i]);
}
setTypeGCNone(&Scanner_Type);
setTypeGCNone(&Match_Type);
setTypeGCNone(&Pattern_Type);
setTypeGCNone(&PyCallIter_Type);
}
bool TRACK_ALLOCATIONS = false; bool TRACK_ALLOCATIONS = false;
void setupRuntime() { void setupRuntime() {
...@@ -3031,7 +3086,8 @@ void setupRuntime() { ...@@ -3031,7 +3086,8 @@ void setupRuntime() {
BoxedHeapClass(object_cls, &functionGCHandler, 0, offsetof(BoxedBuiltinFunctionOrMethod, in_weakreflist), BoxedHeapClass(object_cls, &functionGCHandler, 0, offsetof(BoxedBuiltinFunctionOrMethod, in_weakreflist),
sizeof(BoxedBuiltinFunctionOrMethod), false, sizeof(BoxedBuiltinFunctionOrMethod), false,
static_cast<BoxedString*>(boxString("builtin_function_or_method"))); static_cast<BoxedString*>(boxString("builtin_function_or_method")));
function_cls->simple_destructor = builtin_function_or_method_cls->simple_destructor = functionDtor; function_cls->tp_dealloc = builtin_function_or_method_cls->tp_dealloc = functionDtor;
function_cls->has_safe_tp_dealloc = builtin_function_or_method_cls->has_safe_tp_dealloc = true;
module_cls = new (0) BoxedHeapClass(object_cls, &BoxedModule::gcHandler, offsetof(BoxedModule, attrs), 0, module_cls = new (0) BoxedHeapClass(object_cls, &BoxedModule::gcHandler, offsetof(BoxedModule, attrs), 0,
...@@ -3406,32 +3462,7 @@ void setupRuntime() { ...@@ -3406,32 +3462,7 @@ void setupRuntime() {
PyMarshal_Init(); PyMarshal_Init();
initstrop(); initstrop();
// some additional setup to ensure weakrefs participate in our GC setupDefaultClassGCParticipation();
BoxedClass* weakref_ref_cls = &_PyWeakref_RefType;
weakref_ref_cls->tp_alloc = PystonType_GenericAlloc;
weakref_ref_cls->tp_dealloc = NULL;
weakref_ref_cls->gc_visit = proxy_to_tp_traverse;
weakref_ref_cls->simple_destructor = proxy_to_tp_clear;
weakref_ref_cls->is_pyston_class = true;
BoxedClass* weakref_proxy_cls = &_PyWeakref_ProxyType;
weakref_proxy_cls->tp_alloc = PystonType_GenericAlloc;
weakref_proxy_cls->tp_dealloc = NULL;
weakref_proxy_cls->gc_visit = proxy_to_tp_traverse;
weakref_proxy_cls->simple_destructor = proxy_to_tp_clear;
weakref_proxy_cls->is_pyston_class = true;
BoxedClass* weakref_callableproxy = &_PyWeakref_CallableProxyType;
weakref_callableproxy->tp_alloc = PystonType_GenericAlloc;
weakref_callableproxy->tp_dealloc = NULL;
weakref_callableproxy->gc_visit = proxy_to_tp_traverse;
weakref_callableproxy->simple_destructor = proxy_to_tp_clear;
weakref_callableproxy->is_pyston_class = true;
unicode_cls->tp_alloc = PystonType_GenericAlloc;
unicode_cls->gc_visit = unicode_visit;
unicode_cls->tp_dealloc = NULL;
unicode_cls->is_pyston_class = true;
assert(object_cls->tp_setattro == PyObject_GenericSetAttr); assert(object_cls->tp_setattro == PyObject_GenericSetAttr);
assert(none_cls->tp_setattro == PyObject_GenericSetAttr); assert(none_cls->tp_setattro == PyObject_GenericSetAttr);
......
...@@ -94,6 +94,35 @@ extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *long_cls, *float ...@@ -94,6 +94,35 @@ extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *long_cls, *float
#define unicode_cls (&PyUnicode_Type) #define unicode_cls (&PyUnicode_Type)
#define memoryview_cls (&PyMemoryView_Type) #define memoryview_cls (&PyMemoryView_Type)
#define unicode_cls (&PyUnicode_Type)
#define memoryview_cls (&PyMemoryView_Type)
#define SystemError ((BoxedClass*)PyExc_SystemError)
#define StopIteration ((BoxedClass*)PyExc_StopIteration)
#define NameError ((BoxedClass*)PyExc_NameError)
#define UnboundLocalError ((BoxedClass*)PyExc_UnboundLocalError)
#define BaseException ((BoxedClass*)PyExc_BaseException)
#define TypeError ((BoxedClass*)PyExc_TypeError)
#define AssertionError ((BoxedClass*)PyExc_AssertionError)
#define ValueError ((BoxedClass*)PyExc_ValueError)
#define SystemExit ((BoxedClass*)PyExc_SystemExit)
#define SyntaxError ((BoxedClass*)PyExc_SyntaxError)
#define Exception ((BoxedClass*)PyExc_Exception)
#define AttributeError ((BoxedClass*)PyExc_AttributeError)
#define RuntimeError ((BoxedClass*)PyExc_RuntimeError)
#define ZeroDivisionError ((BoxedClass*)PyExc_ZeroDivisionError)
#define ImportError ((BoxedClass*)PyExc_ImportError)
#define IndexError ((BoxedClass*)PyExc_IndexError)
#define GeneratorExit ((BoxedClass*)PyExc_GeneratorExit)
#define IOError ((BoxedClass*)PyExc_IOError)
#define KeyError ((BoxedClass*)PyExc_KeyError)
#define OverflowError ((BoxedClass*)PyExc_OverflowError)
// Contains a list classes that have BaseException as a parent. This list is NOT guaranteed to be
// comprehensive - it will not contain user-defined exception types. This is mainly for optimization
// purposes, where it's useful to speed up the garbage collection of some exceptions.
extern std::vector<BoxedClass*> exception_types;
extern "C" { extern "C" {
extern Box* None, *NotImplemented, *True, *False; extern Box* None, *NotImplemented, *True, *False;
} }
...@@ -163,13 +192,6 @@ public: ...@@ -163,13 +192,6 @@ public:
gcvisit_func gc_visit; gcvisit_func gc_visit;
// A "simple" destructor -- one that is allowed to be called at any point after the object is dead.
// In particular, this means that it can't touch any Python objects or other gc-managed memory,
// since it will be in an undefined state.
// (Context: in Python destructors are supposed to be called in topological order, due to reference counting.
// We don't support that yet, but still want some simple ability to run code when an object gets freed.)
void (*simple_destructor)(Box*);
// Offset of the HCAttrs object or 0 if there are no hcattrs. // Offset of the HCAttrs object or 0 if there are no hcattrs.
// Negative offset is from the end of the class (useful for variable-size objects with the attrs at the end) // Negative offset is from the end of the class (useful for variable-size objects with the attrs at the end)
// Analogous to tp_dictoffset // Analogous to tp_dictoffset
...@@ -180,6 +202,17 @@ public: ...@@ -180,6 +202,17 @@ public:
bool instancesHaveHCAttrs() { return attrs_offset != 0; } bool instancesHaveHCAttrs() { return attrs_offset != 0; }
bool instancesHaveDictAttrs() { return tp_dictoffset != 0; } bool instancesHaveDictAttrs() { return tp_dictoffset != 0; }
// A "safe" tp_dealloc destructor/finalizer is one we believe:
// 1) Can be called at any point after the object is dead.
// (implies it's references could be finalized already)
// 2) Won't take a lot of time to run.
// 3) Won't take up a lot of memory (requiring another GC run).
// 4) Won't resurrect itself.
//
// We specify that such destructors are safe for optimization purposes. We call the tp_dealloc
// as the object gets freed.
bool has_safe_tp_dealloc;
// Whether this class object is constant or not, ie whether or not class-level // Whether this class object is constant or not, ie whether or not class-level
// attributes can be changed or added. // attributes can be changed or added.
// Does not necessarily imply that the instances of this class are constant, // Does not necessarily imply that the instances of this class are constant,
...@@ -1025,27 +1058,6 @@ void attrwrapperDel(Box* b, llvm::StringRef attr); ...@@ -1025,27 +1058,6 @@ void attrwrapperDel(Box* b, llvm::StringRef attr);
Box* boxAst(AST* ast); Box* boxAst(AST* ast);
AST* unboxAst(Box* b); AST* unboxAst(Box* b);
#define SystemError ((BoxedClass*)PyExc_SystemError)
#define StopIteration ((BoxedClass*)PyExc_StopIteration)
#define NameError ((BoxedClass*)PyExc_NameError)
#define UnboundLocalError ((BoxedClass*)PyExc_UnboundLocalError)
#define BaseException ((BoxedClass*)PyExc_BaseException)
#define TypeError ((BoxedClass*)PyExc_TypeError)
#define AssertionError ((BoxedClass*)PyExc_AssertionError)
#define ValueError ((BoxedClass*)PyExc_ValueError)
#define SystemExit ((BoxedClass*)PyExc_SystemExit)
#define SyntaxError ((BoxedClass*)PyExc_SyntaxError)
#define Exception ((BoxedClass*)PyExc_Exception)
#define AttributeError ((BoxedClass*)PyExc_AttributeError)
#define RuntimeError ((BoxedClass*)PyExc_RuntimeError)
#define ZeroDivisionError ((BoxedClass*)PyExc_ZeroDivisionError)
#define ImportError ((BoxedClass*)PyExc_ImportError)
#define IndexError ((BoxedClass*)PyExc_IndexError)
#define GeneratorExit ((BoxedClass*)PyExc_GeneratorExit)
#define IOError ((BoxedClass*)PyExc_IOError)
#define KeyError ((BoxedClass*)PyExc_KeyError)
#define OverflowError ((BoxedClass*)PyExc_OverflowError)
// Our default for tp_alloc: // Our default for tp_alloc:
extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems) noexcept; extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems) noexcept;
......
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