Commit 39859d79 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'multiple_inheritance'

parents 53dc9612 fee6818c
...@@ -404,26 +404,26 @@ check: ...@@ -404,26 +404,26 @@ check:
@# jit_prof forces the use of GCC as the compiler, which can expose other errors, so just build it and see what happens: @# jit_prof forces the use of GCC as the compiler, which can expose other errors, so just build it and see what happens:
$(MAKE) pyston_prof $(MAKE) pyston_prof
@# and run some basic tests to make sure it works: @# and run some basic tests to make sure it works:
$(call checksha,./pyston_prof -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_prof -q $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_prof -qn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_prof -qO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(MAKE) check_release $(MAKE) check_release
echo "All tests passed" echo "All tests passed"
quick_check: quick_check:
$(MAKE) pyston_dbg $(MAKE) pyston_dbg
$(call checksha,./pyston_dbg -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_dbg -q $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_dbg -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_dbg -qn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_dbg -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_dbg -qO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(MAKE) pyston $(MAKE) pyston
$(call checksha,./pyston -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston -q $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston -qn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston -qO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(MAKE) pyston_prof $(MAKE) pyston_prof
$(call checksha,./pyston_prof -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_prof -q $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_prof -qn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_prof -qO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
Makefile.local: Makefile.local:
echo "Creating default Makefile.local" echo "Creating default Makefile.local"
......
...@@ -180,7 +180,13 @@ void RewriterVar::addAttrGuard(int offset, uint64_t val, bool negate) { ...@@ -180,7 +180,13 @@ void RewriterVar::addAttrGuard(int offset, uint64_t val, bool negate) {
} }
void Rewriter::_addAttrGuard(RewriterVar* var, int offset, uint64_t val, bool negate) { void Rewriter::_addAttrGuard(RewriterVar* var, int offset, uint64_t val, bool negate) {
assembler::Register var_reg = var->getInReg(); // TODO if var is a constant, we will end up emitting something like
// mov $0x123, %rax
// cmp $0x10(%rax), %rdi
// when we could just do
// cmp ($0x133), %rdi
assembler::Register var_reg = var->getInReg(Location::any(), /* allow_constant_in_reg */ true);
if (isLargeConstant(val)) { if (isLargeConstant(val)) {
assembler::Register reg = allocReg(Location::any(), /* otherThan */ var_reg); assembler::Register reg = allocReg(Location::any(), /* otherThan */ var_reg);
assert(reg != var_reg); assert(reg != var_reg);
...@@ -206,7 +212,12 @@ RewriterVar* RewriterVar::getAttr(int offset, Location dest, assembler::MovType ...@@ -206,7 +212,12 @@ RewriterVar* RewriterVar::getAttr(int offset, Location dest, assembler::MovType
} }
void Rewriter::_getAttr(RewriterVar* result, RewriterVar* ptr, int offset, Location dest, assembler::MovType type) { void Rewriter::_getAttr(RewriterVar* result, RewriterVar* ptr, int offset, Location dest, assembler::MovType type) {
assembler::Register ptr_reg = ptr->getInReg(); // TODO if var is a constant, we will end up emitting something like
// mov $0x123, %rax
// mov $0x10(%rax), %rdi
// when we could just do
// mov ($0x133), %rdi
assembler::Register ptr_reg = ptr->getInReg(Location::any(), /* allow_constant_in_reg */ true);
// It's okay to bump the use now, since it's fine to allocate the result // It's okay to bump the use now, since it's fine to allocate the result
// in the same register as ptr // in the same register as ptr
......
...@@ -293,15 +293,16 @@ extern "C" PyObject* PyObject_CallFunctionObjArgs(PyObject* callable, ...) noexc ...@@ -293,15 +293,16 @@ extern "C" PyObject* PyObject_CallFunctionObjArgs(PyObject* callable, ...) noexc
} }
extern "C" PyObject* PyObject_CallObject(PyObject* obj, PyObject* args) noexcept { extern "C" PyObject* PyObject_CallObject(PyObject* obj, PyObject* args) noexcept {
RELEASE_ASSERT(args, ""); // actually it looks like this is allowed to be NULL
RELEASE_ASSERT(args->cls == tuple_cls, "");
// TODO do something like this? not sure if this is safe; will people expect that calling into a known function // TODO do something like this? not sure if this is safe; will people expect that calling into a known function
// won't end up doing a GIL check? // won't end up doing a GIL check?
// threading::GLDemoteRegion _gil_demote; // threading::GLDemoteRegion _gil_demote;
try { try {
Box* r = runtimeCall(obj, ArgPassSpec(0, 0, true, false), args, NULL, NULL, NULL, NULL); Box* r;
if (args)
r = runtimeCall(obj, ArgPassSpec(0, 0, true, false), args, NULL, NULL, NULL, NULL);
else
r = runtimeCall(obj, ArgPassSpec(0, 0, false, false), NULL, NULL, NULL, NULL, NULL);
return r; return r;
} catch (ExcInfo e) { } catch (ExcInfo e) {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
......
...@@ -82,7 +82,7 @@ static int _ustrlen(Py_UNICODE* u) { ...@@ -82,7 +82,7 @@ static int _ustrlen(Py_UNICODE* u) {
#endif #endif
static PyObject* do_mktuple(const char**, va_list*, int, int, int) noexcept; static PyObject* do_mktuple(const char**, va_list*, int, int, int) noexcept;
// static PyObject *do_mklist(const char**, va_list *, int, int, int) noexcept; static PyObject* do_mklist(const char**, va_list*, int, int, int) noexcept;
// static PyObject *do_mkdict(const char**, va_list *, int, int, int) noexcept; // static PyObject *do_mkdict(const char**, va_list *, int, int, int) noexcept;
static PyObject* do_mkvalue(const char**, va_list*, int) noexcept; static PyObject* do_mkvalue(const char**, va_list*, int) noexcept;
...@@ -92,10 +92,10 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe ...@@ -92,10 +92,10 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe
case '(': case '(':
return do_mktuple(p_format, p_va, ')', countformat(*p_format, ')'), flags); return do_mktuple(p_format, p_va, ')', countformat(*p_format, ')'), flags);
#if 0
case '[': case '[':
return do_mklist(p_format, p_va, ']', countformat(*p_format, ']'), flags); return do_mklist(p_format, p_va, ']', countformat(*p_format, ']'), flags);
#if 0
case '{': case '{':
return do_mkdict(p_format, p_va, '}', countformat(*p_format, '}'), flags); return do_mkdict(p_format, p_va, '}', countformat(*p_format, '}'), flags);
#endif #endif
...@@ -239,6 +239,43 @@ static PyObject* do_mktuple(const char** p_format, va_list* p_va, int endchar, i ...@@ -239,6 +239,43 @@ static PyObject* do_mktuple(const char** p_format, va_list* p_va, int endchar, i
return v; return v;
} }
static PyObject* do_mklist(const char** p_format, va_list* p_va, int endchar, int n, int flags) noexcept {
PyObject* v;
int i;
int itemfailed = 0;
if (n < 0)
return NULL;
v = PyList_New(n);
if (v == NULL)
return NULL;
/* Note that we can't bail immediately on error as this will leak
refcounts on any 'N' arguments. */
for (i = 0; i < n; i++) {
PyObject* w = do_mkvalue(p_format, p_va, flags);
if (w == NULL) {
itemfailed = 1;
Py_INCREF(Py_None);
w = Py_None;
}
PyList_SET_ITEM(v, i, w);
}
if (itemfailed) {
/* do_mkvalue() should have already set an error */
Py_DECREF(v);
return NULL;
}
if (**p_format != endchar) {
Py_DECREF(v);
PyErr_SetString(PyExc_SystemError, "Unmatched paren in format");
return NULL;
}
if (endchar)
++*p_format;
return v;
}
static PyObject* va_build_value(const char* fmt, va_list va, int flags) noexcept { static PyObject* va_build_value(const char* fmt, va_list va, int flags) noexcept {
int n = countformat(fmt, '\0'); int n = countformat(fmt, '\0');
......
...@@ -1466,6 +1466,508 @@ static void add_operators(BoxedClass* cls) noexcept { ...@@ -1466,6 +1466,508 @@ static void add_operators(BoxedClass* cls) noexcept {
add_tp_new_wrapper(cls); add_tp_new_wrapper(cls);
} }
static void type_mro_modified(PyTypeObject* type, PyObject* bases) {
/*
Check that all base classes or elements of the mro of type are
able to be cached. This function is called after the base
classes or mro of the type are altered.
Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
inherits from an old-style class, either directly or if it
appears in the MRO of a new-style class. No support either for
custom MROs that include types that are not officially super
types.
Called from mro_internal, which will subsequently be called on
each subclass when their mro is recursively updated.
*/
Py_ssize_t i, n;
int clear = 0;
if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
return;
n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) {
PyObject* b = PyTuple_GET_ITEM(bases, i);
PyTypeObject* cls;
if (!PyType_Check(b)) {
clear = 1;
break;
}
cls = (PyTypeObject*)b;
if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) || !PyType_IsSubtype(type, cls)) {
clear = 1;
break;
}
}
if (clear)
type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_VALID_VERSION_TAG);
}
static int extra_ivars(PyTypeObject* type, PyTypeObject* base) noexcept {
size_t t_size = type->tp_basicsize;
size_t b_size = base->tp_basicsize;
assert(t_size >= b_size); /* Else type smaller than base! */
if (type->tp_itemsize || base->tp_itemsize) {
/* If itemsize is involved, stricter rules */
return t_size != b_size || type->tp_itemsize != base->tp_itemsize;
}
if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 && type->tp_weaklistoffset + sizeof(PyObject*) == t_size
&& type->tp_flags & Py_TPFLAGS_HEAPTYPE)
t_size -= sizeof(PyObject*);
if (type->tp_dictoffset && base->tp_dictoffset == 0 && type->tp_dictoffset + sizeof(PyObject*) == t_size
&& type->tp_flags & Py_TPFLAGS_HEAPTYPE)
t_size -= sizeof(PyObject*);
// Pyston change:
if (type->instancesHaveHCAttrs() && !base->instancesHaveHCAttrs())
t_size -= sizeof(HCAttrs);
return t_size != b_size;
}
static PyTypeObject* solid_base(PyTypeObject* type) noexcept {
PyTypeObject* base;
if (type->tp_base)
base = solid_base(type->tp_base);
else
base = object_cls;
if (extra_ivars(type, base))
return type;
else
return base;
}
PyTypeObject* best_base(PyObject* bases) noexcept {
Py_ssize_t i, n;
PyTypeObject* base, *winner, *candidate, *base_i;
PyObject* base_proto;
assert(PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases);
assert(n > 0);
base = NULL;
winner = NULL;
for (i = 0; i < n; i++) {
base_proto = PyTuple_GET_ITEM(bases, i);
if (PyClass_Check(base_proto))
continue;
if (!PyType_Check(base_proto)) {
PyErr_SetString(PyExc_TypeError, "bases must be types");
return NULL;
}
base_i = (PyTypeObject*)base_proto;
// Pyston change: we require things are already ready
if (base_i->tp_dict == NULL) {
assert(base_i->is_pyston_class);
#if 0
if (PyType_Ready(base_i) < 0)
return NULL;
#endif
}
candidate = solid_base(base_i);
if (winner == NULL) {
winner = candidate;
base = base_i;
} else if (PyType_IsSubtype(winner, candidate))
;
else if (PyType_IsSubtype(candidate, winner)) {
winner = candidate;
base = base_i;
} else {
PyErr_SetString(PyExc_TypeError, "multiple bases have "
"instance lay-out conflict");
return NULL;
}
}
if (base == NULL)
PyErr_SetString(PyExc_TypeError, "a new-style class can't have only classic bases");
return base;
}
static int fill_classic_mro(PyObject* mro, PyObject* cls) {
PyObject* bases, *base;
Py_ssize_t i, n;
assert(PyList_Check(mro));
assert(PyClass_Check(cls));
i = PySequence_Contains(mro, cls);
if (i < 0)
return -1;
if (!i) {
if (PyList_Append(mro, cls) < 0)
return -1;
}
Py_FatalError("unimplemented");
// We should add multiple inheritance for old-style classes
#if 0
bases = ((PyClassObject*)cls)->cl_bases;
assert(bases && PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) {
base = PyTuple_GET_ITEM(bases, i);
if (fill_classic_mro(mro, base) < 0)
return -1;
}
return 0;
#endif
}
static PyObject* classic_mro(PyObject* cls) {
PyObject* mro;
assert(PyClass_Check(cls));
mro = PyList_New(0);
if (mro != NULL) {
if (fill_classic_mro(mro, cls) == 0)
return mro;
Py_DECREF(mro);
}
return NULL;
}
/*
Method resolution order algorithm C3 described in
"A Monotonic Superclass Linearization for Dylan",
by Kim Barrett, Bob Cassel, Paul Haahr,
David A. Moon, Keith Playford, and P. Tucker Withington.
(OOPSLA 1996)
Some notes about the rules implied by C3:
No duplicate bases.
It isn't legal to repeat a class in a list of base classes.
The next three properties are the 3 constraints in "C3".
Local precendece order.
If A precedes B in C's MRO, then A will precede B in the MRO of all
subclasses of C.
Monotonicity.
The MRO of a class must be an extension without reordering of the
MRO of each of its superclasses.
Extended Precedence Graph (EPG).
Linearization is consistent if there is a path in the EPG from
each class to all its successors in the linearization. See
the paper for definition of EPG.
*/
static int tail_contains(PyObject* list, int whence, PyObject* o) {
Py_ssize_t j, size;
size = PyList_GET_SIZE(list);
for (j = whence + 1; j < size; j++) {
if (PyList_GET_ITEM(list, j) == o)
return 1;
}
return 0;
}
static PyObject* class_name(PyObject* cls) {
PyObject* name = PyObject_GetAttrString(cls, "__name__");
if (name == NULL) {
PyErr_Clear();
Py_XDECREF(name);
name = PyObject_Repr(cls);
}
if (name == NULL)
return NULL;
if (!PyString_Check(name)) {
Py_DECREF(name);
return NULL;
}
return name;
}
static int check_duplicates(PyObject* list) {
Py_ssize_t i, j, n;
/* Let's use a quadratic time algorithm,
assuming that the bases lists is short.
*/
n = PyList_GET_SIZE(list);
for (i = 0; i < n; i++) {
PyObject* o = PyList_GET_ITEM(list, i);
for (j = i + 1; j < n; j++) {
if (PyList_GET_ITEM(list, j) == o) {
o = class_name(o);
PyErr_Format(PyExc_TypeError, "duplicate base class %s", o ? PyString_AS_STRING(o) : "?");
Py_XDECREF(o);
return -1;
}
}
}
return 0;
}
/* Raise a TypeError for an MRO order disagreement.
It's hard to produce a good error message. In the absence of better
insight into error reporting, report the classes that were candidates
to be put next into the MRO. There is some conflict between the
order in which they should be put in the MRO, but it's hard to
diagnose what constraint can't be satisfied.
*/
static void set_mro_error(PyObject* to_merge, int* remain) noexcept {
Py_ssize_t i, n, off, to_merge_size;
char buf[1000];
PyObject* k, *v;
PyObject* set = PyDict_New();
if (!set)
return;
to_merge_size = PyList_GET_SIZE(to_merge);
for (i = 0; i < to_merge_size; i++) {
PyObject* L = PyList_GET_ITEM(to_merge, i);
if (remain[i] < PyList_GET_SIZE(L)) {
PyObject* c = PyList_GET_ITEM(L, remain[i]);
if (PyDict_SetItem(set, c, Py_None) < 0) {
Py_DECREF(set);
return;
}
}
}
n = PyDict_Size(set);
off = PyOS_snprintf(buf, sizeof(buf), "Cannot create a \
consistent method resolution\norder (MRO) for bases");
i = 0;
while (PyDict_Next(set, &i, &k, &v) && (size_t)off < sizeof(buf)) {
PyObject* name = class_name(k);
off += PyOS_snprintf(buf + off, sizeof(buf) - off, " %s", name ? PyString_AS_STRING(name) : "?");
Py_XDECREF(name);
if (--n && (size_t)(off + 1) < sizeof(buf)) {
buf[off++] = ',';
buf[off] = '\0';
}
}
PyErr_SetString(PyExc_TypeError, buf);
Py_DECREF(set);
}
static int pmerge(PyObject* acc, PyObject* to_merge) noexcept {
Py_ssize_t i, j, to_merge_size, empty_cnt;
int* remain;
int ok;
to_merge_size = PyList_GET_SIZE(to_merge);
/* remain stores an index into each sublist of to_merge.
remain[i] is the index of the next base in to_merge[i]
that is not included in acc.
*/
remain = (int*)PyMem_MALLOC(SIZEOF_INT * to_merge_size);
if (remain == NULL)
return -1;
for (i = 0; i < to_merge_size; i++)
remain[i] = 0;
again:
empty_cnt = 0;
for (i = 0; i < to_merge_size; i++) {
PyObject* candidate;
PyObject* cur_list = PyList_GET_ITEM(to_merge, i);
if (remain[i] >= PyList_GET_SIZE(cur_list)) {
empty_cnt++;
continue;
}
/* Choose next candidate for MRO.
The input sequences alone can determine the choice.
If not, choose the class which appears in the MRO
of the earliest direct superclass of the new class.
*/
candidate = PyList_GET_ITEM(cur_list, remain[i]);
for (j = 0; j < to_merge_size; j++) {
PyObject* j_lst = PyList_GET_ITEM(to_merge, j);
if (tail_contains(j_lst, remain[j], candidate)) {
goto skip; /* continue outer loop */
}
}
ok = PyList_Append(acc, candidate);
if (ok < 0) {
PyMem_Free(remain);
return -1;
}
for (j = 0; j < to_merge_size; j++) {
PyObject* j_lst = PyList_GET_ITEM(to_merge, j);
if (remain[j] < PyList_GET_SIZE(j_lst) && PyList_GET_ITEM(j_lst, remain[j]) == candidate) {
remain[j]++;
}
}
goto again;
skip:
;
}
if (empty_cnt == to_merge_size) {
PyMem_FREE(remain);
return 0;
}
set_mro_error(to_merge, remain);
PyMem_FREE(remain);
return -1;
}
static PyObject* mro_implementation(PyTypeObject* type) noexcept {
Py_ssize_t i, n;
int ok;
PyObject* bases, *result;
PyObject* to_merge, *bases_aslist;
// Pyston change: we require things are already ready
if (type->tp_dict == NULL) {
assert(type->is_pyston_class);
#if 0
if (PyType_Ready(type) < 0)
return NULL;
#endif
}
/* Find a superclass linearization that honors the constraints
of the explicit lists of bases and the constraints implied by
each base class.
to_merge is a list of lists, where each list is a superclass
linearization implied by a base class. The last element of
to_merge is the declared list of bases.
*/
bases = type->tp_bases;
assert(type->tp_bases);
assert(type->tp_bases->cls == tuple_cls);
n = PyTuple_GET_SIZE(bases);
to_merge = PyList_New(n + 1);
if (to_merge == NULL)
return NULL;
for (i = 0; i < n; i++) {
PyObject* base = PyTuple_GET_ITEM(bases, i);
PyObject* parentMRO;
if (PyType_Check(base))
parentMRO = PySequence_List(((PyTypeObject*)base)->tp_mro);
else
parentMRO = classic_mro(base);
if (parentMRO == NULL) {
Py_DECREF(to_merge);
return NULL;
}
PyList_SET_ITEM(to_merge, i, parentMRO);
}
bases_aslist = PySequence_List(bases);
if (bases_aslist == NULL) {
Py_DECREF(to_merge);
return NULL;
}
/* This is just a basic sanity check. */
if (check_duplicates(bases_aslist) < 0) {
Py_DECREF(to_merge);
Py_DECREF(bases_aslist);
return NULL;
}
PyList_SET_ITEM(to_merge, n, bases_aslist);
result = Py_BuildValue("[O]", (PyObject*)type);
if (result == NULL) {
Py_DECREF(to_merge);
return NULL;
}
ok = pmerge(result, to_merge);
Py_DECREF(to_merge);
if (ok < 0) {
Py_DECREF(result);
return NULL;
}
return result;
}
// Pyston change: made this non-static
PyObject* mro_external(PyObject* self) noexcept {
PyTypeObject* type = (PyTypeObject*)self;
return mro_implementation(type);
}
static int mro_internal(PyTypeObject* type) noexcept {
PyObject* mro, *result, *tuple;
int checkit = 0;
if (Py_TYPE(type) == &PyType_Type) {
result = mro_implementation(type);
} else {
static PyObject* mro_str;
checkit = 1;
mro = lookup_method((PyObject*)type, "mro", &mro_str);
if (mro == NULL)
return -1;
result = PyObject_CallObject(mro, NULL);
Py_DECREF(mro);
}
if (result == NULL)
return -1;
tuple = PySequence_Tuple(result);
Py_DECREF(result);
if (tuple == NULL)
return -1;
if (checkit) {
Py_ssize_t i, len;
PyObject* cls;
PyTypeObject* solid;
solid = solid_base(type);
len = PyTuple_GET_SIZE(tuple);
for (i = 0; i < len; i++) {
PyTypeObject* t;
cls = PyTuple_GET_ITEM(tuple, i);
if (PyClass_Check(cls))
continue;
else if (!PyType_Check(cls)) {
PyErr_Format(PyExc_TypeError, "mro() returned a non-class ('%.500s')", Py_TYPE(cls)->tp_name);
Py_DECREF(tuple);
return -1;
}
t = (PyTypeObject*)cls;
if (!PyType_IsSubtype(solid, solid_base(t))) {
PyErr_Format(PyExc_TypeError, "mro() returned base with unsuitable layout ('%.500s')", t->tp_name);
Py_DECREF(tuple);
return -1;
}
}
}
type->tp_mro = tuple;
type_mro_modified(type, type->tp_mro);
/* corner case: the old-style super class might have been hidden
from the custom MRO */
type_mro_modified(type, type->tp_bases);
PyType_Modified(type);
return 0;
}
extern "C" int PyType_IsSubtype(PyTypeObject* a, PyTypeObject* b) noexcept { extern "C" int PyType_IsSubtype(PyTypeObject* a, PyTypeObject* b) noexcept {
return isSubclass(a, b); return isSubclass(a, b);
} }
...@@ -1769,20 +2271,31 @@ static void inherit_slots(PyTypeObject* type, PyTypeObject* base) noexcept { ...@@ -1769,20 +2271,31 @@ static void inherit_slots(PyTypeObject* type, PyTypeObject* base) noexcept {
} }
} }
// PystonType_Ready is for the common code between PyType_Ready (which is just for extension classes) // commonClassSetup is for the common code between PyType_Ready (which is just for extension classes)
// and our internal type-creation endpoints (BoxedClass::BoxedClass()). // and our internal type-creation endpoints (BoxedClass::BoxedClass()).
// TODO: Move more of the duplicated logic into here. // TODO: Move more of the duplicated logic into here.
void PystonType_Ready(BoxedClass* cls) { void commonClassSetup(BoxedClass* cls) {
inherit_special(cls, cls->tp_base); if (cls->tp_bases == NULL) {
if (cls->tp_base)
cls->tp_bases = new BoxedTuple({ cls->tp_base });
else
cls->tp_bases = new BoxedTuple({});
}
// This is supposed to be over the MRO but we don't support multiple inheritance yet: /* Calculate method resolution order */
BoxedClass* b = cls->tp_base; if (mro_internal(cls) < 0)
while (b) { throwCAPIException();
// Not sure when this could fail; maybe not in Pyston right now but apparently it can in CPython:
if (PyType_Check(b)) if (cls->tp_base)
inherit_slots(cls, b); inherit_special(cls, cls->tp_base);
b = b->tp_base; assert(cls->tp_mro);
assert(cls->tp_mro->cls == tuple_cls);
for (auto b : static_cast<BoxedTuple*>(cls->tp_mro)->elts) {
if (b == cls)
continue;
if (PyType_Check(b))
inherit_slots(cls, static_cast<BoxedClass*>(b));
} }
} }
...@@ -1791,6 +2304,8 @@ extern "C" void PyType_Modified(PyTypeObject* type) noexcept { ...@@ -1791,6 +2304,8 @@ extern "C" void PyType_Modified(PyTypeObject* type) noexcept {
} }
extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
ASSERT(!cls->is_pyston_class, "should not call this on Pyston classes");
gc::registerNonheapRootObject(cls); gc::registerNonheapRootObject(cls);
// unhandled fields: // unhandled fields:
...@@ -1864,7 +2379,12 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { ...@@ -1864,7 +2379,12 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
getset->get, (void (*)(Box*, Box*, void*))getset->set, getset->closure)); getset->get, (void (*)(Box*, Box*, void*))getset->set, getset->closure));
} }
PystonType_Ready(cls); try {
commonClassSetup(cls);
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
}
if (!cls->hasattr("__doc__")) { if (!cls->hasattr("__doc__")) {
if (cls->tp_doc) { if (cls->tp_doc) {
......
...@@ -23,7 +23,14 @@ namespace pyston { ...@@ -23,7 +23,14 @@ namespace pyston {
bool update_slot(BoxedClass* self, const std::string& attr) noexcept; bool update_slot(BoxedClass* self, const std::string& attr) noexcept;
void fixup_slot_dispatchers(BoxedClass* self) noexcept; void fixup_slot_dispatchers(BoxedClass* self) noexcept;
void PystonType_Ready(BoxedClass* cls); void commonClassSetup(BoxedClass* cls);
// We need to expose these due to our different file organization (they
// are defined as part of the CPython copied into typeobject.c, but used
// from Pyston code).
// We could probably unify things more but that's for later.
PyTypeObject* best_base(PyObject* bases) noexcept;
PyObject* mro_external(PyObject* self) noexcept;
} }
#endif #endif
...@@ -630,8 +630,8 @@ LargeArena::LargeFreeChunk* LargeArena::get_from_size_list(LargeFreeChunk** list ...@@ -630,8 +630,8 @@ LargeArena::LargeFreeChunk* LargeArena::get_from_size_list(LargeFreeChunk** list
section->free_chunk_map[i] = 0; section->free_chunk_map[i] = 0;
} }
assert(section->num_free_chunks >= size >> CHUNK_BITS);
section->num_free_chunks -= size >> CHUNK_BITS; section->num_free_chunks -= size >> CHUNK_BITS;
assert(section->num_free_chunks >= 0);
return free_chunks; return free_chunks;
} }
......
...@@ -730,7 +730,7 @@ static BoxedClass* makeBuiltinException(BoxedClass* base, const char* name, int ...@@ -730,7 +730,7 @@ static BoxedClass* makeBuiltinException(BoxedClass* base, const char* name, int
if (size == 0) if (size == 0)
size = base->tp_basicsize; size = base->tp_basicsize;
BoxedClass* cls = new BoxedHeapClass(base, NULL, offsetof(BoxedException, attrs), size, false, name); BoxedClass* cls = BoxedHeapClass::create(type_cls, base, NULL, offsetof(BoxedException, attrs), size, false, name);
cls->giveAttr("__module__", boxStrConstant("exceptions")); cls->giveAttr("__module__", boxStrConstant("exceptions"));
if (base == object_cls) { if (base == object_cls) {
...@@ -954,7 +954,8 @@ Box* pydumpAddr(Box* p) { ...@@ -954,7 +954,8 @@ Box* pydumpAddr(Box* p) {
void setupBuiltins() { void setupBuiltins() {
builtins_module = createModule("__builtin__", "__builtin__"); builtins_module = createModule("__builtin__", "__builtin__");
BoxedHeapClass* ellipsis_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(Box), false, "ellipsis"); BoxedHeapClass* ellipsis_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(Box), false, "ellipsis");
Box* Ellipsis = new (ellipsis_cls) Box(); Box* Ellipsis = new (ellipsis_cls) Box();
assert(Ellipsis->cls); assert(Ellipsis->cls);
gc::registerPermanentRoot(Ellipsis); gc::registerPermanentRoot(Ellipsis);
...@@ -967,7 +968,8 @@ void setupBuiltins() { ...@@ -967,7 +968,8 @@ void setupBuiltins() {
builtins_module->giveAttr( builtins_module->giveAttr(
"print", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)print, NONE, 0, 0, true, true), "print")); "print", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)print, NONE, 0, 0, true, true), "print"));
notimplemented_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(Box), false, "NotImplementedType"); notimplemented_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(Box), false, "NotImplementedType");
notimplemented_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)notimplementedRepr, STR, 1))); notimplemented_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)notimplementedRepr, STR, 1)));
notimplemented_cls->freeze(); notimplemented_cls->freeze();
NotImplemented = new (notimplemented_cls) Box(); NotImplemented = new (notimplemented_cls) Box();
...@@ -1046,8 +1048,8 @@ void setupBuiltins() { ...@@ -1046,8 +1048,8 @@ void setupBuiltins() {
builtins_module->giveAttr("__import__", new BoxedBuiltinFunctionOrMethod(import_func, "__import__", builtins_module->giveAttr("__import__", new BoxedBuiltinFunctionOrMethod(import_func, "__import__",
{ None, None, None, new BoxedInt(-1) })); { None, None, None, new BoxedInt(-1) }));
enumerate_cls enumerate_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedEnumerate::gcHandler, 0, sizeof(BoxedEnumerate),
= new BoxedHeapClass(object_cls, &BoxedEnumerate::gcHandler, 0, sizeof(BoxedEnumerate), false, "enumerate"); false, "enumerate");
enumerate_cls->giveAttr( enumerate_cls->giveAttr(
"__new__", "__new__",
new BoxedFunction(boxRTFunction((void*)BoxedEnumerate::new_, UNKNOWN, 3, 1, false, false), { boxInt(0) })); new BoxedFunction(boxRTFunction((void*)BoxedEnumerate::new_, UNKNOWN, 3, 1, false, false), { boxInt(0) }));
......
...@@ -294,7 +294,8 @@ void setupSys() { ...@@ -294,7 +294,8 @@ void setupSys() {
sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX)); sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX));
sys_flags_cls = new BoxedHeapClass(object_cls, BoxedSysFlags::gcHandler, 0, sizeof(BoxedSysFlags), false, "flags"); sys_flags_cls = BoxedHeapClass::create(type_cls, object_cls, BoxedSysFlags::gcHandler, 0, sizeof(BoxedSysFlags),
false, "flags");
sys_flags_cls->giveAttr("__new__", sys_flags_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)BoxedSysFlags::__new__, UNKNOWN, 1, 0, true, true))); new BoxedFunction(boxRTFunction((void*)BoxedSysFlags::__new__, UNKNOWN, 1, 0, true, true)));
#define ADD(name) \ #define ADD(name) \
......
...@@ -179,7 +179,7 @@ void setupThread() { ...@@ -179,7 +179,7 @@ void setupThread() {
thread_module->giveAttr( thread_module->giveAttr(
"stack_size", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)stackSize, BOXED_INT, 0), "stack_size")); "stack_size", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)stackSize, BOXED_INT, 0), "stack_size"));
thread_lock_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedThreadLock), false, "lock"); thread_lock_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedThreadLock), false, "lock");
thread_lock_cls->giveAttr("__module__", boxStrConstant("thread")); thread_lock_cls->giveAttr("__module__", boxStrConstant("thread"));
thread_lock_cls->giveAttr( thread_lock_cls->giveAttr(
"acquire", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::acquire, BOXED_BOOL, 2, 1, false, false), "acquire", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::acquire, BOXED_BOOL, 2, 1, false, false),
...@@ -191,13 +191,13 @@ void setupThread() { ...@@ -191,13 +191,13 @@ void setupThread() {
thread_lock_cls->giveAttr("__exit__", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::exit, NONE, 4))); thread_lock_cls->giveAttr("__exit__", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::exit, NONE, 4)));
thread_lock_cls->freeze(); thread_lock_cls->freeze();
thread_local_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedThreadLocal), false, "_local"); thread_local_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedThreadLocal), false, "_local");
thread_local_cls->giveAttr("__module__", boxStrConstant("thread")); thread_local_cls->giveAttr("__module__", boxStrConstant("thread"));
thread_local_cls->freeze(); thread_local_cls->freeze();
thread_module->giveAttr("_local", thread_local_cls); thread_module->giveAttr("_local", thread_local_cls);
BoxedClass* ThreadError BoxedClass* ThreadError = BoxedHeapClass::create(type_cls, Exception, NULL, Exception->attrs_offset,
= new BoxedHeapClass(Exception, NULL, Exception->attrs_offset, Exception->tp_basicsize, false, "error"); Exception->tp_basicsize, false, "error");
ThreadError->giveAttr("__module__", boxStrConstant("thread")); ThreadError->giveAttr("__module__", boxStrConstant("thread"));
ThreadError->freeze(); ThreadError->freeze();
......
...@@ -501,6 +501,8 @@ extern "C" Py_ssize_t PySequence_Index(PyObject* o, PyObject* value) noexcept { ...@@ -501,6 +501,8 @@ extern "C" Py_ssize_t PySequence_Index(PyObject* o, PyObject* value) noexcept {
extern "C" PyObject* PySequence_Tuple(PyObject* o) noexcept { extern "C" PyObject* PySequence_Tuple(PyObject* o) noexcept {
if (o->cls == tuple_cls) if (o->cls == tuple_cls)
return o; return o;
if (PyList_Check(o))
return PyList_AsTuple(o);
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
...@@ -1543,7 +1545,7 @@ static Box* methodGetDoc(Box* b, void*) { ...@@ -1543,7 +1545,7 @@ static Box* methodGetDoc(Box* b, void*) {
} }
void setupCAPI() { void setupCAPI() {
capifunc_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedCApiFunction), false, "capifunc"); capifunc_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedCApiFunction), false, "capifunc");
capifunc_cls->giveAttr("__repr__", capifunc_cls->giveAttr("__repr__",
new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1))); new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1)));
...@@ -1554,7 +1556,7 @@ void setupCAPI() { ...@@ -1554,7 +1556,7 @@ void setupCAPI() {
capifunc_cls->freeze(); capifunc_cls->freeze();
method_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedMethodDescriptor), false, "method"); method_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedMethodDescriptor), false, "method");
method_cls->giveAttr("__get__", method_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3))); new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3)));
method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2, method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2,
...@@ -1562,13 +1564,14 @@ void setupCAPI() { ...@@ -1562,13 +1564,14 @@ void setupCAPI() {
method_cls->giveAttr("__doc__", new (pyston_getset_cls) BoxedGetsetDescriptor(methodGetDoc, NULL, NULL)); method_cls->giveAttr("__doc__", new (pyston_getset_cls) BoxedGetsetDescriptor(methodGetDoc, NULL, NULL));
method_cls->freeze(); method_cls->freeze();
wrapperdescr_cls wrapperdescr_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedWrapperDescriptor), false,
= new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedWrapperDescriptor), false, "wrapper_descriptor"); "wrapper_descriptor");
wrapperdescr_cls->giveAttr("__get__", wrapperdescr_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3))); new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3)));
wrapperdescr_cls->freeze(); wrapperdescr_cls->freeze();
wrapperobject_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedWrapperObject), false, "method-wrapper"); wrapperobject_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedWrapperObject), false, "method-wrapper");
wrapperobject_cls->giveAttr( wrapperobject_cls->giveAttr(
"__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true))); "__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true)));
wrapperobject_cls->freeze(); wrapperobject_cls->freeze();
......
...@@ -270,10 +270,10 @@ Box* instanceSetitem(Box* _inst, Box* key, Box* value) { ...@@ -270,10 +270,10 @@ Box* instanceSetitem(Box* _inst, Box* key, Box* value) {
} }
void setupClassobj() { void setupClassobj() {
classobj_cls = new BoxedHeapClass(object_cls, &BoxedClassobj::gcHandler, offsetof(BoxedClassobj, attrs), classobj_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler,
sizeof(BoxedClassobj), false, "classobj"); offsetof(BoxedClassobj, attrs), sizeof(BoxedClassobj), false, "classobj");
instance_cls = new BoxedHeapClass(object_cls, &BoxedInstance::gcHandler, offsetof(BoxedInstance, attrs), instance_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedInstance::gcHandler,
sizeof(BoxedInstance), false, "instance"); offsetof(BoxedInstance, attrs), sizeof(BoxedInstance), false, "instance");
classobj_cls->giveAttr("__new__", classobj_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)classobjNew, UNKNOWN, 4, 0, false, false))); new BoxedFunction(boxRTFunction((void*)classobjNew, UNKNOWN, 4, 0, false, false)));
......
...@@ -572,13 +572,15 @@ static Box* dict_repr(PyObject* self) noexcept { ...@@ -572,13 +572,15 @@ static Box* dict_repr(PyObject* self) noexcept {
} }
void setupDict() { void setupDict() {
dict_iterator_cls = new BoxedHeapClass(object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict), false, dict_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict),
"dictionary-itemiterator"); false, "dictionary-itemiterator");
dict_keys_cls = new BoxedHeapClass(object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false, "dict_keys"); dict_keys_cls = BoxedHeapClass::create(type_cls, object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false,
dict_values_cls "dict_keys");
= new BoxedHeapClass(object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false, "dict_values"); dict_values_cls = BoxedHeapClass::create(type_cls, object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false,
dict_items_cls = new BoxedHeapClass(object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false, "dict_items"); "dict_values");
dict_items_cls = BoxedHeapClass::create(type_cls, object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false,
"dict_items");
dict_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)dictLen, BOXED_INT, 1))); dict_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)dictLen, BOXED_INT, 1)));
dict_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)dictNew, UNKNOWN, 1, 0, true, true))); dict_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)dictNew, UNKNOWN, 1, 0, true, true)));
......
...@@ -298,8 +298,8 @@ void generatorDestructor(Box* b) { ...@@ -298,8 +298,8 @@ void generatorDestructor(Box* b) {
} }
void setupGenerator() { void setupGenerator() {
generator_cls = new BoxedHeapClass(object_cls, &generatorGCHandler, offsetof(BoxedGenerator, attrs), generator_cls = BoxedHeapClass::create(type_cls, object_cls, &generatorGCHandler, offsetof(BoxedGenerator, attrs),
sizeof(BoxedGenerator), false, "generator"); sizeof(BoxedGenerator), false, "generator");
generator_cls->simple_destructor = generatorDestructor; generator_cls->simple_destructor = generatorDestructor;
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)));
......
...@@ -178,9 +178,9 @@ Box* xrangeReversed(Box* self) { ...@@ -178,9 +178,9 @@ Box* xrangeReversed(Box* self) {
} }
void setupXrange() { void setupXrange() {
xrange_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedXrange), false, "xrange"); xrange_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedXrange), false, "xrange");
xrange_iterator_cls = new BoxedHeapClass(object_cls, &BoxedXrangeIterator::xrangeIteratorGCHandler, 0, xrange_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedXrangeIterator::xrangeIteratorGCHandler, 0,
sizeof(BoxedXrangeIterator), false, "rangeiterator"); sizeof(BoxedXrangeIterator), false, "rangeiterator");
xrange_cls->giveAttr( xrange_cls->giveAttr(
"__new__", "__new__",
......
...@@ -141,7 +141,8 @@ extern "C" PyObject* PySeqIter_New(PyObject* seq) noexcept { ...@@ -141,7 +141,8 @@ extern "C" PyObject* PySeqIter_New(PyObject* seq) noexcept {
} }
void setupIter() { void setupIter() {
seqiter_cls = new BoxedHeapClass(object_cls, seqiterGCVisit, 0, sizeof(BoxedSeqIter), false, "iterator"); seqiter_cls
= BoxedHeapClass::create(type_cls, object_cls, seqiterGCVisit, 0, sizeof(BoxedSeqIter), false, "iterator");
seqiter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1))); seqiter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1)));
seqiter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqiterHasnext, BOXED_BOOL, 1))); seqiter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqiterHasnext, BOXED_BOOL, 1)));
...@@ -149,7 +150,7 @@ void setupIter() { ...@@ -149,7 +150,7 @@ void setupIter() {
seqiter_cls->freeze(); seqiter_cls->freeze();
seqreviter_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedSeqIter), false, "reversed"); seqreviter_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedSeqIter), false, "reversed");
seqreviter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1))); seqreviter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1)));
seqreviter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqreviterHasnext, BOXED_BOOL, 1))); seqreviter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqreviterHasnext, BOXED_BOOL, 1)));
...@@ -157,8 +158,8 @@ void setupIter() { ...@@ -157,8 +158,8 @@ void setupIter() {
seqreviter_cls->freeze(); seqreviter_cls->freeze();
iterwrapper_cls iterwrapper_cls = BoxedHeapClass::create(type_cls, object_cls, iterwrapperGCVisit, 0, sizeof(BoxedIterWrapper),
= new BoxedHeapClass(object_cls, iterwrapperGCVisit, 0, sizeof(BoxedIterWrapper), false, "iterwrapper"); false, "iterwrapper");
iterwrapper_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)iterwrapperNext, UNKNOWN, 1))); iterwrapper_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)iterwrapperNext, UNKNOWN, 1)));
iterwrapper_cls->giveAttr("__hasnext__", iterwrapper_cls->giveAttr("__hasnext__",
......
...@@ -49,6 +49,19 @@ extern "C" PyObject** PyList_Items(PyObject* op) noexcept { ...@@ -49,6 +49,19 @@ extern "C" PyObject** PyList_Items(PyObject* op) noexcept {
return &static_cast<BoxedList*>(op)->elts->elts[0]; return &static_cast<BoxedList*>(op)->elts->elts[0];
} }
extern "C" PyObject* PyList_AsTuple(PyObject* v) noexcept {
PyObject* w;
PyObject** p, **q;
Py_ssize_t n;
if (v == NULL || !PyList_Check(v)) {
PyErr_BadInternalCall();
return NULL;
}
auto l = static_cast<BoxedList*>(v);
return new BoxedTuple(BoxedTuple::GCVector(l->elts->elts, l->elts->elts + l->size));
}
extern "C" Box* listRepr(BoxedList* self) { extern "C" Box* listRepr(BoxedList* self) {
LOCK_REGION(self->lock.asRead()); LOCK_REGION(self->lock.asRead());
...@@ -751,10 +764,10 @@ extern "C" int PyList_SetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, P ...@@ -751,10 +764,10 @@ extern "C" int PyList_SetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, P
} }
void setupList() { void setupList() {
list_iterator_cls list_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &listIteratorGCHandler, 0, sizeof(BoxedList),
= new BoxedHeapClass(object_cls, &listIteratorGCHandler, 0, sizeof(BoxedList), false, "listiterator"); false, "listiterator");
list_reverse_iterator_cls = new BoxedHeapClass(object_cls, &listIteratorGCHandler, 0, sizeof(BoxedListIterator), list_reverse_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &listIteratorGCHandler, 0,
false, "listreverseiterator"); sizeof(BoxedListIterator), false, "listreverseiterator");
list_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)listLen, BOXED_INT, 1))); list_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)listLen, BOXED_INT, 1)));
......
...@@ -195,10 +195,11 @@ bool isInstance(Box* obj, BoxedClass* cls) { ...@@ -195,10 +195,11 @@ bool isInstance(Box* obj, BoxedClass* cls) {
extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent) { extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent) {
// TODO the class is allowed to override this using __subclasscheck__ // TODO the class is allowed to override this using __subclasscheck__
while (child) { assert(child->tp_mro);
if (child == parent) assert(child->tp_mro->cls == tuple_cls);
for (auto b : static_cast<BoxedTuple*>(child->tp_mro)->elts) {
if (b == parent)
return true; return true;
child = child->tp_base;
} }
return false; return false;
} }
...@@ -314,7 +315,10 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset ...@@ -314,7 +315,10 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
if (cls == NULL) { if (cls == NULL) {
assert(type_cls == NULL); assert(type_cls == NULL);
} else { } else {
assert(isSubclass(cls, type_cls)); // The (cls == type_cls) part of the check is important because during bootstrapping
// we might not have set up enough stuff in order to do proper subclass checking,
// but those clases will either have cls == NULL or cls == type_cls
assert(cls == type_cls || isSubclass(cls, type_cls));
} }
assert(tp_dealloc == NULL); assert(tp_dealloc == NULL);
...@@ -349,26 +353,23 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset ...@@ -349,26 +353,23 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
gc::registerPermanentRoot(this); gc::registerPermanentRoot(this);
} }
BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, void BoxedClass::finishInitialization() {
bool is_user_defined, const std::string& name) commonClassSetup(this);
: BoxedHeapClass(base, gc_visit, attrs_offset, instance_size, is_user_defined, new BoxedString(name)) {
} }
BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size,
bool is_user_defined) bool is_user_defined, BoxedString* name)
: BoxedClass(base, gc_visit, attrs_offset, instance_size, is_user_defined), ht_name(NULL), ht_slots(NULL) { : BoxedClass(base, gc_visit, attrs_offset, instance_size, is_user_defined), ht_name(name), ht_slots(NULL) {
// This constructor is only used for bootstrapping purposes to be called for types that
// are initialized before str_cls.
// Therefore, we assert that str_cls is uninitialized to make sure this isn't called at
// an inappropriate time.
assert(str_cls == NULL);
tp_as_number = &as_number; tp_as_number = &as_number;
tp_as_mapping = &as_mapping; tp_as_mapping = &as_mapping;
tp_as_sequence = &as_sequence; tp_as_sequence = &as_sequence;
tp_as_buffer = &as_buffer; tp_as_buffer = &as_buffer;
tp_flags |= Py_TPFLAGS_HEAPTYPE; tp_flags |= Py_TPFLAGS_HEAPTYPE;
if (!ht_name)
assert(str_cls == NULL);
else
tp_name = ht_name->s.c_str();
memset(&as_number, 0, sizeof(as_number)); memset(&as_number, 0, sizeof(as_number));
memset(&as_mapping, 0, sizeof(as_mapping)); memset(&as_mapping, 0, sizeof(as_mapping));
...@@ -376,21 +377,26 @@ BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attr ...@@ -376,21 +377,26 @@ BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attr
memset(&as_buffer, 0, sizeof(as_buffer)); memset(&as_buffer, 0, sizeof(as_buffer));
} }
BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, BoxedHeapClass* BoxedHeapClass::create(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
bool is_user_defined, BoxedString* name) int instance_size, bool is_user_defined, const std::string& name) {
: BoxedClass(base, gc_visit, attrs_offset, instance_size, is_user_defined), ht_name(name), ht_slots(NULL) { return create(metaclass, base, gc_visit, attrs_offset, instance_size, is_user_defined, new BoxedString(name), NULL);
}
tp_as_number = &as_number; BoxedHeapClass* BoxedHeapClass::create(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
tp_as_mapping = &as_mapping; int instance_size, bool is_user_defined, BoxedString* name, BoxedTuple* bases) {
tp_as_sequence = &as_sequence; BoxedHeapClass* made = new (metaclass)
tp_as_buffer = &as_buffer; BoxedHeapClass(base, gc_visit, attrs_offset, instance_size, is_user_defined, name);
tp_name = ht_name->s.c_str();
tp_flags |= Py_TPFLAGS_HEAPTYPE;
memset(&as_number, 0, sizeof(as_number)); // While it might be ok if these were set, it'd indicate a difference in
memset(&as_mapping, 0, sizeof(as_mapping)); // expectations as to who was going to calculate them:
memset(&as_sequence, 0, sizeof(as_sequence)); assert(!made->tp_mro);
memset(&as_buffer, 0, sizeof(as_buffer)); assert(!made->tp_bases);
made->tp_bases = bases;
made->finishInitialization();
assert(made->tp_mro);
return made;
} }
std::string getFullNameOfClass(BoxedClass* cls) { std::string getFullNameOfClass(BoxedClass* cls) {
...@@ -656,19 +662,45 @@ Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* re ...@@ -656,19 +662,45 @@ Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* re
RewriterVar* obj_saved = rewrite_args->obj; RewriterVar* obj_saved = rewrite_args->obj;
val = cls->getattr(attr, rewrite_args); auto _mro = cls->tp_mro;
assert(rewrite_args->out_success); assert(_mro->cls == tuple_cls);
if (!val and cls->tp_base) { BoxedTuple* mro = static_cast<BoxedTuple*>(_mro);
// Guarding approach:
// Guard on the value of the tp_mro slot, which should be a tuple and thus be
// immutable. Then we don't have to figure out the guards to emit that check
// the individual mro entries.
// We can probably move this guard to after we call getattr() on the given cls.
//
// TODO this can fail if we replace the mro with another mro that lives in the same
// address.
obj_saved->addAttrGuard(offsetof(BoxedClass, tp_mro), (intptr_t)mro);
for (auto base : mro->elts) {
rewrite_args->out_success = false; rewrite_args->out_success = false;
rewrite_args->obj = obj_saved->getAttr(offsetof(BoxedClass, tp_base)); if (base == cls) {
val = typeLookup(cls->tp_base, attr, rewrite_args); // Small optimization: don't have to load the class again since it was given to us in
// a register.
assert(rewrite_args->obj == obj_saved);
} else {
rewrite_args->obj = rewrite_args->rewriter->loadConst((intptr_t)base, Location::any());
}
val = base->getattr(attr, rewrite_args);
assert(rewrite_args->out_success);
if (val)
return val;
} }
return val;
return NULL;
} else { } else {
val = cls->getattr(attr, NULL); assert(cls->tp_mro);
if (!val and cls->tp_base) assert(cls->tp_mro->cls == tuple_cls);
return typeLookup(cls->tp_base, attr, NULL); for (auto b : static_cast<BoxedTuple*>(cls->tp_mro)->elts) {
return val; val = b->getattr(attr, NULL);
if (val)
return val;
}
return NULL;
} }
} }
...@@ -1521,9 +1553,8 @@ extern "C" Box* getattr(Box* obj, const char* attr) { ...@@ -1521,9 +1553,8 @@ extern "C" Box* getattr(Box* obj, const char* attr) {
// This doesn't belong here either: // This doesn't belong here either:
if (strcmp(attr, "__bases__") == 0 && isSubclass(obj->cls, type_cls)) { if (strcmp(attr, "__bases__") == 0 && isSubclass(obj->cls, type_cls)) {
BoxedClass* cls = static_cast<BoxedClass*>(obj); BoxedClass* cls = static_cast<BoxedClass*>(obj);
if (cls->tp_base) assert(cls->tp_bases);
return new BoxedTuple({ static_cast<BoxedClass*>(obj)->tp_base }); return cls->tp_bases;
return EmptyTuple;
} }
} }
...@@ -2031,10 +2062,16 @@ extern "C" void dump(void* p) { ...@@ -2031,10 +2062,16 @@ extern "C" void dump(void* p) {
auto cls = static_cast<BoxedClass*>(b); auto cls = static_cast<BoxedClass*>(b);
printf("Type name: %s\n", getFullNameOfClass(cls).c_str()); printf("Type name: %s\n", getFullNameOfClass(cls).c_str());
printf("MRO: %s", getFullNameOfClass(cls).c_str()); printf("MRO:");
while (cls->tp_base) {
printf(" -> %s", getFullNameOfClass(cls->tp_base).c_str()); if (cls->tp_mro && cls->tp_mro->cls == tuple_cls) {
cls = cls->tp_base; bool first = true;
for (auto b : static_cast<BoxedTuple*>(cls->tp_mro)->elts) {
if (!first)
printf(" ->");
first = false;
printf(" %s", getFullNameOfClass(static_cast<BoxedClass*>(b)).c_str());
}
} }
printf("\n"); printf("\n");
} }
...@@ -3572,10 +3609,10 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) { ...@@ -3572,10 +3609,10 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
if (!isSubclass(_cls->cls, type_cls)) if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "type.__new__(X): X is not a type object (%s)", getTypeName(_cls)); raiseExcHelper(TypeError, "type.__new__(X): X is not a type object (%s)", getTypeName(_cls));
BoxedClass* cls = static_cast<BoxedClass*>(_cls); BoxedClass* metatype = static_cast<BoxedClass*>(_cls);
if (!isSubclass(cls, type_cls)) if (!isSubclass(metatype, type_cls))
raiseExcHelper(TypeError, "type.__new__(%s): %s is not a subtype of type", getNameOfClass(cls), raiseExcHelper(TypeError, "type.__new__(%s): %s is not a subtype of type", getNameOfClass(metatype),
getNameOfClass(cls)); getNameOfClass(metatype));
if (arg2 == NULL) { if (arg2 == NULL) {
assert(arg3 == NULL); assert(arg3 == NULL);
...@@ -3592,30 +3629,65 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) { ...@@ -3592,30 +3629,65 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
RELEASE_ASSERT(arg1->cls == str_cls, ""); RELEASE_ASSERT(arg1->cls == str_cls, "");
BoxedString* name = static_cast<BoxedString*>(arg1); BoxedString* name = static_cast<BoxedString*>(arg1);
BoxedClass* base;
if (bases->elts.size() == 0) { if (bases->elts.size() == 0) {
bases = new BoxedTuple({ object_cls }); bases = new BoxedTuple({ object_cls });
} }
RELEASE_ASSERT(bases->elts.size() == 1, ""); // Ported from CPython:
Box* _base = bases->elts[0]; int nbases = bases->elts.size();
RELEASE_ASSERT(isSubclass(_base->cls, type_cls), ""); BoxedClass* winner = metatype;
base = static_cast<BoxedClass*>(_base); for (auto tmp : bases->elts) {
auto tmptype = tmp->cls;
if (tmptype == classobj_cls)
continue;
if (isSubclass(winner, tmptype))
continue;
if (isSubclass(tmptype, winner)) {
winner = tmptype;
continue;
}
raiseExcHelper(TypeError, "metaclass conflict: "
"the metaclass of a derived class "
"must be a (non-strict) subclass "
"of the metaclasses of all its bases");
}
if ((base->tp_flags & Py_TPFLAGS_BASETYPE) == 0) if (winner != metatype) {
if (getattr(winner, "__new__") != getattr(type_cls, "__new__")) {
RELEASE_ASSERT(0, "untested");
return callattr(winner, &new_str, CallattrFlags({.cls_only = true, .null_on_nonexistent = false }),
ArgPassSpec(3), arg1, arg2, arg3, _args + 1, NULL);
}
metatype = winner;
}
BoxedClass* base = best_base(bases);
checkAndThrowCAPIException();
assert(base);
if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE))
raiseExcHelper(TypeError, "type '%.100s' is not an acceptable base type", base->tp_name); raiseExcHelper(TypeError, "type '%.100s' is not an acceptable base type", base->tp_name);
assert(isSubclass(base->cls, type_cls));
// TODO I don't think we have to implement the __slots__ memory savings behavior
// (we get almost all of that automatically with hidden classes), but adding a __slots__
// adds other restrictions (ex for multiple inheritance) that we won't end up enforcing.
// I guess it should be ok if we're more permissive?
// auto slots = PyDict_GetItemString(attr_dict, "__slots__");
// RELEASE_ASSERT(!slots, "__slots__ unsupported");
BoxedClass* made; BoxedClass* made;
if (base->instancesHaveDictAttrs() || base->instancesHaveHCAttrs()) { if (base->instancesHaveDictAttrs() || base->instancesHaveHCAttrs()) {
made = new (cls) BoxedHeapClass(base, NULL, base->attrs_offset, base->tp_basicsize, true, name); made = BoxedHeapClass::create(metatype, base, NULL, base->attrs_offset, base->tp_basicsize, true, name, bases);
} else { } else {
assert(base->tp_basicsize % sizeof(void*) == 0); assert(base->tp_basicsize % sizeof(void*) == 0);
made = new (cls) made = BoxedHeapClass::create(metatype, base, NULL, base->tp_basicsize, base->tp_basicsize + sizeof(HCAttrs),
BoxedHeapClass(base, NULL, base->tp_basicsize, base->tp_basicsize + sizeof(HCAttrs), true, name); true, name, bases);
} }
// TODO: how much of these should be in BoxedClass::finishInitialization()?
made->tp_dictoffset = base->tp_dictoffset; made->tp_dictoffset = base->tp_dictoffset;
for (const auto& p : attr_dict->d) { for (const auto& p : attr_dict->d) {
...@@ -3630,7 +3702,6 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) { ...@@ -3630,7 +3702,6 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
made->tp_new = base->tp_new; made->tp_new = base->tp_new;
PystonType_Ready(made);
fixup_slot_dispatchers(made); fixup_slot_dispatchers(made);
if (base->tp_alloc == &PystonType_GenericAlloc) if (base->tp_alloc == &PystonType_GenericAlloc)
......
...@@ -246,7 +246,8 @@ Box* setNonzero(BoxedSet* self) { ...@@ -246,7 +246,8 @@ Box* setNonzero(BoxedSet* self) {
using namespace pyston::set; using namespace pyston::set;
void setupSet() { void setupSet() {
set_iterator_cls = new BoxedHeapClass(object_cls, &setIteratorGCHandler, 0, sizeof(BoxedSet), false, "setiterator"); set_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &setIteratorGCHandler, 0, sizeof(BoxedSet), false,
"setiterator");
set_iterator_cls->giveAttr("__hasnext__", set_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)setiteratorHasnext, BOXED_BOOL, 1))); new BoxedFunction(boxRTFunction((void*)setiteratorHasnext, BOXED_BOOL, 1)));
set_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)setiteratorNext, UNKNOWN, 1))); set_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)setiteratorNext, UNKNOWN, 1)));
......
...@@ -2208,8 +2208,8 @@ void setupStr() { ...@@ -2208,8 +2208,8 @@ void setupStr() {
str_cls->simple_destructor = strDestructor; str_cls->simple_destructor = strDestructor;
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
str_iterator_cls str_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &strIteratorGCHandler, 0,
= new BoxedHeapClass(object_cls, &strIteratorGCHandler, 0, sizeof(BoxedStringIterator), false, "striterator"); sizeof(BoxedStringIterator), false, "striterator");
str_iterator_cls->giveAttr("__hasnext__", str_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::hasnext, BOXED_BOOL, 1))); new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::hasnext, BOXED_BOOL, 1)));
str_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::next, STR, 1))); str_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::next, STR, 1)));
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <sstream> #include <sstream>
#include "capi/types.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
...@@ -66,15 +67,68 @@ Box* superGetattribute(Box* _s, Box* _attr) { ...@@ -66,15 +67,68 @@ Box* superGetattribute(Box* _s, Box* _attr) {
} }
if (!skip) { if (!skip) {
// We don't support multiple inheritance yet, so the lookup order is simple: PyObject* mro, *res, *tmp, *dict;
Box* r = typeLookup(s->type->tp_base, attr->s, NULL); PyTypeObject* starttype;
descrgetfunc f;
if (r) { Py_ssize_t i, n;
return processDescriptor(r, (s->obj == s->obj_type ? None : s->obj), s->obj_type);
starttype = s->obj_type;
mro = starttype->tp_mro;
if (mro == NULL)
n = 0;
else {
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
}
for (i = 0; i < n; i++) {
if ((PyObject*)(s->type) == PyTuple_GET_ITEM(mro, i))
break;
}
i++;
res = NULL;
for (; i < n; i++) {
tmp = PyTuple_GET_ITEM(mro, i);
// Pyston change:
#if 0
if (PyType_Check(tmp))
dict = ((PyTypeObject *)tmp)->tp_dict;
else if (PyClass_Check(tmp))
dict = ((PyClassObject *)tmp)->cl_dict;
else
continue;
res = PyDict_GetItem(dict, name);
#endif
res = tmp->getattr(attr->s);
if (res != NULL) {
// Pyston change:
#if 0
Py_INCREF(res);
f = Py_TYPE(res)->tp_descr_get;
if (f != NULL) {
tmp = f(res,
/* Only pass 'obj' param if
this is instance-mode sper
(See SF ID #743627)
*/
(s->obj == (PyObject *)
s->obj_type
? (PyObject *)NULL
: s->obj),
(PyObject *)starttype);
Py_DECREF(res);
res = tmp;
}
#endif
return processDescriptor(res, (s->obj == s->obj_type ? None : s->obj), s->obj_type);
}
} }
} }
Box* r = typeLookup(s->cls, attr->s, NULL); Box* r = typeLookup(s->cls, attr->s, NULL);
// TODO implement this
RELEASE_ASSERT(r, "should call the equivalent of objectGetattr here"); RELEASE_ASSERT(r, "should call the equivalent of objectGetattr here");
return processDescriptor(r, s, s->cls); return processDescriptor(r, s, s->cls);
} }
...@@ -132,7 +186,8 @@ Box* superInit(Box* _self, Box* _type, Box* obj) { ...@@ -132,7 +186,8 @@ Box* superInit(Box* _self, Box* _type, Box* obj) {
} }
void setupSuper() { void setupSuper() {
super_cls = new BoxedHeapClass(object_cls, &BoxedSuper::gcHandler, 0, sizeof(BoxedSuper), false, "super"); super_cls
= BoxedHeapClass::create(type_cls, object_cls, &BoxedSuper::gcHandler, 0, sizeof(BoxedSuper), false, "super");
super_cls->giveAttr("__getattribute__", new BoxedFunction(boxRTFunction((void*)superGetattribute, UNKNOWN, 2))); super_cls->giveAttr("__getattribute__", new BoxedFunction(boxRTFunction((void*)superGetattribute, UNKNOWN, 2)));
super_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)superRepr, STR, 1))); super_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)superRepr, STR, 1)));
......
...@@ -107,8 +107,8 @@ Box* BoxedTraceback::getLines(Box* b) { ...@@ -107,8 +107,8 @@ Box* BoxedTraceback::getLines(Box* b) {
} }
void setupTraceback() { void setupTraceback() {
traceback_cls traceback_cls = BoxedHeapClass::create(type_cls, object_cls, BoxedTraceback::gcHandler, 0, sizeof(BoxedTraceback),
= new BoxedHeapClass(object_cls, BoxedTraceback::gcHandler, 0, sizeof(BoxedTraceback), false, "traceback"); false, "traceback");
traceback_cls->giveAttr("getLines", new BoxedFunction(boxRTFunction((void*)BoxedTraceback::getLines, UNKNOWN, 1))); traceback_cls->giveAttr("getLines", new BoxedFunction(boxRTFunction((void*)BoxedTraceback::getLines, UNKNOWN, 1)));
......
...@@ -386,7 +386,8 @@ extern "C" void tupleIteratorGCHandler(GCVisitor* v, Box* b) { ...@@ -386,7 +386,8 @@ extern "C" void tupleIteratorGCHandler(GCVisitor* v, Box* b) {
void setupTuple() { void setupTuple() {
tuple_iterator_cls = new BoxedHeapClass(object_cls, &tupleIteratorGCHandler, 0, sizeof(BoxedTuple), false, "tuple"); tuple_iterator_cls
= BoxedHeapClass::create(type_cls, object_cls, &tupleIteratorGCHandler, 0, sizeof(BoxedTuple), false, "tuple");
tuple_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)tupleNew, UNKNOWN, 1, 0, true, true))); tuple_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)tupleNew, UNKNOWN, 1, 0, true, true)));
CLFunction* getitem = createRTFunction(2, 0, 0, 0); CLFunction* getitem = createRTFunction(2, 0, 0, 0);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <sstream> #include <sstream>
#include <stdint.h> #include <stdint.h>
#include "capi/typeobject.h"
#include "core/options.h" #include "core/options.h"
#include "core/stats.h" #include "core/stats.h"
#include "core/types.h" #include "core/types.h"
...@@ -96,10 +97,16 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems) ...@@ -96,10 +97,16 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
assert(static_cast<BoxedClass*>(e)->is_pyston_class); assert(static_cast<BoxedClass*>(e)->is_pyston_class);
} }
#endif #endif
BoxedClass* b = cls; if (!cls->tp_mro) {
while (b) { assert(!list_cls);
ASSERT(b->is_pyston_class, "%s (%s)", cls->tp_name, b->tp_name); } else {
b = b->tp_base; assert(cls->tp_mro && "maybe we should just skip these checks if !mro");
assert(cls->tp_mro->cls == tuple_cls);
for (auto b : static_cast<BoxedTuple*>(cls->tp_mro)->elts) {
assert(isSubclass(b->cls, type_cls));
ASSERT(static_cast<BoxedClass*>(b)->is_pyston_class, "%s (%s)", cls->tp_name,
static_cast<BoxedClass*>(b)->tp_name);
}
} }
#endif #endif
...@@ -405,6 +412,10 @@ extern "C" void typeGCHandler(GCVisitor* v, Box* b) { ...@@ -405,6 +412,10 @@ extern "C" void typeGCHandler(GCVisitor* v, Box* b) {
v->visit(cls->tp_base); v->visit(cls->tp_base);
if (cls->tp_dict) if (cls->tp_dict)
v->visit(cls->tp_dict); v->visit(cls->tp_dict);
if (cls->tp_mro)
v->visit(cls->tp_mro);
if (cls->tp_bases)
v->visit(cls->tp_bases);
if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) { if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
BoxedHeapClass* hcls = static_cast<BoxedHeapClass*>(cls); BoxedHeapClass* hcls = static_cast<BoxedHeapClass*>(cls);
...@@ -898,6 +909,15 @@ Box* typeHash(BoxedClass* self) { ...@@ -898,6 +909,15 @@ Box* typeHash(BoxedClass* self) {
return boxInt(reinterpret_cast<intptr_t>(self) >> 4); return boxInt(reinterpret_cast<intptr_t>(self) >> 4);
} }
Box* typeMro(BoxedClass* self) {
assert(isSubclass(self->cls, type_cls));
Box* r = mro_external(self);
if (!r)
throwCAPIException();
return r;
}
Box* moduleRepr(BoxedModule* m) { Box* moduleRepr(BoxedModule* m) {
assert(m->cls == module_cls); assert(m->cls == module_cls);
...@@ -1220,20 +1240,19 @@ void setupRuntime() { ...@@ -1220,20 +1240,19 @@ void setupRuntime() {
object_cls = ::new (mem) BoxedClass(NULL, &boxGCHandler, 0, sizeof(Box), false); object_cls = ::new (mem) BoxedClass(NULL, &boxGCHandler, 0, sizeof(Box), false);
mem = gc_alloc(sizeof(BoxedHeapClass), gc::GCKind::PYTHON); mem = gc_alloc(sizeof(BoxedHeapClass), gc::GCKind::PYTHON);
type_cls = ::new (mem) type_cls = ::new (mem)
BoxedHeapClass(object_cls, &typeGCHandler, offsetof(BoxedClass, attrs), sizeof(BoxedHeapClass), false); BoxedHeapClass(object_cls, &typeGCHandler, offsetof(BoxedClass, attrs), sizeof(BoxedHeapClass), false, NULL);
PyObject_Init(object_cls, type_cls); PyObject_Init(object_cls, type_cls);
PyObject_Init(type_cls, type_cls); PyObject_Init(type_cls, type_cls);
none_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(Box), false); none_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(Box), false, NULL);
None = new (none_cls) Box(); None = new (none_cls) Box();
assert(None->cls); assert(None->cls);
gc::registerPermanentRoot(None); gc::registerPermanentRoot(None);
// You can't actually have an instance of basestring // You can't actually have an instance of basestring
basestring_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(Box), false); basestring_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(Box), false, NULL);
// TODO we leak all the string data! str_cls = new BoxedHeapClass(basestring_cls, NULL, 0, sizeof(BoxedString), false, NULL);
str_cls = new BoxedHeapClass(basestring_cls, NULL, 0, sizeof(BoxedString), false);
// Hold off on assigning names until str_cls is ready // Hold off on assigning names until str_cls is ready
object_cls->tp_name = "object"; object_cls->tp_name = "object";
...@@ -1260,54 +1279,75 @@ void setupRuntime() { ...@@ -1260,54 +1279,75 @@ void setupRuntime() {
object_cls->giveAttr("__base__", None); object_cls->giveAttr("__base__", None);
tuple_cls = new BoxedHeapClass(object_cls, &tupleGCHandler, 0, sizeof(BoxedTuple), false, "tuple"); tuple_cls = new BoxedHeapClass(object_cls, &tupleGCHandler, 0, sizeof(BoxedTuple), false, boxStrConstant("tuple"));
EmptyTuple = new BoxedTuple({}); EmptyTuple = new BoxedTuple({});
gc::registerPermanentRoot(EmptyTuple); gc::registerPermanentRoot(EmptyTuple);
list_cls = new BoxedHeapClass(object_cls, &listGCHandler, 0, sizeof(BoxedList), false, boxStrConstant("list"));
// Kind of hacky, but it's easier to manually construct the mro for a couple key classes
// than try to make the MRO construction code be safe against say, tuple_cls not having
// an mro (since the mro is stored as a tuple).
tuple_cls->tp_mro = new BoxedTuple({ tuple_cls, object_cls });
list_cls->tp_mro = new BoxedTuple({ list_cls, object_cls });
type_cls->tp_mro = new BoxedTuple({ type_cls, object_cls });
object_cls->finishInitialization();
type_cls->finishInitialization();
basestring_cls->finishInitialization();
str_cls->finishInitialization();
none_cls->finishInitialization();
tuple_cls->finishInitialization();
list_cls->finishInitialization();
module_cls module_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, offsetof(BoxedModule, attrs), sizeof(BoxedModule),
= new BoxedHeapClass(object_cls, NULL, offsetof(BoxedModule, attrs), sizeof(BoxedModule), false, "module"); false, "module");
// TODO it'd be nice to be able to do these in the respective setupType methods, // TODO it'd be nice to be able to do these in the respective setupType methods,
// but those setup methods probably want access to these objects. // but those setup methods probably want access to these objects.
// We could have a multi-stage setup process, but that seems overkill for now. // We could have a multi-stage setup process, but that seems overkill for now.
int_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedInt), false, "int"); int_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedInt), false, "int");
bool_cls = new BoxedHeapClass(int_cls, NULL, 0, sizeof(BoxedBool), false, "bool"); bool_cls = BoxedHeapClass::create(type_cls, int_cls, NULL, 0, sizeof(BoxedBool), false, "bool");
complex_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedComplex), false, "complex"); complex_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedComplex), false, "complex");
long_cls = new BoxedHeapClass(object_cls, &BoxedLong::gchandler, 0, sizeof(BoxedLong), false, "long"); long_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedLong::gchandler, 0, sizeof(BoxedLong), false, "long");
float_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedFloat), false, "float"); float_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedFloat), false, "float");
function_cls = new BoxedHeapClass(object_cls, &functionGCHandler, offsetof(BoxedFunction, attrs), function_cls = BoxedHeapClass::create(type_cls, object_cls, &functionGCHandler, offsetof(BoxedFunction, attrs),
sizeof(BoxedFunction), false, "function"); sizeof(BoxedFunction), false, "function");
function_cls->tp_weaklistoffset = offsetof(BoxedFunction, in_weakreflist); function_cls->tp_weaklistoffset = offsetof(BoxedFunction, in_weakreflist);
builtin_function_or_method_cls builtin_function_or_method_cls = BoxedHeapClass::create(
= new BoxedHeapClass(object_cls, &functionGCHandler, offsetof(BoxedBuiltinFunctionOrMethod, attrs), type_cls, object_cls, &functionGCHandler, offsetof(BoxedBuiltinFunctionOrMethod, attrs),
sizeof(BoxedBuiltinFunctionOrMethod), false, "builtin_function_or_method"); sizeof(BoxedBuiltinFunctionOrMethod), false, "builtin_function_or_method");
builtin_function_or_method_cls->tp_weaklistoffset = offsetof(BoxedBuiltinFunctionOrMethod, in_weakreflist); builtin_function_or_method_cls->tp_weaklistoffset = offsetof(BoxedBuiltinFunctionOrMethod, in_weakreflist);
function_cls->simple_destructor = builtin_function_or_method_cls->simple_destructor = functionDtor; function_cls->simple_destructor = builtin_function_or_method_cls->simple_destructor = functionDtor;
instancemethod_cls = new BoxedHeapClass(object_cls, &instancemethodGCHandler, 0, sizeof(BoxedInstanceMethod), false, instancemethod_cls = BoxedHeapClass::create(type_cls, object_cls, &instancemethodGCHandler, 0,
"instancemethod"); sizeof(BoxedInstanceMethod), false, "instancemethod");
instancemethod_cls->tp_weaklistoffset = offsetof(BoxedInstanceMethod, in_weakreflist); instancemethod_cls->tp_weaklistoffset = offsetof(BoxedInstanceMethod, in_weakreflist);
list_cls = new BoxedHeapClass(object_cls, &listGCHandler, 0, sizeof(BoxedList), false, "list"); list_cls = BoxedHeapClass::create(type_cls, object_cls, &listGCHandler, 0, sizeof(BoxedList), false, "list");
slice_cls = new BoxedHeapClass(object_cls, &sliceGCHandler, 0, sizeof(BoxedSlice), false, "slice"); slice_cls = BoxedHeapClass::create(type_cls, object_cls, &sliceGCHandler, 0, sizeof(BoxedSlice), false, "slice");
dict_cls = new BoxedHeapClass(object_cls, &dictGCHandler, 0, sizeof(BoxedDict), false, "dict"); dict_cls = BoxedHeapClass::create(type_cls, object_cls, &dictGCHandler, 0, sizeof(BoxedDict), false, "dict");
file_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedFile), false, "file"); file_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedFile), false, "file");
set_cls = new BoxedHeapClass(object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "set"); set_cls = BoxedHeapClass::create(type_cls, object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "set");
frozenset_cls = new BoxedHeapClass(object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "frozenset"); frozenset_cls
member_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false, "member"); = BoxedHeapClass::create(type_cls, object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "frozenset");
pyston_getset_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset"); member_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false, "member");
capi_getset_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset"); pyston_getset_cls
closure_cls = new BoxedHeapClass(object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs), sizeof(BoxedClosure), = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
false, "closure"); capi_getset_cls
property_cls = new BoxedHeapClass(object_cls, &propertyGCHandler, 0, sizeof(BoxedProperty), false, "property"); = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
staticmethod_cls closure_cls = BoxedHeapClass::create(type_cls, object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs),
= new BoxedHeapClass(object_cls, &staticmethodGCHandler, 0, sizeof(BoxedStaticmethod), false, "staticmethod"); sizeof(BoxedClosure), false, "closure");
classmethod_cls property_cls
= new BoxedHeapClass(object_cls, &classmethodGCHandler, 0, sizeof(BoxedClassmethod), false, "classmethod"); = BoxedHeapClass::create(type_cls, object_cls, &propertyGCHandler, 0, sizeof(BoxedProperty), false, "property");
attrwrapper_cls staticmethod_cls = BoxedHeapClass::create(type_cls, object_cls, &staticmethodGCHandler, 0,
= new BoxedHeapClass(object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper), false, "attrwrapper"); sizeof(BoxedStaticmethod), false, "staticmethod");
classmethod_cls = BoxedHeapClass::create(type_cls, object_cls, &classmethodGCHandler, 0, sizeof(BoxedClassmethod),
false, "classmethod");
attrwrapper_cls = BoxedHeapClass::create(type_cls, object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper),
false, "attrwrapper");
// TODO: add explicit __get__ and __set__ methods to these // TODO: add explicit __get__ and __set__ methods to these
pyston_getset_cls->freeze(); pyston_getset_cls->freeze();
...@@ -1345,6 +1385,9 @@ void setupRuntime() { ...@@ -1345,6 +1385,9 @@ void setupRuntime() {
type_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)typeRepr, STR, 1))); type_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)typeRepr, STR, 1)));
type_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)typeHash, BOXED_INT, 1))); type_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)typeHash, BOXED_INT, 1)));
type_cls->giveAttr("__module__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeModule, typeSetModule, NULL)); type_cls->giveAttr("__module__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeModule, typeSetModule, NULL));
type_cls->giveAttr("__mro__",
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedClass, tp_mro)));
type_cls->giveAttr("mro", new BoxedFunction(boxRTFunction((void*)typeMro, UNKNOWN, 1)));
type_cls->freeze(); type_cls->freeze();
none_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)noneRepr, STR, 1))); none_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)noneRepr, STR, 1)));
......
...@@ -192,9 +192,15 @@ public: ...@@ -192,9 +192,15 @@ public:
void freeze(); void freeze();
protected:
// These functions are not meant for external callers and will mostly just be called
// by BoxedHeapClass::create(), but setupRuntime() also needs to do some manual class
// creation due to bootstrapping issues.
void finishInitialization();
BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined); BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined);
DEFAULT_CLASS(type_cls); friend void setupRuntime();
}; };
class BoxedHeapClass : public BoxedClass { class BoxedHeapClass : public BoxedClass {
...@@ -207,15 +213,22 @@ public: ...@@ -207,15 +213,22 @@ public:
BoxedString* ht_name; BoxedString* ht_name;
PyObject** ht_slots; PyObject** ht_slots;
BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined, // These functions are the preferred way to construct new types:
const std::string& name); static BoxedHeapClass* create(BoxedClass* metatype, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int instance_size, bool is_user_defined, BoxedString* name, BoxedTuple* bases);
static BoxedHeapClass* create(BoxedClass* metatype, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int instance_size, bool is_user_defined, const std::string& name);
private:
// These functions are not meant for external callers and will mostly just be called
// by BoxedHeapClass::create(), but setupRuntime() also needs to do some manual class
// creation due to bootstrapping issues.
BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined, BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined,
BoxedString* name); BoxedString* name);
// This constructor is only used for bootstrapping purposes to be called for types that friend void setupRuntime();
// are initialized before str_cls.
BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined); DEFAULT_CLASS(type_cls);
}; };
static_assert(sizeof(pyston::Box) == sizeof(struct _object), ""); static_assert(sizeof(pyston::Box) == sizeof(struct _object), "");
......
# Testing the basic multiple-inheritance rules and functionality:
class C(object):
n = 1
def c(self):
print "C.c()"
def f(self):
print "C.f()", self.n
class D(object):
n = 2
def d(self):
print "D.d()"
def f(self):
print "D.f()", self.n
class E(C, D):
pass
class F(D, C):
pass
class G(E, D):
pass
for o in [C(), D(), E(), F()]:
print type(o), type(o).mro(), type(o).__mro__
o.f()
try:
o.c()
except Exception, e:
print e
try:
o.d()
except Exception, e:
print e
# Testing invalid multiple inheritance hierarchies:
# Conflicting MRO:
try:
class G(E, F):
pass
except TypeError, e:
# This is silly but I think actually reasonable: the error message for this case is implementation-specific,
# since it depends on dict ordering rules (says either "for bases E, F" or "for bases F, E", depending on ordering).
# Canonicalize the error message by sorting the characters in it:
print ''.join(sorted(e.message)).strip()
# Conflicting MRO:
try:
class H(C, F):
pass
except TypeError, e:
print ''.join(sorted(e.message)).strip()
# "instance lay-out conflict"
try:
class I(str, int):
pass
except TypeError, e:
print e
# Testing the way super() behaves with multiple inheritance:
class S(C, D):
n = 3
def c(self):
print "S.c()"
super(S, self).c()
def d(self):
print "S.d()"
super(S, self).d()
def f(self):
print "S.f()"
print self.n, super(S, self).n, super(C, self).n
# TODO: Pyston doesn't support the full super.__getattribute__, so this will abort
# rather than throw an exception:
# try:
# print super(D, self).n
# except Exception as e:
# print e
super(S, self).f()
super(C, self).f()
s = S()
s.c()
s.d()
s.f()
for cls in [object, tuple, list, type, int, bool]:
print cls.__mro__
...@@ -5,6 +5,9 @@ class B(object): ...@@ -5,6 +5,9 @@ class B(object):
o.arg1 = arg1 o.arg1 = arg1
return o return o
def f(self):
print "B.f()"
class C(B): class C(B):
def __new__(cls, arg1, arg2): def __new__(cls, arg1, arg2):
print "C.__new__", arg2 print "C.__new__", arg2
...@@ -13,9 +16,14 @@ class C(B): ...@@ -13,9 +16,14 @@ class C(B):
print super(C, cls), super(C, o) print super(C, cls), super(C, o)
return o return o
def f(self):
print "C.f()"
super(C, self).f()
c = C(1, 2) c = C(1, 2)
print c.arg1 print c.arg1
print c.arg2 print c.arg2
c.f()
try: try:
super(1) super(1)
......
...@@ -413,16 +413,16 @@ if __name__ == "__main__": ...@@ -413,16 +413,16 @@ if __name__ == "__main__":
] ]
tests += big_tests tests += big_tests
LIB_DIR = os.path.join(sys.prefix, "lib/python2.7")
for t in tests: for t in tests:
bn = os.path.basename(t) bn = os.path.basename(t)
assert bn.endswith(".py") assert bn.endswith(".py")
module_name = bn[:-3] module_name = bn[:-3]
try:
__import__(module_name) if os.path.exists(os.path.join(LIB_DIR, module_name)) or \
os.path.exists(os.path.join(LIB_DIR, module_name + ".py")) or \
module_name in sys.builtin_module_names:
raise Exception("Error: %s hides builtin module '%s'" % (t, module_name)) raise Exception("Error: %s hides builtin module '%s'" % (t, module_name))
except ImportError:
pass
# good
for t in TOSKIP: for t in TOSKIP:
assert t in ("%s/t.py" % TEST_DIR, "%s/t2.py" % TEST_DIR) or t in tests, t assert t in ("%s/t.py" % TEST_DIR, "%s/t2.py" % TEST_DIR) or t in tests, t
......
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