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

Merge branch 'multiple_inheritance'

parents 53dc9612 fee6818c
......@@ -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:
$(MAKE) pyston_prof
@# 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 -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -q $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -qn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -qO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(MAKE) check_release
echo "All tests passed"
quick_check:
$(MAKE) pyston_dbg
$(call checksha,./pyston_dbg -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_dbg -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_dbg -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_dbg -q $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_dbg -qn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_dbg -qO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(MAKE) pyston
$(call checksha,./pyston -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston -q $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston -qn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston -qO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(MAKE) pyston_prof
$(call checksha,./pyston_prof -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -q $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -qn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -qO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
Makefile.local:
echo "Creating default Makefile.local"
......
......@@ -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) {
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)) {
assembler::Register reg = allocReg(Location::any(), /* otherThan */ var_reg);
assert(reg != var_reg);
......@@ -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) {
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
// in the same register as ptr
......
......@@ -293,15 +293,16 @@ extern "C" PyObject* PyObject_CallFunctionObjArgs(PyObject* callable, ...) noexc
}
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
// won't end up doing a GIL check?
// threading::GLDemoteRegion _gil_demote;
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;
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
......
......@@ -82,7 +82,7 @@ static int _ustrlen(Py_UNICODE* u) {
#endif
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_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
case '(':
return do_mktuple(p_format, p_va, ')', countformat(*p_format, ')'), flags);
#if 0
case '[':
return do_mklist(p_format, p_va, ']', countformat(*p_format, ']'), flags);
#if 0
case '{':
return do_mkdict(p_format, p_va, '}', countformat(*p_format, '}'), flags);
#endif
......@@ -239,6 +239,43 @@ static PyObject* do_mktuple(const char** p_format, va_list* p_va, int endchar, i
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 {
int n = countformat(fmt, '\0');
......
......@@ -1466,6 +1466,508 @@ static void add_operators(BoxedClass* cls) noexcept {
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 {
return isSubclass(a, b);
}
......@@ -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()).
// TODO: Move more of the duplicated logic into here.
void PystonType_Ready(BoxedClass* cls) {
inherit_special(cls, cls->tp_base);
void commonClassSetup(BoxedClass* cls) {
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:
BoxedClass* b = cls->tp_base;
while (b) {
// Not sure when this could fail; maybe not in Pyston right now but apparently it can in CPython:
if (PyType_Check(b))
inherit_slots(cls, b);
/* Calculate method resolution order */
if (mro_internal(cls) < 0)
throwCAPIException();
if (cls->tp_base)
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 {
}
extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
ASSERT(!cls->is_pyston_class, "should not call this on Pyston classes");
gc::registerNonheapRootObject(cls);
// unhandled fields:
......@@ -1864,7 +2379,12 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
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->tp_doc) {
......
......@@ -23,7 +23,14 @@ namespace pyston {
bool update_slot(BoxedClass* self, const std::string& attr) 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
......@@ -630,8 +630,8 @@ LargeArena::LargeFreeChunk* LargeArena::get_from_size_list(LargeFreeChunk** list
section->free_chunk_map[i] = 0;
}
assert(section->num_free_chunks >= size >> CHUNK_BITS);
section->num_free_chunks -= size >> CHUNK_BITS;
assert(section->num_free_chunks >= 0);
return free_chunks;
}
......
......@@ -730,7 +730,7 @@ static BoxedClass* makeBuiltinException(BoxedClass* base, const char* name, int
if (size == 0)
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"));
if (base == object_cls) {
......@@ -954,7 +954,8 @@ Box* pydumpAddr(Box* p) {
void setupBuiltins() {
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();
assert(Ellipsis->cls);
gc::registerPermanentRoot(Ellipsis);
......@@ -967,7 +968,8 @@ void setupBuiltins() {
builtins_module->giveAttr(
"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->freeze();
NotImplemented = new (notimplemented_cls) Box();
......@@ -1046,8 +1048,8 @@ void setupBuiltins() {
builtins_module->giveAttr("__import__", new BoxedBuiltinFunctionOrMethod(import_func, "__import__",
{ None, None, None, new BoxedInt(-1) }));
enumerate_cls
= new BoxedHeapClass(object_cls, &BoxedEnumerate::gcHandler, 0, sizeof(BoxedEnumerate), false, "enumerate");
enumerate_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedEnumerate::gcHandler, 0, sizeof(BoxedEnumerate),
false, "enumerate");
enumerate_cls->giveAttr(
"__new__",
new BoxedFunction(boxRTFunction((void*)BoxedEnumerate::new_, UNKNOWN, 3, 1, false, false), { boxInt(0) }));
......
......@@ -294,7 +294,8 @@ void setupSys() {
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__",
new BoxedFunction(boxRTFunction((void*)BoxedSysFlags::__new__, UNKNOWN, 1, 0, true, true)));
#define ADD(name) \
......
......@@ -179,7 +179,7 @@ void setupThread() {
thread_module->giveAttr(
"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(
"acquire", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::acquire, BOXED_BOOL, 2, 1, false, false),
......@@ -191,13 +191,13 @@ void setupThread() {
thread_lock_cls->giveAttr("__exit__", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::exit, NONE, 4)));
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->freeze();
thread_module->giveAttr("_local", thread_local_cls);
BoxedClass* ThreadError
= new BoxedHeapClass(Exception, NULL, Exception->attrs_offset, Exception->tp_basicsize, false, "error");
BoxedClass* ThreadError = BoxedHeapClass::create(type_cls, Exception, NULL, Exception->attrs_offset,
Exception->tp_basicsize, false, "error");
ThreadError->giveAttr("__module__", boxStrConstant("thread"));
ThreadError->freeze();
......
......@@ -501,6 +501,8 @@ extern "C" Py_ssize_t PySequence_Index(PyObject* o, PyObject* value) noexcept {
extern "C" PyObject* PySequence_Tuple(PyObject* o) noexcept {
if (o->cls == tuple_cls)
return o;
if (PyList_Check(o))
return PyList_AsTuple(o);
Py_FatalError("unimplemented");
}
......@@ -1543,7 +1545,7 @@ static Box* methodGetDoc(Box* b, void*) {
}
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__",
new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1)));
......@@ -1554,7 +1556,7 @@ void setupCAPI() {
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__",
new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3)));
method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2,
......@@ -1562,13 +1564,14 @@ void setupCAPI() {
method_cls->giveAttr("__doc__", new (pyston_getset_cls) BoxedGetsetDescriptor(methodGetDoc, NULL, NULL));
method_cls->freeze();
wrapperdescr_cls
= new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedWrapperDescriptor), false, "wrapper_descriptor");
wrapperdescr_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedWrapperDescriptor), false,
"wrapper_descriptor");
wrapperdescr_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3)));
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(
"__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true)));
wrapperobject_cls->freeze();
......
......@@ -270,10 +270,10 @@ Box* instanceSetitem(Box* _inst, Box* key, Box* value) {
}
void setupClassobj() {
classobj_cls = new BoxedHeapClass(object_cls, &BoxedClassobj::gcHandler, offsetof(BoxedClassobj, attrs),
sizeof(BoxedClassobj), false, "classobj");
instance_cls = new BoxedHeapClass(object_cls, &BoxedInstance::gcHandler, offsetof(BoxedInstance, attrs),
sizeof(BoxedInstance), false, "instance");
classobj_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler,
offsetof(BoxedClassobj, attrs), sizeof(BoxedClassobj), false, "classobj");
instance_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedInstance::gcHandler,
offsetof(BoxedInstance, attrs), sizeof(BoxedInstance), false, "instance");
classobj_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)classobjNew, UNKNOWN, 4, 0, false, false)));
......
......@@ -572,13 +572,15 @@ static Box* dict_repr(PyObject* self) noexcept {
}
void setupDict() {
dict_iterator_cls = new BoxedHeapClass(object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict), false,
"dictionary-itemiterator");
dict_keys_cls = new BoxedHeapClass(object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false, "dict_keys");
dict_values_cls
= new BoxedHeapClass(object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false, "dict_values");
dict_items_cls = new BoxedHeapClass(object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false, "dict_items");
dict_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict),
false, "dictionary-itemiterator");
dict_keys_cls = BoxedHeapClass::create(type_cls, object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false,
"dict_keys");
dict_values_cls = BoxedHeapClass::create(type_cls, object_cls, &dictViewGCHandler, 0, sizeof(BoxedDictView), false,
"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("__new__", new BoxedFunction(boxRTFunction((void*)dictNew, UNKNOWN, 1, 0, true, true)));
......
......@@ -298,8 +298,8 @@ void generatorDestructor(Box* b) {
}
void setupGenerator() {
generator_cls = new BoxedHeapClass(object_cls, &generatorGCHandler, offsetof(BoxedGenerator, attrs),
sizeof(BoxedGenerator), false, "generator");
generator_cls = BoxedHeapClass::create(type_cls, object_cls, &generatorGCHandler, offsetof(BoxedGenerator, attrs),
sizeof(BoxedGenerator), false, "generator");
generator_cls->simple_destructor = generatorDestructor;
generator_cls->giveAttr("__iter__",
new BoxedFunction(boxRTFunction((void*)generatorIter, typeFromClass(generator_cls), 1)));
......
......@@ -178,9 +178,9 @@ Box* xrangeReversed(Box* self) {
}
void setupXrange() {
xrange_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedXrange), false, "xrange");
xrange_iterator_cls = new BoxedHeapClass(object_cls, &BoxedXrangeIterator::xrangeIteratorGCHandler, 0,
sizeof(BoxedXrangeIterator), false, "rangeiterator");
xrange_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedXrange), false, "xrange");
xrange_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedXrangeIterator::xrangeIteratorGCHandler, 0,
sizeof(BoxedXrangeIterator), false, "rangeiterator");
xrange_cls->giveAttr(
"__new__",
......
......@@ -141,7 +141,8 @@ extern "C" PyObject* PySeqIter_New(PyObject* seq) noexcept {
}
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("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqiterHasnext, BOXED_BOOL, 1)));
......@@ -149,7 +150,7 @@ void setupIter() {
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("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqreviterHasnext, BOXED_BOOL, 1)));
......@@ -157,8 +158,8 @@ void setupIter() {
seqreviter_cls->freeze();
iterwrapper_cls
= new BoxedHeapClass(object_cls, iterwrapperGCVisit, 0, sizeof(BoxedIterWrapper), false, "iterwrapper");
iterwrapper_cls = BoxedHeapClass::create(type_cls, object_cls, iterwrapperGCVisit, 0, sizeof(BoxedIterWrapper),
false, "iterwrapper");
iterwrapper_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)iterwrapperNext, UNKNOWN, 1)));
iterwrapper_cls->giveAttr("__hasnext__",
......
......@@ -49,6 +49,19 @@ extern "C" PyObject** PyList_Items(PyObject* op) noexcept {
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) {
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
}
void setupList() {
list_iterator_cls
= new BoxedHeapClass(object_cls, &listIteratorGCHandler, 0, sizeof(BoxedList), false, "listiterator");
list_reverse_iterator_cls = new BoxedHeapClass(object_cls, &listIteratorGCHandler, 0, sizeof(BoxedListIterator),
false, "listreverseiterator");
list_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &listIteratorGCHandler, 0, sizeof(BoxedList),
false, "listiterator");
list_reverse_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &listIteratorGCHandler, 0,
sizeof(BoxedListIterator), false, "listreverseiterator");
list_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)listLen, BOXED_INT, 1)));
......
......@@ -195,10 +195,11 @@ bool isInstance(Box* obj, BoxedClass* cls) {
extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent) {
// TODO the class is allowed to override this using __subclasscheck__
while (child) {
if (child == parent)
assert(child->tp_mro);
assert(child->tp_mro->cls == tuple_cls);
for (auto b : static_cast<BoxedTuple*>(child->tp_mro)->elts) {
if (b == parent)
return true;
child = child->tp_base;
}
return false;
}
......@@ -314,7 +315,10 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
if (cls == NULL) {
assert(type_cls == NULL);
} 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);
......@@ -349,26 +353,23 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
gc::registerPermanentRoot(this);
}
BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size,
bool is_user_defined, const std::string& name)
: BoxedHeapClass(base, gc_visit, attrs_offset, instance_size, is_user_defined, new BoxedString(name)) {
void BoxedClass::finishInitialization() {
commonClassSetup(this);
}
BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size,
bool is_user_defined)
: BoxedClass(base, gc_visit, attrs_offset, instance_size, is_user_defined), ht_name(NULL), 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);
bool is_user_defined, BoxedString* name)
: BoxedClass(base, gc_visit, attrs_offset, instance_size, is_user_defined), ht_name(name), ht_slots(NULL) {
tp_as_number = &as_number;
tp_as_mapping = &as_mapping;
tp_as_sequence = &as_sequence;
tp_as_buffer = &as_buffer;
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_mapping, 0, sizeof(as_mapping));
......@@ -376,21 +377,26 @@ BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attr
memset(&as_buffer, 0, sizeof(as_buffer));
}
BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size,
bool is_user_defined, BoxedString* name)
: BoxedClass(base, gc_visit, attrs_offset, instance_size, is_user_defined), ht_name(name), ht_slots(NULL) {
BoxedHeapClass* BoxedHeapClass::create(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int instance_size, bool is_user_defined, const std::string& name) {
return create(metaclass, base, gc_visit, attrs_offset, instance_size, is_user_defined, new BoxedString(name), NULL);
}
tp_as_number = &as_number;
tp_as_mapping = &as_mapping;
tp_as_sequence = &as_sequence;
tp_as_buffer = &as_buffer;
tp_name = ht_name->s.c_str();
tp_flags |= Py_TPFLAGS_HEAPTYPE;
BoxedHeapClass* BoxedHeapClass::create(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int instance_size, bool is_user_defined, BoxedString* name, BoxedTuple* bases) {
BoxedHeapClass* made = new (metaclass)
BoxedHeapClass(base, gc_visit, attrs_offset, instance_size, is_user_defined, name);
memset(&as_number, 0, sizeof(as_number));
memset(&as_mapping, 0, sizeof(as_mapping));
memset(&as_sequence, 0, sizeof(as_sequence));
memset(&as_buffer, 0, sizeof(as_buffer));
// While it might be ok if these were set, it'd indicate a difference in
// expectations as to who was going to calculate them:
assert(!made->tp_mro);
assert(!made->tp_bases);
made->tp_bases = bases;
made->finishInitialization();
assert(made->tp_mro);
return made;
}
std::string getFullNameOfClass(BoxedClass* cls) {
......@@ -656,19 +662,45 @@ Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* re
RewriterVar* obj_saved = rewrite_args->obj;
val = cls->getattr(attr, rewrite_args);
assert(rewrite_args->out_success);
if (!val and cls->tp_base) {
auto _mro = cls->tp_mro;
assert(_mro->cls == tuple_cls);
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->obj = obj_saved->getAttr(offsetof(BoxedClass, tp_base));
val = typeLookup(cls->tp_base, attr, rewrite_args);
if (base == cls) {
// 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 {
val = cls->getattr(attr, NULL);
if (!val and cls->tp_base)
return typeLookup(cls->tp_base, attr, NULL);
return val;
assert(cls->tp_mro);
assert(cls->tp_mro->cls == tuple_cls);
for (auto b : static_cast<BoxedTuple*>(cls->tp_mro)->elts) {
val = b->getattr(attr, NULL);
if (val)
return val;
}
return NULL;
}
}
......@@ -1521,9 +1553,8 @@ extern "C" Box* getattr(Box* obj, const char* attr) {
// This doesn't belong here either:
if (strcmp(attr, "__bases__") == 0 && isSubclass(obj->cls, type_cls)) {
BoxedClass* cls = static_cast<BoxedClass*>(obj);
if (cls->tp_base)
return new BoxedTuple({ static_cast<BoxedClass*>(obj)->tp_base });
return EmptyTuple;
assert(cls->tp_bases);
return cls->tp_bases;
}
}
......@@ -2031,10 +2062,16 @@ extern "C" void dump(void* p) {
auto cls = static_cast<BoxedClass*>(b);
printf("Type name: %s\n", getFullNameOfClass(cls).c_str());
printf("MRO: %s", getFullNameOfClass(cls).c_str());
while (cls->tp_base) {
printf(" -> %s", getFullNameOfClass(cls->tp_base).c_str());
cls = cls->tp_base;
printf("MRO:");
if (cls->tp_mro && cls->tp_mro->cls == tuple_cls) {
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");
}
......@@ -3572,10 +3609,10 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "type.__new__(X): X is not a type object (%s)", getTypeName(_cls));
BoxedClass* cls = static_cast<BoxedClass*>(_cls);
if (!isSubclass(cls, type_cls))
raiseExcHelper(TypeError, "type.__new__(%s): %s is not a subtype of type", getNameOfClass(cls),
getNameOfClass(cls));
BoxedClass* metatype = static_cast<BoxedClass*>(_cls);
if (!isSubclass(metatype, type_cls))
raiseExcHelper(TypeError, "type.__new__(%s): %s is not a subtype of type", getNameOfClass(metatype),
getNameOfClass(metatype));
if (arg2 == NULL) {
assert(arg3 == NULL);
......@@ -3592,30 +3629,65 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
RELEASE_ASSERT(arg1->cls == str_cls, "");
BoxedString* name = static_cast<BoxedString*>(arg1);
BoxedClass* base;
if (bases->elts.size() == 0) {
bases = new BoxedTuple({ object_cls });
}
RELEASE_ASSERT(bases->elts.size() == 1, "");
Box* _base = bases->elts[0];
RELEASE_ASSERT(isSubclass(_base->cls, type_cls), "");
base = static_cast<BoxedClass*>(_base);
// Ported from CPython:
int nbases = bases->elts.size();
BoxedClass* winner = metatype;
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);
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;
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 {
assert(base->tp_basicsize % sizeof(void*) == 0);
made = new (cls)
BoxedHeapClass(base, NULL, base->tp_basicsize, base->tp_basicsize + sizeof(HCAttrs), true, name);
made = BoxedHeapClass::create(metatype, base, NULL, base->tp_basicsize, base->tp_basicsize + sizeof(HCAttrs),
true, name, bases);
}
// TODO: how much of these should be in BoxedClass::finishInitialization()?
made->tp_dictoffset = base->tp_dictoffset;
for (const auto& p : attr_dict->d) {
......@@ -3630,7 +3702,6 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
made->tp_new = base->tp_new;
PystonType_Ready(made);
fixup_slot_dispatchers(made);
if (base->tp_alloc == &PystonType_GenericAlloc)
......
......@@ -246,7 +246,8 @@ Box* setNonzero(BoxedSet* self) {
using namespace pyston::set;
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__",
new BoxedFunction(boxRTFunction((void*)setiteratorHasnext, BOXED_BOOL, 1)));
set_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)setiteratorNext, UNKNOWN, 1)));
......
......@@ -2208,8 +2208,8 @@ void setupStr() {
str_cls->simple_destructor = strDestructor;
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
str_iterator_cls
= new BoxedHeapClass(object_cls, &strIteratorGCHandler, 0, sizeof(BoxedStringIterator), false, "striterator");
str_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &strIteratorGCHandler, 0,
sizeof(BoxedStringIterator), false, "striterator");
str_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::hasnext, BOXED_BOOL, 1)));
str_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::next, STR, 1)));
......
......@@ -16,6 +16,7 @@
#include <sstream>
#include "capi/types.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/objmodel.h"
......@@ -66,15 +67,68 @@ Box* superGetattribute(Box* _s, Box* _attr) {
}
if (!skip) {
// We don't support multiple inheritance yet, so the lookup order is simple:
Box* r = typeLookup(s->type->tp_base, attr->s, NULL);
if (r) {
return processDescriptor(r, (s->obj == s->obj_type ? None : s->obj), s->obj_type);
PyObject* mro, *res, *tmp, *dict;
PyTypeObject* starttype;
descrgetfunc f;
Py_ssize_t i, n;
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);
// TODO implement this
RELEASE_ASSERT(r, "should call the equivalent of objectGetattr here");
return processDescriptor(r, s, s->cls);
}
......@@ -132,7 +186,8 @@ Box* superInit(Box* _self, Box* _type, Box* obj) {
}
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("__repr__", new BoxedFunction(boxRTFunction((void*)superRepr, STR, 1)));
......
......@@ -107,8 +107,8 @@ Box* BoxedTraceback::getLines(Box* b) {
}
void setupTraceback() {
traceback_cls
= new BoxedHeapClass(object_cls, BoxedTraceback::gcHandler, 0, sizeof(BoxedTraceback), false, "traceback");
traceback_cls = BoxedHeapClass::create(type_cls, object_cls, BoxedTraceback::gcHandler, 0, sizeof(BoxedTraceback),
false, "traceback");
traceback_cls->giveAttr("getLines", new BoxedFunction(boxRTFunction((void*)BoxedTraceback::getLines, UNKNOWN, 1)));
......
......@@ -386,7 +386,8 @@ extern "C" void tupleIteratorGCHandler(GCVisitor* v, Box* b) {
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)));
CLFunction* getitem = createRTFunction(2, 0, 0, 0);
......
......@@ -21,6 +21,7 @@
#include <sstream>
#include <stdint.h>
#include "capi/typeobject.h"
#include "core/options.h"
#include "core/stats.h"
#include "core/types.h"
......@@ -96,10 +97,16 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
assert(static_cast<BoxedClass*>(e)->is_pyston_class);
}
#endif
BoxedClass* b = cls;
while (b) {
ASSERT(b->is_pyston_class, "%s (%s)", cls->tp_name, b->tp_name);
b = b->tp_base;
if (!cls->tp_mro) {
assert(!list_cls);
} else {
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
......@@ -405,6 +412,10 @@ extern "C" void typeGCHandler(GCVisitor* v, Box* b) {
v->visit(cls->tp_base);
if (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) {
BoxedHeapClass* hcls = static_cast<BoxedHeapClass*>(cls);
......@@ -898,6 +909,15 @@ Box* typeHash(BoxedClass* self) {
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) {
assert(m->cls == module_cls);
......@@ -1220,20 +1240,19 @@ void setupRuntime() {
object_cls = ::new (mem) BoxedClass(NULL, &boxGCHandler, 0, sizeof(Box), false);
mem = gc_alloc(sizeof(BoxedHeapClass), gc::GCKind::PYTHON);
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(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();
assert(None->cls);
gc::registerPermanentRoot(None);
// 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);
str_cls = new BoxedHeapClass(basestring_cls, NULL, 0, sizeof(BoxedString), false, NULL);
// Hold off on assigning names until str_cls is ready
object_cls->tp_name = "object";
......@@ -1260,54 +1279,75 @@ void setupRuntime() {
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({});
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
= new BoxedHeapClass(object_cls, NULL, offsetof(BoxedModule, attrs), sizeof(BoxedModule), false, "module");
module_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, offsetof(BoxedModule, attrs), sizeof(BoxedModule),
false, "module");
// 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.
// 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");
bool_cls = new BoxedHeapClass(int_cls, NULL, 0, sizeof(BoxedBool), false, "bool");
complex_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedComplex), false, "complex");
long_cls = new BoxedHeapClass(object_cls, &BoxedLong::gchandler, 0, sizeof(BoxedLong), false, "long");
float_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedFloat), false, "float");
function_cls = new BoxedHeapClass(object_cls, &functionGCHandler, offsetof(BoxedFunction, attrs),
sizeof(BoxedFunction), false, "function");
int_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedInt), false, "int");
bool_cls = BoxedHeapClass::create(type_cls, int_cls, NULL, 0, sizeof(BoxedBool), false, "bool");
complex_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedComplex), false, "complex");
long_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedLong::gchandler, 0, sizeof(BoxedLong), false, "long");
float_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedFloat), false, "float");
function_cls = BoxedHeapClass::create(type_cls, object_cls, &functionGCHandler, offsetof(BoxedFunction, attrs),
sizeof(BoxedFunction), false, "function");
function_cls->tp_weaklistoffset = offsetof(BoxedFunction, in_weakreflist);
builtin_function_or_method_cls
= new BoxedHeapClass(object_cls, &functionGCHandler, offsetof(BoxedBuiltinFunctionOrMethod, attrs),
sizeof(BoxedBuiltinFunctionOrMethod), false, "builtin_function_or_method");
builtin_function_or_method_cls = BoxedHeapClass::create(
type_cls, object_cls, &functionGCHandler, offsetof(BoxedBuiltinFunctionOrMethod, attrs),
sizeof(BoxedBuiltinFunctionOrMethod), false, "builtin_function_or_method");
builtin_function_or_method_cls->tp_weaklistoffset = offsetof(BoxedBuiltinFunctionOrMethod, in_weakreflist);
function_cls->simple_destructor = builtin_function_or_method_cls->simple_destructor = functionDtor;
instancemethod_cls = new BoxedHeapClass(object_cls, &instancemethodGCHandler, 0, sizeof(BoxedInstanceMethod), false,
"instancemethod");
instancemethod_cls = BoxedHeapClass::create(type_cls, object_cls, &instancemethodGCHandler, 0,
sizeof(BoxedInstanceMethod), false, "instancemethod");
instancemethod_cls->tp_weaklistoffset = offsetof(BoxedInstanceMethod, in_weakreflist);
list_cls = new BoxedHeapClass(object_cls, &listGCHandler, 0, sizeof(BoxedList), false, "list");
slice_cls = new BoxedHeapClass(object_cls, &sliceGCHandler, 0, sizeof(BoxedSlice), false, "slice");
dict_cls = new BoxedHeapClass(object_cls, &dictGCHandler, 0, sizeof(BoxedDict), false, "dict");
file_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedFile), false, "file");
set_cls = new BoxedHeapClass(object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "set");
frozenset_cls = new BoxedHeapClass(object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "frozenset");
member_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false, "member");
pyston_getset_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
capi_getset_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
closure_cls = new BoxedHeapClass(object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs), sizeof(BoxedClosure),
false, "closure");
property_cls = new BoxedHeapClass(object_cls, &propertyGCHandler, 0, sizeof(BoxedProperty), false, "property");
staticmethod_cls
= new BoxedHeapClass(object_cls, &staticmethodGCHandler, 0, sizeof(BoxedStaticmethod), false, "staticmethod");
classmethod_cls
= new BoxedHeapClass(object_cls, &classmethodGCHandler, 0, sizeof(BoxedClassmethod), false, "classmethod");
attrwrapper_cls
= new BoxedHeapClass(object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper), false, "attrwrapper");
list_cls = BoxedHeapClass::create(type_cls, object_cls, &listGCHandler, 0, sizeof(BoxedList), false, "list");
slice_cls = BoxedHeapClass::create(type_cls, object_cls, &sliceGCHandler, 0, sizeof(BoxedSlice), false, "slice");
dict_cls = BoxedHeapClass::create(type_cls, object_cls, &dictGCHandler, 0, sizeof(BoxedDict), false, "dict");
file_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedFile), false, "file");
set_cls = BoxedHeapClass::create(type_cls, object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "set");
frozenset_cls
= BoxedHeapClass::create(type_cls, object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "frozenset");
member_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false, "member");
pyston_getset_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
capi_getset_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
closure_cls = BoxedHeapClass::create(type_cls, object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs),
sizeof(BoxedClosure), false, "closure");
property_cls
= BoxedHeapClass::create(type_cls, object_cls, &propertyGCHandler, 0, sizeof(BoxedProperty), false, "property");
staticmethod_cls = BoxedHeapClass::create(type_cls, object_cls, &staticmethodGCHandler, 0,
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
pyston_getset_cls->freeze();
......@@ -1345,6 +1385,9 @@ void setupRuntime() {
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("__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();
none_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)noneRepr, STR, 1)));
......
......@@ -192,9 +192,15 @@ public:
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);
DEFAULT_CLASS(type_cls);
friend void setupRuntime();
};
class BoxedHeapClass : public BoxedClass {
......@@ -207,15 +213,22 @@ public:
BoxedString* ht_name;
PyObject** ht_slots;
BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined,
const std::string& name);
// These functions are the preferred way to construct new types:
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,
BoxedString* name);
// This constructor is only used for bootstrapping purposes to be called for types that
// are initialized before str_cls.
BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined);
friend void setupRuntime();
DEFAULT_CLASS(type_cls);
};
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):
o.arg1 = arg1
return o
def f(self):
print "B.f()"
class C(B):
def __new__(cls, arg1, arg2):
print "C.__new__", arg2
......@@ -13,9 +16,14 @@ class C(B):
print super(C, cls), super(C, o)
return o
def f(self):
print "C.f()"
super(C, self).f()
c = C(1, 2)
print c.arg1
print c.arg2
c.f()
try:
super(1)
......
......@@ -413,16 +413,16 @@ if __name__ == "__main__":
]
tests += big_tests
LIB_DIR = os.path.join(sys.prefix, "lib/python2.7")
for t in tests:
bn = os.path.basename(t)
assert bn.endswith(".py")
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))
except ImportError:
pass
# good
for t in TOSKIP:
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