Commit f78c923d authored by Kevin Modzelewski's avatar Kevin Modzelewski

Fix some hacks around static classes

Or maybe it's just hacking it up some more.
parent ce233891
...@@ -653,6 +653,7 @@ init_io(void) ...@@ -653,6 +653,7 @@ init_io(void)
// Pyston change: during init we have to supply the module name by ourself. // Pyston change: during init we have to supply the module name by ourself.
_PyIO_unsupported_operation = PyObject_CallFunction((PyObject *)&PyType_Type, "s(OO){s:s}", _PyIO_unsupported_operation = PyObject_CallFunction((PyObject *)&PyType_Type, "s(OO){s:s}",
"UnsupportedOperation", PyExc_ValueError, PyExc_IOError, "__module__", "io"); "UnsupportedOperation", PyExc_ValueError, PyExc_IOError, "__module__", "io");
PyGC_RegisterStaticConstant(_PyIO_unsupported_operation);
// _PyIO_unsupported_operation = PyObject_CallFunction( // _PyIO_unsupported_operation = PyObject_CallFunction(
// (PyObject *)&PyType_Type, "s(OO){}", // (PyObject *)&PyType_Type, "s(OO){}",
// "UnsupportedOperation", PyExc_ValueError, PyExc_IOError); // "UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
......
...@@ -519,6 +519,8 @@ static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int ...@@ -519,6 +519,8 @@ static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int
} }
result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}", result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}",
type, base, "_fields", fnames, "__module__", "_ast"); type, base, "_fields", fnames, "__module__", "_ast");
// Pyston addition:
PyGC_RegisterStaticConstant(result);
Py_DECREF(fnames); Py_DECREF(fnames);
return (PyTypeObject*)result; return (PyTypeObject*)result;
} }
......
...@@ -593,6 +593,9 @@ PyErr_NewException(const char *name, PyObject *base, PyObject *dict) ...@@ -593,6 +593,9 @@ PyErr_NewException(const char *name, PyObject *base, PyObject *dict)
/* Create a real new-style class. */ /* Create a real new-style class. */
result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO", result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO",
dot+1, bases, dict); dot+1, bases, dict);
// Pyston change:
// This should probably be the responsibility of the caller, but just do it here for now:
PyGC_RegisterStaticConstant(result);
failure: failure:
Py_XDECREF(bases); Py_XDECREF(bases);
Py_XDECREF(mydict); Py_XDECREF(mydict);
......
...@@ -6926,6 +6926,17 @@ Box* _typeNew(BoxedClass* metatype, BoxedString* name, BoxedTuple* bases, BoxedD ...@@ -6926,6 +6926,17 @@ Box* _typeNew(BoxedClass* metatype, BoxedString* name, BoxedTuple* bases, BoxedD
bases, total_slots); bases, total_slots);
made->tp_dictoffset = dict_offset; made->tp_dictoffset = dict_offset;
// XXX Hack: the classes vector lists all classes that have untracked references to them.
// This is pretty much any class created in C code, since the C code will tend to hold on
// to a reference to the created class. So in the BoxedClass constructor we add the new class to
// "classes", which will cause the class to get decref'd at the end.
// But for classes created from Python, we don't have this extra untracked reference.
// Rather than fix up the plumbing for now, just reach into the other system and remove this
// class from the list.
// This hack also exists in BoxedHeapClass::create
RELEASE_ASSERT(classes.back() == made, "");
classes.pop_back();
if (boxedSlots) { if (boxedSlots) {
// Set ht_slots // Set ht_slots
BoxedTuple* slotsTuple = BoxedTuple::create(final_slot_names.size()); BoxedTuple* slotsTuple = BoxedTuple::create(final_slot_names.size());
......
...@@ -633,6 +633,31 @@ static Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args ...@@ -633,6 +633,31 @@ static Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args
return typeCallInner<S>(rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); return typeCallInner<S>(rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
} }
// This function only exists for the corner case in typeCallInternal that should get removed anyway:
Box* typeCall(Box* obj, BoxedTuple* vararg, BoxedDict* kwargs) {
assert(vararg->cls == tuple_cls);
bool pass_kwargs = (kwargs && kwargs->d.size());
int n = vararg->size();
int args_to_pass = n + 1 + (pass_kwargs ? 1 : 0); // 1 for obj, 1 for kwargs
Box** args = NULL;
if (args_to_pass > 3)
args = (Box**)alloca(sizeof(Box*) * (args_to_pass - 3));
Box* arg1, *arg2, *arg3;
arg1 = obj;
for (int i = 0; i < n; i++) {
getArg(i + 1, arg1, arg2, arg3, args) = vararg->elts[i];
}
if (pass_kwargs)
getArg(n + 1, arg1, arg2, arg3, args) = kwargs;
return typeCallInternal<CXX>(NULL, NULL, ArgPassSpec(n + 1, 0, false, pass_kwargs), arg1, arg2, arg3, args, NULL);
}
// For use on __init__ return values // For use on __init__ return values
static Box* assertInitNone(STOLEN(Box*) rtn, STOLEN(Box*) obj) { static Box* assertInitNone(STOLEN(Box*) rtn, STOLEN(Box*) obj) {
AUTO_DECREF(rtn); AUTO_DECREF(rtn);
...@@ -1339,32 +1364,6 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1339,32 +1364,6 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
return made; return made;
} }
Box* typeCall(Box* obj, BoxedTuple* vararg, BoxedDict* kwargs) {
RELEASE_ASSERT(0, "this shouldn't get called any more");
assert(vararg->cls == tuple_cls);
bool pass_kwargs = (kwargs && kwargs->d.size());
int n = vararg->size();
int args_to_pass = n + 1 + (pass_kwargs ? 1 : 0); // 1 for obj, 1 for kwargs
Box** args = NULL;
if (args_to_pass > 3)
args = (Box**)alloca(sizeof(Box*) * (args_to_pass - 3));
Box* arg1, *arg2, *arg3;
arg1 = obj;
for (int i = 0; i < n; i++) {
getArg(i + 1, arg1, arg2, arg3, args) = vararg->elts[i];
}
if (pass_kwargs)
getArg(n + 1, arg1, arg2, arg3, args) = kwargs;
return typeCallInternal<CXX>(NULL, NULL, ArgPassSpec(n + 1, 0, false, pass_kwargs), arg1, arg2, arg3, args, NULL);
}
static Box* typeDict(Box* obj, void* context) { static Box* typeDict(Box* obj, void* context) {
if (obj->cls->instancesHaveHCAttrs()) if (obj->cls->instancesHaveHCAttrs())
return PyDictProxy_New(obj->getAttrWrapper()); return PyDictProxy_New(obj->getAttrWrapper());
...@@ -1445,18 +1444,8 @@ extern "C" Box* createUserClass(BoxedString* name, Box* _bases, Box* _attr_dict) ...@@ -1445,18 +1444,8 @@ extern "C" Box* createUserClass(BoxedString* name, Box* _bases, Box* _attr_dict)
Box* r = runtimeCall(metaclass, ArgPassSpec(3), name, _bases, _attr_dict, NULL, NULL); Box* r = runtimeCall(metaclass, ArgPassSpec(3), name, _bases, _attr_dict, NULL, NULL);
RELEASE_ASSERT(r, ""); RELEASE_ASSERT(r, "");
// XXX Hack: the classes vector lists all classes that have untracked references to them. if (isSubclass(r->cls, type_cls))
// This is pretty much any class created in C code, since the C code will tend to hold on assert(classes.back() != r);
// to a reference to the created class. So in the BoxedClass constructor we add the new class to
// "classes", which will cause the class to get decref'd at the end.
// But for classes created from Python, we don't have this extra untracked reference.
// Rather than fix up the plumbing for now, just reach into the other system and remove this
// class from the list.
// This hack also exists in BoxedHeapClass::create
if (isSubclass(r->cls, type_cls)) {
RELEASE_ASSERT(classes.back() == r, "");
classes.pop_back();
}
return r; return r;
} catch (ExcInfo e) { } catch (ExcInfo e) {
...@@ -4073,6 +4062,12 @@ extern "C" PyObject* PyGC_RegisterStaticConstant(Box* b) noexcept { ...@@ -4073,6 +4062,12 @@ extern "C" PyObject* PyGC_RegisterStaticConstant(Box* b) noexcept {
return b; return b;
} }
extern "C" PyObject* PyGC_RegisterStaticClass(Box* b) noexcept {
assert(PyType_Check(b));
classes.push_back(static_cast<BoxedClass*>(b));
return b;
}
extern "C" void _PyUnicode_Fini(void); extern "C" void _PyUnicode_Fini(void);
static int _check_and_flush(FILE* stream) { static int _check_and_flush(FILE* stream) {
......
# expected: reffail
import gc import gc
# Dynamically create new classes and instances of those classes in such a way # Dynamically create new classes and instances of those classes in such a way
......
# expected: reffail
class MM(type): class MM(type):
def __new__(*args): def __new__(*args):
print "MM.__new__", args[:3] print "MM.__new__", args[:3]
......
# expected: reffail
# object.__new__ doesn't complain if __init__ is overridden: # object.__new__ doesn't complain if __init__ is overridden:
class C1(object): class C1(object):
......
# expected: reffail
print 'basic test' print 'basic test'
class C(object): class C(object):
__slots__ = ['a', 'b', '__private_var'] __slots__ = ['a', 'b', '__private_var']
......
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