Commit 49ee07fa authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'tp_as_number'

parents 76210a33 b679d358
......@@ -321,7 +321,7 @@ NONSTDLIB_SRCS := $(MAIN_SRCS) $(OPTIONAL_SRCS) $(TOOL_SRCS) $(UNITTEST_SRCS)
# all: pyston_dbg pyston_release pyston_oprof pyston_prof $(OPTIONAL_SRCS:.cpp=.o) ext_python ext_pyston
all: pyston_dbg pyston_release pyston_prof ext_python ext_pyston unittests
ALL_HEADERS := $(wildcard src/*/*.h) $(wildcard src/*/*/*.h) $(wildcard cpython2.7/Include/*.h)
ALL_HEADERS := $(wildcard src/*/*.h) $(wildcard src/*/*/*.h) $(wildcard from_cpython/Include/*.h)
tags: $(SRCS) $(OPTIONAL_SRCS) $(FROM_CPYTHON_SRCS) $(ALL_HEADERS)
$(ECHO) Calculating tags...
$(VERB) ctags $^
......@@ -865,6 +865,10 @@ $(call make_target,_grwl)
$(call make_target,_grwl_dbg)
$(call make_target,_nosync)
runpy_%: %.py ext_python
PYTHONPATH=test/test_extension/build/lib.linux-x86_64-2.7 python $<
$(call make_search,runpy_%)
# "kill valgrind":
kv:
ps aux | awk '/[v]algrind/ {print $$2}' | xargs kill -9; true
......
......@@ -42,7 +42,7 @@ PyAPI_FUNC(bool) PyInt_Check(PyObject*);
#define PyInt_Check(op) \
PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_INT_SUBCLASS)
#endif
#define PyInt_CheckExact(op) ((op)->ob_type == &PyInt_Type)
#define PyInt_CheckExact(op) (Py_TYPE(op) == &PyInt_Type)
PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int);
#ifdef Py_USING_UNICODE
......
......@@ -75,4 +75,29 @@ extern "C" int PyObject_GenericSetAttr(PyObject* obj, PyObject* name, PyObject*
extern "C" int PyObject_AsWriteBuffer(PyObject* obj, void** buffer, Py_ssize_t* buffer_len) {
Py_FatalError("unimplemented");
}
/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
extern "C" int PyObject_RichCompareBool(PyObject* v, PyObject* w, int op) {
PyObject* res;
int ok;
/* Quick result when objects are the same.
Guarantees that identity implies equality. */
if (v == w) {
if (op == Py_EQ)
return 1;
else if (op == Py_NE)
return 0;
}
res = PyObject_RichCompare(v, w, op);
if (res == NULL)
return -1;
if (PyBool_Check(res))
ok = (res == Py_True);
else
ok = PyObject_IsTrue(res);
Py_DECREF(res);
return ok;
}
}
......@@ -79,6 +79,30 @@ RICHCMP_WRAPPER(ne, Py_NE)
RICHCMP_WRAPPER(gt, Py_GT)
RICHCMP_WRAPPER(ge, Py_GE)
static PyObject* wrap_ternaryfunc(PyObject* self, PyObject* args, void* wrapped) noexcept {
ternaryfunc func = (ternaryfunc)wrapped;
PyObject* other;
PyObject* third = Py_None;
/* Note: This wrapper only works for __pow__() */
if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third))
return NULL;
return (*func)(self, other, third);
}
static PyObject* wrap_ternaryfunc_r(PyObject* self, PyObject* args, void* wrapped) noexcept {
ternaryfunc func = (ternaryfunc)wrapped;
PyObject* other;
PyObject* third = Py_None;
/* Note: This wrapper only works for __pow__() */
if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third))
return NULL;
return (*func)(other, self, third);
}
static PyObject* wrap_unaryfunc(PyObject* self, PyObject* args, void* wrapped) noexcept {
unaryfunc func = (unaryfunc)wrapped;
......@@ -87,6 +111,18 @@ static PyObject* wrap_unaryfunc(PyObject* self, PyObject* args, void* wrapped) n
return (*func)(self);
}
static PyObject* wrap_inquirypred(PyObject* self, PyObject* args, void* wrapped) noexcept {
inquiry func = (inquiry)wrapped;
int res;
if (!check_num_args(args, 0))
return NULL;
res = (*func)(self);
if (res == -1 && PyErr_Occurred())
return NULL;
return PyBool_FromLong((long)res);
}
static PyObject* wrap_binaryfunc(PyObject* self, PyObject* args, void* wrapped) noexcept {
binaryfunc func = (binaryfunc)wrapped;
PyObject* other;
......@@ -97,6 +133,34 @@ static PyObject* wrap_binaryfunc(PyObject* self, PyObject* args, void* wrapped)
return (*func)(self, other);
}
static PyObject* wrap_binaryfunc_l(PyObject* self, PyObject* args, void* wrapped) {
binaryfunc func = (binaryfunc)wrapped;
PyObject* other;
if (!check_num_args(args, 1))
return NULL;
other = PyTuple_GET_ITEM(args, 0);
if (!(self->cls->tp_flags & Py_TPFLAGS_CHECKTYPES) && !PyType_IsSubtype(other->cls, self->cls)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
return (*func)(self, other);
}
static PyObject* wrap_binaryfunc_r(PyObject* self, PyObject* args, void* wrapped) {
binaryfunc func = (binaryfunc)wrapped;
PyObject* other;
if (!check_num_args(args, 1))
return NULL;
other = PyTuple_GET_ITEM(args, 0);
if (!(self->cls->tp_flags & Py_TPFLAGS_CHECKTYPES) && !PyType_IsSubtype(other->cls, self->cls)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
return (*func)(other, self);
}
static Py_ssize_t getindex(PyObject* self, PyObject* arg) noexcept {
Py_ssize_t i;
......@@ -343,6 +407,41 @@ static PyObject* call_method(PyObject* o, const char* name, PyObject** nameobj,
return retval;
}
/* Clone of call_method() that returns NotImplemented when the lookup fails. */
static PyObject* call_maybe(PyObject* o, const char* name, PyObject** nameobj, const char* format, ...) noexcept {
va_list va;
PyObject* args, * func = 0, *retval;
va_start(va, format);
func = lookup_maybe(o, name, nameobj);
if (func == NULL) {
va_end(va);
if (!PyErr_Occurred()) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
return NULL;
}
if (format && *format)
args = Py_VaBuildValue(format, va);
else
args = PyTuple_New(0);
va_end(va);
if (args == NULL)
return NULL;
assert(PyTuple_Check(args));
retval = PyObject_Call(func, args, NULL);
Py_DECREF(args);
Py_DECREF(func);
return retval;
}
PyObject* slot_tp_repr(PyObject* self) noexcept {
try {
......@@ -352,6 +451,14 @@ PyObject* slot_tp_repr(PyObject* self) noexcept {
}
}
PyObject* slot_tp_str(PyObject* self) noexcept {
try {
return str(self);
} catch (Box* e) {
abort();
}
}
static long slot_tp_hash(PyObject* self) noexcept {
PyObject* func;
static PyObject* hash_str, *eq_str, *cmp_str;
......@@ -591,6 +698,73 @@ static int slot_sq_contains(PyObject* self, PyObject* value) {
return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \
}
/* Boolean helper for SLOT1BINFULL().
right.__class__ is a nontrivial subclass of left.__class__. */
static int method_is_overloaded(PyObject* left, PyObject* right, const char* name) {
PyObject* a, *b;
int ok;
b = PyObject_GetAttrString((PyObject*)(Py_TYPE(right)), name);
if (b == NULL) {
PyErr_Clear();
/* If right doesn't have it, it's not overloaded */
return 0;
}
a = PyObject_GetAttrString((PyObject*)(Py_TYPE(left)), name);
if (a == NULL) {
PyErr_Clear();
Py_DECREF(b);
/* If right has it but left doesn't, it's overloaded */
return 1;
}
ok = PyObject_RichCompareBool(a, b, Py_NE);
Py_DECREF(a);
Py_DECREF(b);
if (ok < 0) {
PyErr_Clear();
return 0;
}
return ok;
}
#define SLOT1BINFULL(FUNCNAME, TESTFUNC, SLOTNAME, OPSTR, ROPSTR) \
static PyObject* FUNCNAME(PyObject* self, PyObject* other) { \
static PyObject* cache_str, *rcache_str; \
int do_other = Py_TYPE(self) != Py_TYPE(other) && Py_TYPE(other)->tp_as_number != NULL \
&& Py_TYPE(other)->tp_as_number->SLOTNAME == TESTFUNC; \
if (Py_TYPE(self)->tp_as_number != NULL && Py_TYPE(self)->tp_as_number->SLOTNAME == TESTFUNC) { \
PyObject* r; \
if (do_other && PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) \
&& method_is_overloaded(self, other, ROPSTR)) { \
r = call_maybe(other, ROPSTR, &rcache_str, "(O)", self); \
if (r != Py_NotImplemented) \
return r; \
Py_DECREF(r); \
do_other = 0; \
} \
r = call_maybe(self, OPSTR, &cache_str, "(O)", other); \
if (r != Py_NotImplemented || Py_TYPE(other) == Py_TYPE(self)) \
return r; \
Py_DECREF(r); \
} \
if (do_other) { \
return call_maybe(other, ROPSTR, &rcache_str, "(O)", self); \
} \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
}
#define SLOT1BIN(FUNCNAME, SLOTNAME, OPSTR, ROPSTR) SLOT1BINFULL(FUNCNAME, FUNCNAME, SLOTNAME, OPSTR, ROPSTR)
#define SLOT2(FUNCNAME, OPSTR, ARG1TYPE, ARG2TYPE, ARGCODES) \
static PyObject* FUNCNAME(PyObject* self, ARG1TYPE arg1, ARG2TYPE arg2) { \
static PyObject* cache_str; \
return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1, arg2); \
}
#define slot_mp_length slot_sq_length
SLOT1(slot_mp_subscript, "__getitem__", PyObject*, "O")
......@@ -609,6 +783,85 @@ static int slot_mp_ass_subscript(PyObject* self, PyObject* key, PyObject* value)
return 0;
}
SLOT1BIN(slot_nb_add, nb_add, "__add__", "__radd__")
SLOT1BIN(slot_nb_subtract, nb_subtract, "__sub__", "__rsub__")
SLOT1BIN(slot_nb_multiply, nb_multiply, "__mul__", "__rmul__")
SLOT1BIN(slot_nb_divide, nb_divide, "__div__", "__rdiv__")
SLOT1BIN(slot_nb_remainder, nb_remainder, "__mod__", "__rmod__")
SLOT1BIN(slot_nb_divmod, nb_divmod, "__divmod__", "__rdivmod__")
static PyObject* slot_nb_power(PyObject*, PyObject*, PyObject*);
SLOT1BINFULL(slot_nb_power_binary, slot_nb_power, nb_power, "__pow__", "__rpow__")
static PyObject* slot_nb_power(PyObject* self, PyObject* other, PyObject* modulus) {
static PyObject* pow_str;
if (modulus == Py_None)
return slot_nb_power_binary(self, other);
/* Three-arg power doesn't use __rpow__. But ternary_op
can call this when the second argument's type uses
slot_nb_power, so check before calling self.__pow__. */
if (Py_TYPE(self)->tp_as_number != NULL && Py_TYPE(self)->tp_as_number->nb_power == slot_nb_power) {
return call_method(self, "__pow__", &pow_str, "(OO)", other, modulus);
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
SLOT0(slot_nb_negative, "__neg__")
SLOT0(slot_nb_positive, "__pos__")
SLOT0(slot_nb_absolute, "__abs__")
static int slot_nb_nonzero(PyObject* self) noexcept {
PyObject* func, *args;
static PyObject* nonzero_str, *len_str;
int result = -1;
int using_len = 0;
func = lookup_maybe(self, "__nonzero__", &nonzero_str);
if (func == NULL) {
if (PyErr_Occurred())
return -1;
func = lookup_maybe(self, "__len__", &len_str);
if (func == NULL)
return PyErr_Occurred() ? -1 : 1;
using_len = 1;
}
args = PyTuple_New(0);
if (args != NULL) {
PyObject* temp = PyObject_Call(func, args, NULL);
Py_DECREF(args);
if (temp != NULL) {
if (PyInt_CheckExact(temp) || PyBool_Check(temp))
result = PyObject_IsTrue(temp);
else {
PyErr_Format(PyExc_TypeError, "%s should return "
"bool or int, returned %s",
(using_len ? "__len__" : "__nonzero__"), temp->cls->tp_name);
result = -1;
}
Py_DECREF(temp);
}
}
Py_DECREF(func);
return result;
}
SLOT0(slot_nb_invert, "__invert__")
SLOT1BIN(slot_nb_lshift, nb_lshift, "__lshift__", "__rlshift__")
SLOT1BIN(slot_nb_rshift, nb_rshift, "__rshift__", "__rrshift__")
SLOT1BIN(slot_nb_and, nb_and, "__and__", "__rand__")
SLOT1BIN(slot_nb_xor, nb_xor, "__xor__", "__rxor__")
SLOT1BIN(slot_nb_or, nb_or, "__or__", "__ror__")
static int slot_nb_coerce(PyObject** a, PyObject** b);
SLOT0(slot_nb_int, "__int__")
SLOT0(slot_nb_long, "__long__")
SLOT0(slot_nb_float, "__float__")
SLOT0(slot_nb_oct, "__oct__")
SLOT0(slot_nb_hex, "__hex__")
typedef wrapper_def slotdef;
......@@ -687,6 +940,7 @@ static slotdef slotdefs[] = {
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, "x.__hash__() <==> hash(x)"),
FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, "x.__call__(...) <==> x(...)",
PyWrapperFlag_KEYWORDS),
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, "x.__str__() <==> str(x)"),
TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt, "x.__lt__(y) <==> x<y"),
TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le, "x.__le__(y) <==> x<=y"),
TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq, "x.__eq__(y) <==> x==y"),
......@@ -699,6 +953,41 @@ static slotdef slotdefs[] = {
PyWrapperFlag_KEYWORDS),
TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
BINSLOT("__add__", nb_add, slot_nb_add, "+"), // [force clang-format to line break]
RBINSLOT("__radd__", nb_add, slot_nb_add, "+"), //
BINSLOT("__sub__", nb_subtract, slot_nb_subtract, "-"), //
RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract, "-"), //
BINSLOT("__mul__", nb_multiply, slot_nb_multiply, "*"), //
RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply, "*"), //
BINSLOT("__div__", nb_divide, slot_nb_divide, "/"), //
RBINSLOT("__rdiv__", nb_divide, slot_nb_divide, "/"), //
BINSLOT("__mod__", nb_remainder, slot_nb_remainder, "%"), //
RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder, "%"), //
BINSLOTNOTINFIX("__divmod__", nb_divmod, slot_nb_divmod, "divmod(x, y)"),
RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod, "divmod(y, x)"),
NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc, "x.__pow__(y[, z]) <==> pow(x, y[, z])"),
NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r, "y.__rpow__(x[, z]) <==> pow(x, y[, z])"),
UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-x"), //
UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+x"), //
UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc, "abs(x)"), //
UNSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_inquirypred, "x != 0"), //
UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~x"), //
BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"), //
RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"), //
BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"), //
RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift, ">>"), //
BINSLOT("__and__", nb_and, slot_nb_and, "&"), //
RBINSLOT("__rand__", nb_and, slot_nb_and, "&"), //
BINSLOT("__xor__", nb_xor, slot_nb_xor, "^"), //
RBINSLOT("__rxor__", nb_xor, slot_nb_xor, "^"), //
BINSLOT("__or__", nb_or, slot_nb_or, "|"), //
RBINSLOT("__ror__", nb_or, slot_nb_or, "|"), //
UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc, "int(x)"), //
UNSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc, "long(x)"), //
UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc, "float(x)"), //
UNSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc, "oct(x)"), //
UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc, "hex(x)"), //
MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, "x.__len__() <==> len(x)"),
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, wrap_binaryfunc, "x.__getitem__(y) <==> x[y]"),
MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript, wrap_objobjargproc,
......@@ -739,6 +1028,17 @@ static void init_slotdefs() {
for (int i = 0; i < sizeof(slotdefs) / sizeof(slotdefs[0]); i++) {
if (i > 0) {
#ifndef NDEBUG
if (slotdefs[i - 1].offset > slotdefs[i].offset) {
printf("slotdef for %s in the wrong place\n", slotdefs[i - 1].name);
for (int j = i; j < sizeof(slotdefs) / sizeof(slotdefs[0]); j++) {
if (slotdefs[i - 1].offset <= slotdefs[j].offset) {
printf("Should go before %s\n", slotdefs[j].name);
break;
}
}
}
#endif
ASSERT(slotdefs[i].offset >= slotdefs[i - 1].offset, "%d %s", i, slotdefs[i - 1].name);
// CPython interns the name here
}
......@@ -839,14 +1139,38 @@ extern "C" int PyType_Ready(PyTypeObject* cls) {
RELEASE_ASSERT(cls->tp_getattr == NULL, "");
RELEASE_ASSERT(cls->tp_setattr == NULL, "");
RELEASE_ASSERT(cls->tp_compare == NULL, "");
RELEASE_ASSERT(cls->tp_as_number == NULL, "");
RELEASE_ASSERT(cls->tp_str == NULL, "");
if (cls->tp_as_number) {
auto num = cls->tp_as_number;
// Members not added yet:
assert(num->nb_coerce == NULL);
assert(num->nb_inplace_add == NULL);
assert(num->nb_inplace_subtract == NULL);
assert(num->nb_inplace_multiply == NULL);
assert(num->nb_inplace_divide == NULL);
assert(num->nb_inplace_remainder == NULL);
assert(num->nb_inplace_power == NULL);
assert(num->nb_inplace_lshift == NULL);
assert(num->nb_inplace_rshift == NULL);
assert(num->nb_inplace_and == NULL);
assert(num->nb_inplace_xor == NULL);
assert(num->nb_inplace_or == NULL);
assert(num->nb_floor_divide == NULL);
assert(num->nb_true_divide == NULL);
assert(num->nb_inplace_floor_divide == NULL);
assert(num->nb_inplace_true_divide == NULL);
assert(num->nb_index == NULL);
}
RELEASE_ASSERT(cls->tp_getattro == NULL || cls->tp_getattro == PyObject_GenericGetAttr, "");
RELEASE_ASSERT(cls->tp_setattro == NULL || cls->tp_setattro == PyObject_GenericSetAttr, "");
RELEASE_ASSERT(cls->tp_as_buffer == NULL, "");
int ALLOWABLE_FLAGS = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC;
int ALLOWABLE_FLAGS = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES;
RELEASE_ASSERT((cls->tp_flags & ~ALLOWABLE_FLAGS) == 0, "");
if (cls->tp_as_number) {
RELEASE_ASSERT(cls->tp_flags & Py_TPFLAGS_CHECKTYPES, "Pyston doesn't yet support non-checktypes behavior");
}
RELEASE_ASSERT(cls->tp_iter == NULL, "");
RELEASE_ASSERT(cls->tp_iternext == NULL, "");
......
......@@ -353,6 +353,7 @@ BoxedClass::BoxedClass(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_
tp_basicsize = instance_size;
tp_flags |= Py_TPFLAGS_HEAPTYPE;
tp_flags |= Py_TPFLAGS_CHECKTYPES;
if (metaclass == NULL) {
assert(type_cls == NULL);
......@@ -1456,26 +1457,6 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
descr = typeLookup(obj->cls, attr, NULL);
}
if (isSubclass(obj->cls, type_cls)) {
BoxedClass* self = static_cast<BoxedClass*>(obj);
if (attr == _getattr_str || attr == _getattribute_str) {
// Will have to embed the clear in the IC, so just disable the patching for now:
rewrite_args = NULL;
// TODO should put this clearing behavior somewhere else, since there are probably more
// cases in which we want to do it.
self->dependent_icgetattrs.invalidateAll();
}
if (attr == "__base__" && self->getattr("__base__"))
raiseExcHelper(TypeError, "readonly attribute");
bool touched_slot = update_slot(self, attr);
if (touched_slot)
rewrite_args = NULL;
}
Box* _set_ = NULL;
RewriterVar* r_set = NULL;
if (descr) {
......@@ -1511,6 +1492,26 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
} else {
obj->setattr(attr, val, rewrite_args);
}
if (isSubclass(obj->cls, type_cls)) {
BoxedClass* self = static_cast<BoxedClass*>(obj);
if (attr == _getattr_str || attr == _getattribute_str) {
// Will have to embed the clear in the IC, so just disable the patching for now:
rewrite_args = NULL;
// TODO should put this clearing behavior somewhere else, since there are probably more
// cases in which we want to do it.
self->dependent_icgetattrs.invalidateAll();
}
if (attr == "__base__" && self->getattr("__base__"))
raiseExcHelper(TypeError, "readonly attribute");
bool touched_slot = update_slot(self, attr);
if (touched_slot)
rewrite_args = NULL;
}
}
extern "C" void setattr(Box* obj, const char* attr, Box* attr_val) {
......
......@@ -61,6 +61,14 @@ slots_tester_seq_repr(slots_tester_object *obj)
return PyString_FromString(buf);
}
static PyObject *
slots_tester_seq_str(slots_tester_object *obj)
{
char buf[80];
snprintf(buf, sizeof(buf), "<my custom str: %d>", obj->n);
return PyString_FromString(buf);
}
static PyObject *
slots_tester_seq_call(slots_tester_object *obj, PyObject *args, PyObject *kw)
{
......@@ -111,7 +119,7 @@ static PyTypeObject slots_tester_seq = {
0, /* tp_as_mapping */
(hashfunc)slots_tester_seq_hash, /* tp_hash */
(ternaryfunc)slots_tester_seq_call, /* tp_call */
0, /* tp_str */
(reprfunc)slots_tester_seq_str, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
......@@ -170,7 +178,7 @@ static PyTypeObject slots_tester_map= {
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
(reprfunc)slots_tester_seq_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
&slots_tester_map_asmapping, /* tp_as_mapping */
......@@ -202,6 +210,143 @@ static PyTypeObject slots_tester_map= {
0, /* tp_free */
};
#define _PYSTON_STRINGIFY(N) #N
#define PYSTON_STRINGIFY(N) _PYSTON_STRINGIFY(N)
#define CREATE_UN(N, R) \
static PyObject* N(slots_tester_object* lhs) { \
printf(PYSTON_STRINGIFY(N) ", %d\n", lhs->n); \
Py_INCREF(R); \
return (PyObject*)R; \
}
#define CREATE_BIN(N) \
static PyObject* N(slots_tester_object* lhs, PyObject* rhs) { \
printf(PYSTON_STRINGIFY(N) ", %d %s\n", lhs->n, Py_TYPE(rhs)->tp_name); \
Py_INCREF(lhs); \
return (PyObject*)lhs; \
}
CREATE_BIN(s_add);
CREATE_BIN(s_subtract);
CREATE_BIN(s_multiply);
CREATE_BIN(s_divide);
CREATE_BIN(s_remainder);
CREATE_BIN(s_divmod);
CREATE_UN(s_negative, lhs);
CREATE_UN(s_positive, lhs);
CREATE_UN(s_absolute, lhs);
static int s_nonzero(slots_tester_object* self) {
printf("s_nonzero, %d\n", self->n);
return self->n != 0;
}
CREATE_UN(s_invert, lhs);
static PyObject* s_power(slots_tester_object* lhs, PyObject* rhs, PyObject* mod) {
printf("s_power, %d %s %s\n", lhs->n, Py_TYPE(rhs)->tp_name, Py_TYPE(mod)->tp_name);
Py_INCREF(lhs);
return (PyObject*)lhs;
}
CREATE_BIN(s_lshift);
CREATE_BIN(s_rshift);
CREATE_BIN(s_and);
CREATE_BIN(s_xor);
CREATE_BIN(s_or);
CREATE_UN(s_int, Py_True);
CREATE_UN(s_long, Py_True);
CREATE_UN(s_float, PyFloat_FromDouble(1.0));
CREATE_UN(s_oct, PyString_FromString("oct"));
CREATE_UN(s_hex, PyString_FromString("hex"));
#undef CREATE_BIN
static PyNumberMethods slots_tester_as_number = {
(binaryfunc)s_add, /* nb_add */
(binaryfunc)s_subtract, /* nb_subtract */
(binaryfunc)s_multiply, /* nb_multiply */
(binaryfunc)s_divide, /* nb_divide */
(binaryfunc)s_remainder, /* nb_remainder */
(binaryfunc)s_divmod, /* nb_divmod */
(ternaryfunc)s_power, /* nb_power */
(unaryfunc)s_negative, /* nb_negative */
(unaryfunc)s_positive, /* nb_positive */
(unaryfunc)s_absolute, /* nb_absolute */
(inquiry)s_nonzero, /* nb_nonzero */
(unaryfunc)s_invert, /*nb_invert*/
(binaryfunc)s_lshift, /*nb_lshift*/
(binaryfunc)s_rshift, /*nb_rshift*/
(binaryfunc)s_and, /*nb_and*/
(binaryfunc)s_xor, /*nb_xor*/
(binaryfunc)s_or, /*nb_or*/
0, /*nb_coerce*/
(unaryfunc)s_int, /*nb_int*/
(unaryfunc)s_long, /*nb_long*/
(unaryfunc)s_float, /*nb_float*/
(unaryfunc)s_oct, /*nb_oct*/
(unaryfunc)s_hex, /*nb_hex*/
0, /*nb_inplace_add*/
0, /*nb_inplace_subtract*/
0, /*nb_inplace_multiply*/
0, /*nb_inplace_divide*/
0, /*nb_inplace_remainder*/
0, /*nb_inplace_power*/
0, /*nb_inplace_lshift*/
0, /*nb_inplace_rshift*/
0, /*nb_inplace_and*/
0, /*nb_inplace_xor*/
0, /*nb_inplace_or*/
0, /* nb_floor_divide */
0, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
};
static PyTypeObject slots_tester_num = {
PyVarObject_HEAD_INIT(NULL, 0)
"slots_test.slots_tester_num", /* tp_name */
sizeof(slots_tester_object), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
&slots_tester_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
(reprfunc)slots_tester_seq_str, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
slots_tester_new, /* tp_new */
0, /* tp_free */
};
// Tests the correctness of the CAPI slots when the attributes get set in Python code:
static PyObject *
call_funcs(PyObject* _module, PyObject* args) {
......@@ -282,6 +427,69 @@ call_funcs(PyObject* _module, PyObject* args) {
printf("tp_as_sequence doesnt exist\n");
}
if (cls->tp_as_number) {
printf("tp_as_number exists\n");
PyNumberMethods* num = cls->tp_as_number;
if (!(cls->tp_flags & Py_TPFLAGS_CHECKTYPES)) {
printf("CHECKTYPES is not set!\n");
}
#define CHECK_UN(N) \
if (num->N) { \
PyObject* res = num->N(obj); \
printf(PYSTON_STRINGIFY(N) " exists and returned a %s\n", Py_TYPE(res)->tp_name); \
Py_DECREF(res); \
}
#define CHECK_BIN(N) \
if (num->N) { \
PyObject* res = num->N(obj, obj); \
printf(PYSTON_STRINGIFY(N) " exists and returned a %s\n", Py_TYPE(res)->tp_name); \
Py_DECREF(res); \
}
CHECK_BIN(nb_add);
CHECK_BIN(nb_subtract);
CHECK_BIN(nb_multiply);
CHECK_BIN(nb_divide);
CHECK_BIN(nb_remainder);
CHECK_BIN(nb_divmod);
CHECK_UN(nb_negative);
CHECK_UN(nb_positive);
CHECK_UN(nb_absolute);
if (num->nb_nonzero) {
int n = num->nb_nonzero(obj);
printf("nb_nonzero exists and returned %d\n", n);
}
CHECK_UN(nb_invert);
if (num->nb_power) {
PyObject* res = num->nb_power(obj, obj, Py_None);
printf("nb_power exists and returned a %s\n", Py_TYPE(res)->tp_name);
Py_DECREF(res);
}
CHECK_BIN(nb_lshift);
CHECK_BIN(nb_rshift);
CHECK_BIN(nb_and);
CHECK_BIN(nb_xor);
CHECK_BIN(nb_or);
CHECK_UN(nb_int);
CHECK_UN(nb_long);
CHECK_UN(nb_float);
CHECK_UN(nb_oct);
CHECK_UN(nb_hex);
#undef CHECK_BIN
} else {
printf("tp_as_number doesnt exist\n");
}
Py_RETURN_NONE;
}
......@@ -307,9 +515,14 @@ initslots_test(void)
if (res < 0)
return;
res = PyType_Ready(&slots_tester_num);
if (res < 0)
return;
// Not sure if the result of PyInt_FromLong needs to be decref'd
PyDict_SetItemString(slots_tester_seq.tp_dict, "set_through_tpdict", PyInt_FromLong(123));
PyModule_AddObject(m, "SlotsTesterSeq", (PyObject *)&slots_tester_seq);
PyModule_AddObject(m, "SlotsTesterMap", (PyObject *)&slots_tester_map);
PyModule_AddObject(m, "SlotsTesterNum", (PyObject *)&slots_tester_num);
}
......@@ -2,18 +2,43 @@ import slots_test
for i in xrange(3):
t = slots_test.SlotsTesterSeq(i + 5)
print t, repr(t), t(), t[2]
print hash(t), t < 1, t > 2, t != 3
print t, repr(t), str(t), t(), t[2]
print hash(t), t < 1, t > 2, t != 3, bool(t)
# print slots_test.SlotsTesterSeq.__doc__
print slots_test.SlotsTesterSeq.set_through_tpdict, slots_test.SlotsTesterSeq(5).set_through_tpdict
for i in xrange(3):
t = slots_test.SlotsTesterMap(i + 5)
print len(t), t[2]
print len(t), t[2], repr(t), str(t)
t[1] = 5
del t[2]
for i in xrange(3):
t = slots_test.SlotsTesterNum(i)
print bool(t)
print t + 5
print t - 5
print t * 5
print t / 5
print t % 5
print divmod(t, 5)
print t ** 5
print t << 5
print t >> 5
print t & 5
print t ^ 5
print t | 5
print +t
print -t
print abs(t)
print ~t
print int(t)
print long(t)
print float(t)
print hex(t)
print oct(t)
class C(object):
def __repr__(self):
print "__repr__()"
......@@ -33,4 +58,14 @@ slots_test.call_funcs(C())
def repr2(self):
return "repr2()"
C.__repr__ = repr2
def nonzero(self):
print "nonzero"
return True
C.__nonzero__ = nonzero
def add(self, rhs):
print "add", self, rhs
C.__add__ = add
slots_test.call_funcs(C())
......@@ -350,7 +350,7 @@ if __name__ == "__main__":
run_memcheck = False
start = 1
opts, patterns = getopt.gnu_getopt(sys.argv[1:], "j:a:t:mR:k")
opts, patterns = getopt.gnu_getopt(sys.argv[1:], "j:a:t:mR:kK")
for (t, v) in opts:
if t == '-m':
run_memcheck = True
......@@ -361,6 +361,8 @@ if __name__ == "__main__":
IMAGE = v
elif t == '-k':
KEEP_GOING = True
elif t == '-K':
KEEP_GOING = False
elif t == '-a':
EXTRA_JIT_ARGS.append(v)
elif t == '-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