Commit b8cd6e68 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #577 from kmod/tp_richcompare

tp_richcompare
parents cd6654bb f97bfec2
...@@ -119,7 +119,7 @@ diff --git a/src/mi/dyn-register.c b/src/mi/dyn-register.c ...@@ -119,7 +119,7 @@ diff --git a/src/mi/dyn-register.c b/src/mi/dyn-register.c
index c28954a..c4f88b1 100644 index c28954a..c4f88b1 100644
--- a/src/mi/dyn-register.c --- a/src/mi/dyn-register.c
+++ b/src/mi/dyn-register.c +++ b/src/mi/dyn-register.c
@@ -32,13 +32,28 @@ _U_dyn_register (unw_dyn_info_t *di) @@ -32,13 +32,27 @@ _U_dyn_register (unw_dyn_info_t *di)
{ {
mutex_lock (&_U_dyn_info_list_lock); mutex_lock (&_U_dyn_info_list_lock);
{ {
...@@ -148,8 +148,7 @@ index c28954a..c4f88b1 100644 ...@@ -148,8 +148,7 @@ index c28954a..c4f88b1 100644
+ break; + break;
+ } + }
+ +
+ if (_U_dyn_info_list_size > 1) + memmove(&_U_dyn_info_list[i+1], &_U_dyn_info_list[i], (_U_dyn_info_list_size - i) * sizeof(unw_dyn_info_t*));
+ memmove(&_U_dyn_info_list[i+1], &_U_dyn_info_list[i], (_U_dyn_info_list_size - i) * sizeof(unw_dyn_info_t*));
+ _U_dyn_info_list[i] = di; + _U_dyn_info_list[i] = di;
+ _U_dyn_info_list_size ++; + _U_dyn_info_list_size ++;
} }
......
...@@ -764,7 +764,7 @@ static int try_3way_compare(PyObject* v, PyObject* w) { ...@@ -764,7 +764,7 @@ static int try_3way_compare(PyObject* v, PyObject* w) {
0 if v == w; 0 if v == w;
1 if v > w. 1 if v > w.
*/ */
static int default_3way_compare(PyObject* v, PyObject* w) { /* Pyston change: static*/ int default_3way_compare(PyObject* v, PyObject* w) {
int c; int c;
const char* vname, *wname; const char* vname, *wname;
...@@ -865,7 +865,7 @@ extern "C" int PyObject_Compare(PyObject* v, PyObject* w) noexcept { ...@@ -865,7 +865,7 @@ extern "C" int PyObject_Compare(PyObject* v, PyObject* w) noexcept {
} }
/* Return (new reference to) Py_True or Py_False. */ /* Return (new reference to) Py_True or Py_False. */
static PyObject* convert_3way_to_object(int op, int c) noexcept { /* Pyston change: static */ PyObject* convert_3way_to_object(int op, int c) noexcept {
PyObject* result; PyObject* result;
switch (op) { switch (op) {
case Py_LT: case Py_LT:
......
...@@ -761,7 +761,15 @@ static PyObject* half_richcompare(PyObject* self, PyObject* other, int op) noexc ...@@ -761,7 +761,15 @@ static PyObject* half_richcompare(PyObject* self, PyObject* other, int op) noexc
return res; return res;
} }
static PyObject* slot_tp_richcompare(PyObject* self, PyObject* other, int op) noexcept { /* Pyston change: static*/ PyObject* slot_tp_richcompare(PyObject* self, PyObject* other, int op) noexcept {
static StatCounter slowpath_richcompare("slowpath_richcompare");
slowpath_richcompare.log();
#if 0
std::string per_name_stat_name = "slowpath_richcompare." + std::string(self->cls->tp_name);
int id = Stats::getStatId(per_name_stat_name);
Stats::log(id);
#endif
PyObject* res; PyObject* res;
if (Py_TYPE(self)->tp_richcompare == slot_tp_richcompare) { if (Py_TYPE(self)->tp_richcompare == slot_tp_richcompare) {
......
...@@ -33,6 +33,8 @@ void commonClassSetup(BoxedClass* cls); ...@@ -33,6 +33,8 @@ void commonClassSetup(BoxedClass* cls);
PyTypeObject* best_base(PyObject* bases) noexcept; PyTypeObject* best_base(PyObject* bases) noexcept;
PyObject* mro_external(PyObject* self) noexcept; PyObject* mro_external(PyObject* self) noexcept;
int type_set_bases(PyTypeObject* type, PyObject* value, void* context) noexcept; int type_set_bases(PyTypeObject* type, PyObject* value, void* context) noexcept;
PyObject* slot_tp_richcompare(PyObject* self, PyObject* other, int op) noexcept;
} }
#endif #endif
...@@ -237,6 +237,9 @@ public: ...@@ -237,6 +237,9 @@ public:
} }
}; };
PyObject* convert_3way_to_object(int op, int c) noexcept;
int default_3way_compare(PyObject* v, PyObject* w);
} // namespace pyston } // namespace pyston
#endif #endif
...@@ -162,10 +162,11 @@ extern "C" Box* min(Box* arg0, BoxedTuple* args) { ...@@ -162,10 +162,11 @@ extern "C" Box* min(Box* arg0, BoxedTuple* args) {
if (!minElement) { if (!minElement) {
minElement = e; minElement = e;
} else { } else {
Box* comp_result = compareInternal(minElement, e, AST_TYPE::Gt, NULL); int r = PyObject_RichCompareBool(minElement, e, Py_GT);
if (nonzero(comp_result)) { if (r == -1)
throwCAPIException();
if (r)
minElement = e; minElement = e;
}
} }
} }
...@@ -192,10 +193,11 @@ extern "C" Box* max(Box* arg0, BoxedTuple* args) { ...@@ -192,10 +193,11 @@ extern "C" Box* max(Box* arg0, BoxedTuple* args) {
if (!maxElement) { if (!maxElement) {
maxElement = e; maxElement = e;
} else { } else {
Box* comp_result = compareInternal(maxElement, e, AST_TYPE::Lt, NULL); int r = PyObject_RichCompareBool(maxElement, e, Py_LT);
if (nonzero(comp_result)) { if (r == -1)
throwCAPIException();
if (r)
maxElement = e; maxElement = e;
}
} }
} }
......
...@@ -586,8 +586,11 @@ extern "C" long _Py_HashPointer(void* p) noexcept { ...@@ -586,8 +586,11 @@ extern "C" long _Py_HashPointer(void* p) noexcept {
} }
extern "C" int PyObject_IsTrue(PyObject* o) noexcept { extern "C" int PyObject_IsTrue(PyObject* o) noexcept {
if (o->cls == bool_cls)
return o == True;
try { try {
return nonzero(o); return o->nonzeroIC();
} catch (ExcInfo e) { } catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); fatalOrError(PyExc_NotImplementedError, "unimplemented");
return -1; return -1;
...@@ -1647,6 +1650,13 @@ static Box* methodGetDoc(Box* b, void*) { ...@@ -1647,6 +1650,13 @@ static Box* methodGetDoc(Box* b, void*) {
return None; return None;
} }
static Box* wrapperdescrGetDoc(Box* b, void*) {
assert(b->cls == wrapperdescr_cls);
auto s = static_cast<BoxedWrapperDescriptor*>(b)->wrapper->doc;
assert(s.size());
return boxString(s);
}
/* extension modules might be compiled with GC support so these /* extension modules might be compiled with GC support so these
functions must always be available */ functions must always be available */
...@@ -1735,6 +1745,8 @@ void setupCAPI() { ...@@ -1735,6 +1745,8 @@ void setupCAPI() {
new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3))); new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3)));
wrapperdescr_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__call__, wrapperdescr_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__call__,
UNKNOWN, 2, 0, true, true))); UNKNOWN, 2, 0, true, true)));
wrapperdescr_cls->giveAttr("__doc__",
new (pyston_getset_cls) BoxedGetsetDescriptor(wrapperdescrGetDoc, NULL, NULL));
wrapperdescr_cls->freeze(); wrapperdescr_cls->freeze();
wrapperobject_cls->giveAttr( wrapperobject_cls->giveAttr(
......
...@@ -566,109 +566,6 @@ extern "C" Box* intTruediv(BoxedInt* lhs, Box* rhs) { ...@@ -566,109 +566,6 @@ extern "C" Box* intTruediv(BoxedInt* lhs, Box* rhs) {
} }
} }
extern "C" Box* intEqInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n == rhs->n);
}
extern "C" Box* intEq(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__eq__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (isSubclass(rhs->cls, int_cls)) {
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n == rhs_int->n);
} else {
return NotImplemented;
}
}
extern "C" Box* intNeInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n != rhs->n);
}
extern "C" Box* intNe(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__ne__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n != rhs_int->n);
}
extern "C" Box* intLtInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n < rhs->n);
}
extern "C" Box* intLt(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__lt__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n < rhs_int->n);
}
extern "C" Box* intLeInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n <= rhs->n);
}
extern "C" Box* intLe(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__le__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n <= rhs_int->n);
}
extern "C" Box* intGtInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n > rhs->n);
}
extern "C" Box* intGt(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__gt__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n > rhs_int->n);
}
extern "C" Box* intGeInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n >= rhs->n);
}
extern "C" Box* intGe(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__ge__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n >= rhs_int->n);
}
extern "C" Box* intLShiftInt(BoxedInt* lhs, BoxedInt* rhs) { extern "C" Box* intLShiftInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls)); assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls)); assert(isSubclass(rhs->cls, int_cls));
...@@ -1119,6 +1016,33 @@ static int64_t int_hash(BoxedInt* o) noexcept { ...@@ -1119,6 +1016,33 @@ static int64_t int_hash(BoxedInt* o) noexcept {
return n; return n;
} }
static PyObject* int_richcompare(PyObject* v, PyObject* w, int op) noexcept {
if (!PyInt_Check(v) || !PyInt_Check(w)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
int64_t lhs = static_cast<BoxedInt*>(v)->n;
int64_t rhs = static_cast<BoxedInt*>(w)->n;
switch (op) {
case Py_EQ:
return boxBool(lhs == rhs);
case Py_NE:
return boxBool(lhs != rhs);
case Py_LT:
return boxBool(lhs < rhs);
case Py_LE:
return boxBool(lhs <= rhs);
case Py_GT:
return boxBool(lhs > rhs);
case Py_GE:
return boxBool(lhs >= rhs);
default:
RELEASE_ASSERT(0, "%d", op);
}
}
void setupInt() { void setupInt() {
for (int i = 0; i < NUM_INTERNED_INTS; i++) { for (int i = 0; i < NUM_INTERNED_INTS; i++) {
interned_ints[i] = new BoxedInt(i); interned_ints[i] = new BoxedInt(i);
...@@ -1138,12 +1062,8 @@ void setupInt() { ...@@ -1138,12 +1062,8 @@ void setupInt() {
int_cls->giveAttr("__pow__", int_cls->giveAttr("__pow__",
new BoxedFunction(boxRTFunction((void*)intPow, UNKNOWN, 3, 1, false, false), { None })); new BoxedFunction(boxRTFunction((void*)intPow, UNKNOWN, 3, 1, false, false), { None }));
_addFuncIntUnknown("__eq__", BOXED_BOOL, (void*)intEqInt, (void*)intEq); // Note: CPython implements int comparisons using tp_compare
_addFuncIntUnknown("__ne__", BOXED_BOOL, (void*)intNeInt, (void*)intNe); int_cls->tp_richcompare = int_richcompare;
_addFuncIntUnknown("__lt__", BOXED_BOOL, (void*)intLtInt, (void*)intLt);
_addFuncIntUnknown("__le__", BOXED_BOOL, (void*)intLeInt, (void*)intLe);
_addFuncIntUnknown("__gt__", BOXED_BOOL, (void*)intGtInt, (void*)intGt);
_addFuncIntUnknown("__ge__", BOXED_BOOL, (void*)intGeInt, (void*)intGe);
_addFuncIntUnknown("__lshift__", UNKNOWN, (void*)intLShiftInt, (void*)intLShift); _addFuncIntUnknown("__lshift__", UNKNOWN, (void*)intLShiftInt, (void*)intLShift);
_addFuncIntUnknown("__rshift__", UNKNOWN, (void*)intRShiftInt, (void*)intRShift); _addFuncIntUnknown("__rshift__", UNKNOWN, (void*)intRShiftInt, (void*)intRShift);
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "capi/typeobject.h"
#include "capi/types.h"
#include "core/common.h" #include "core/common.h"
#include "core/options.h" #include "core/options.h"
#include "core/stats.h" #include "core/stats.h"
...@@ -846,104 +848,18 @@ extern "C" Box* longXor(BoxedLong* v1, Box* _v2) { ...@@ -846,104 +848,18 @@ extern "C" Box* longXor(BoxedLong* v1, Box* _v2) {
return NotImplemented; return NotImplemented;
} }
// TODO reduce duplication between these 6 functions, and add double support static PyObject* long_richcompare(Box* _v1, Box* _v2, int op) noexcept {
Box* longGt(BoxedLong* v1, Box* _v2) { RELEASE_ASSERT(isSubclass(_v1->cls, long_cls), "");
if (!isSubclass(v1->cls, long_cls)) BoxedLong* v1 = static_cast<BoxedLong*>(_v1);
raiseExcHelper(TypeError, "descriptor '__gt__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) > 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) > 0);
} else {
return NotImplemented;
}
}
Box* longGe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__ge__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) >= 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) >= 0);
} else {
return NotImplemented;
}
}
Box* longLt(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__lt__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) < 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) < 0);
} else {
return NotImplemented;
}
}
Box* longLe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__le__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) <= 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) <= 0);
} else {
return NotImplemented;
}
}
Box* longEq(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__eq__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) == 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) == 0);
} else {
return NotImplemented;
}
}
Box* longNe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__ne__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) { if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2); BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) != 0); return convert_3way_to_object(op, mpz_cmp(v1->n, v2->n));
} else if (isSubclass(_v2->cls, int_cls)) { } else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2); BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) != 0); return convert_3way_to_object(op, mpz_cmp_si(v1->n, v2->n));
} else { } else {
return NotImplemented; return NotImplemented;
} }
...@@ -1457,12 +1373,8 @@ void setupLong() { ...@@ -1457,12 +1373,8 @@ void setupLong() {
long_cls->giveAttr("__xor__", new BoxedFunction(boxRTFunction((void*)longXor, UNKNOWN, 2))); long_cls->giveAttr("__xor__", new BoxedFunction(boxRTFunction((void*)longXor, UNKNOWN, 2)));
long_cls->giveAttr("__rxor__", long_cls->getattr("__xor__")); long_cls->giveAttr("__rxor__", long_cls->getattr("__xor__"));
long_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)longGt, UNKNOWN, 2))); // Note: CPython implements long comparisons using tp_compare
long_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)longGe, UNKNOWN, 2))); long_cls->tp_richcompare = long_richcompare;
long_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)longLt, UNKNOWN, 2)));
long_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)longLe, UNKNOWN, 2)));
long_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)longEq, UNKNOWN, 2)));
long_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)longNe, UNKNOWN, 2)));
long_cls->giveAttr("__lshift__", new BoxedFunction(boxRTFunction((void*)longLshift, UNKNOWN, 2))); long_cls->giveAttr("__lshift__", new BoxedFunction(boxRTFunction((void*)longLshift, UNKNOWN, 2)));
long_cls->giveAttr("__rshift__", new BoxedFunction(boxRTFunction((void*)longRshift, UNKNOWN, 2))); long_cls->giveAttr("__rshift__", new BoxedFunction(boxRTFunction((void*)longRshift, UNKNOWN, 2)));
...@@ -1488,6 +1400,7 @@ void setupLong() { ...@@ -1488,6 +1400,7 @@ void setupLong() {
long_cls->giveAttr("numerator", new (pyston_getset_cls) BoxedGetsetDescriptor(longLong, NULL, NULL)); long_cls->giveAttr("numerator", new (pyston_getset_cls) BoxedGetsetDescriptor(longLong, NULL, NULL));
long_cls->giveAttr("denominator", new (pyston_getset_cls) BoxedGetsetDescriptor(long1, NULL, NULL)); long_cls->giveAttr("denominator", new (pyston_getset_cls) BoxedGetsetDescriptor(long1, NULL, NULL));
add_operators(long_cls);
long_cls->freeze(); long_cls->freeze();
long_cls->tp_as_number->nb_power = long_pow; long_cls->tp_as_number->nb_power = long_pow;
......
...@@ -137,26 +137,19 @@ size_t PyHasher::operator()(Box* b) const { ...@@ -137,26 +137,19 @@ size_t PyHasher::operator()(Box* b) const {
bool PyEq::operator()(Box* lhs, Box* rhs) const { bool PyEq::operator()(Box* lhs, Box* rhs) const {
STAT_TIMER(t0, "us_timer_PyEq"); STAT_TIMER(t0, "us_timer_PyEq");
if (lhs == rhs) int r = PyObject_RichCompareBool(lhs, rhs, Py_EQ);
return true; if (r == -1)
throwCAPIException();
if (lhs->cls == rhs->cls) { return (bool)r;
if (lhs->cls == str_cls) {
return static_cast<BoxedString*>(lhs)->s() == static_cast<BoxedString*>(rhs)->s();
}
}
// TODO fix this
Box* cmp = compareInternal(lhs, rhs, AST_TYPE::Eq, NULL);
return cmp->nonzeroIC();
} }
bool PyLt::operator()(Box* lhs, Box* rhs) const { bool PyLt::operator()(Box* lhs, Box* rhs) const {
STAT_TIMER(t0, "us_timer_PyLt"); STAT_TIMER(t0, "us_timer_PyLt");
// TODO fix this int r = PyObject_RichCompareBool(lhs, rhs, Py_LT);
Box* cmp = compareInternal(lhs, rhs, AST_TYPE::Lt, NULL); if (r == -1)
return cmp->nonzeroIC(); throwCAPIException();
return (bool)r;
} }
extern "C" Box* deopt(AST_expr* expr, Box* value) { extern "C" Box* deopt(AST_expr* expr, Box* value) {
...@@ -3705,6 +3698,11 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -3705,6 +3698,11 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
return boxBool(b); return boxBool(b);
} }
if (isUserDefined(lhs->cls) || isUserDefined(rhs->cls)) {
rewrite_args = NULL;
REWRITE_ABORTED("");
}
// Can do the guard checks after the Is/IsNot handling, since that is // Can do the guard checks after the Is/IsNot handling, since that is
// irrespective of the object classes // irrespective of the object classes
if (rewrite_args) { if (rewrite_args) {
...@@ -3717,6 +3715,48 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -3717,6 +3715,48 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
rewrite_args->rhs->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)rhs->cls); rewrite_args->rhs->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)rhs->cls);
} }
// TODO: switch from our op types to cpythons
int cpython_op_type;
switch (op_type) {
case AST_TYPE::Eq:
cpython_op_type = Py_EQ;
break;
case AST_TYPE::NotEq:
cpython_op_type = Py_NE;
break;
case AST_TYPE::Lt:
cpython_op_type = Py_LT;
break;
case AST_TYPE::LtE:
cpython_op_type = Py_LE;
break;
case AST_TYPE::Gt:
cpython_op_type = Py_GT;
break;
case AST_TYPE::GtE:
cpython_op_type = Py_GE;
break;
default:
RELEASE_ASSERT(0, "%d", op_type);
}
if (rewrite_args && lhs->cls == rhs->cls && !PyInstance_Check(lhs) && lhs->cls->tp_richcompare != NULL
&& lhs->cls->tp_richcompare != slot_tp_richcompare) {
// This branch is the `v->ob_type == w->ob_type` branch of PyObject_RichCompare, but
// simplified by using the assumption that tp_richcompare exists and never returns NotImplemented
// for builtin types when both arguments are the right type.
assert(!isUserDefined(lhs->cls));
Box* r = lhs->cls->tp_richcompare(lhs, rhs, cpython_op_type);
RELEASE_ASSERT(r != NotImplemented, "%s returned notimplemented?", lhs->cls->tp_name);
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)lhs->cls->tp_richcompare, rewrite_args->lhs, rewrite_args->rhs,
rewrite_args->rewriter->loadConst(cpython_op_type));
rewrite_args->out_success = true;
return r;
}
const std::string& op_name = getOpName(op_type); const std::string& op_name = getOpName(op_type);
Box* lrtn; Box* lrtn;
...@@ -3735,11 +3775,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -3735,11 +3775,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
if (lrtn) { if (lrtn) {
if (lrtn != NotImplemented) { if (lrtn != NotImplemented) {
bool can_patchpoint = !isUserDefined(lhs->cls) && !isUserDefined(rhs->cls);
if (rewrite_args) { if (rewrite_args) {
if (can_patchpoint) { rewrite_args->out_success = true;
rewrite_args->out_success = true;
}
} }
return lrtn; return lrtn;
} }
...@@ -3783,38 +3820,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -3783,38 +3820,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
} }
#endif #endif
// TODO int c = default_3way_compare(lhs, rhs);
// According to http://docs.python.org/2/library/stdtypes.html#comparisons return convert_3way_to_object(cpython_op_type, c);
// CPython implementation detail: Objects of different types except numbers are ordered by their type names; objects
// of the same types that don’t support proper comparison are ordered by their address.
if (op_type == AST_TYPE::Gt || op_type == AST_TYPE::GtE || op_type == AST_TYPE::Lt || op_type == AST_TYPE::LtE) {
intptr_t cmp1, cmp2;
if (lhs->cls == rhs->cls) {
cmp1 = (intptr_t)lhs;
cmp2 = (intptr_t)rhs;
} else {
// This isn't really necessary, but try to make sure that numbers get sorted first
if (lhs->cls == int_cls || lhs->cls == float_cls)
cmp1 = 0;
else
cmp1 = (intptr_t)lhs->cls;
if (rhs->cls == int_cls || rhs->cls == float_cls)
cmp2 = 0;
else
cmp2 = (intptr_t)rhs->cls;
}
if (op_type == AST_TYPE::Gt)
return boxBool(cmp1 > cmp2);
if (op_type == AST_TYPE::GtE)
return boxBool(cmp1 >= cmp2);
if (op_type == AST_TYPE::Lt)
return boxBool(cmp1 < cmp2);
if (op_type == AST_TYPE::LtE)
return boxBool(cmp1 <= cmp2);
}
RELEASE_ASSERT(0, "%d", op_type);
} }
extern "C" Box* compare(Box* lhs, Box* rhs, int op_type) { extern "C" Box* compare(Box* lhs, Box* rhs, int op_type) {
...@@ -3827,21 +3834,52 @@ extern "C" Box* compare(Box* lhs, Box* rhs, int op_type) { ...@@ -3827,21 +3834,52 @@ extern "C" Box* compare(Box* lhs, Box* rhs, int op_type) {
std::unique_ptr<Rewriter> rewriter( std::unique_ptr<Rewriter> rewriter(
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, "compare")); Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, "compare"));
Box* rtn;
if (rewriter.get()) { if (rewriter.get()) {
// rewriter->trap(); // rewriter->trap();
CompareRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(1), CompareRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(1),
rewriter->getReturnDestination()); rewriter->getReturnDestination());
rtn = compareInternal(lhs, rhs, op_type, &rewrite_args); Box* rtn = compareInternal(lhs, rhs, op_type, &rewrite_args);
if (!rewrite_args.out_success) { if (!rewrite_args.out_success) {
rewriter.reset(NULL); rewriter.reset(NULL);
} else } else
rewriter->commitReturning(rewrite_args.out_rtn); rewriter->commitReturning(rewrite_args.out_rtn);
return rtn;
} else { } else {
rtn = compareInternal(lhs, rhs, op_type, NULL); // TODO: switch from our op types to cpythons
int cpython_op_type;
if (op_type == AST_TYPE::In || op_type == AST_TYPE::NotIn)
return compareInternal(lhs, rhs, op_type, NULL);
if (op_type == AST_TYPE::Is)
return boxBool(lhs == rhs);
if (op_type == AST_TYPE::IsNot)
return boxBool(lhs != rhs);
switch (op_type) {
case AST_TYPE::Eq:
cpython_op_type = Py_EQ;
break;
case AST_TYPE::NotEq:
cpython_op_type = Py_NE;
break;
case AST_TYPE::Lt:
cpython_op_type = Py_LT;
break;
case AST_TYPE::LtE:
cpython_op_type = Py_LE;
break;
case AST_TYPE::Gt:
cpython_op_type = Py_GT;
break;
case AST_TYPE::GtE:
cpython_op_type = Py_GE;
break;
default:
RELEASE_ASSERT(0, "%d", op_type);
}
Box* r = PyObject_RichCompare(lhs, rhs, cpython_op_type);
if (!r)
throwCAPIException();
return r;
} }
return rtn;
} }
extern "C" Box* unaryop(Box* operand, int op_type) { extern "C" Box* unaryop(Box* operand, int op_type) {
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "Python.h" #include "Python.h"
#include "capi/typeobject.h"
#include "capi/types.h" #include "capi/types.h"
#include "core/common.h" #include "core/common.h"
#include "core/types.h" #include "core/types.h"
...@@ -1154,64 +1155,46 @@ extern "C" Box* strMul(BoxedString* lhs, Box* rhs) { ...@@ -1154,64 +1155,46 @@ extern "C" Box* strMul(BoxedString* lhs, Box* rhs) {
return boxString(buf); return boxString(buf);
} }
extern "C" Box* strLt(BoxedString* lhs, Box* rhs) { Box* str_richcompare(Box* lhs, Box* rhs, int op) {
assert(isSubclass(lhs->cls, str_cls)); assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls)) // Note: it is somehow about 50% faster to do this check inside the switch
return NotImplemented; // statement, rather than out here. It's functionally equivalent but the
// generated assembly is somehow quite better:
BoxedString* srhs = static_cast<BoxedString*>(rhs); // if (unlikely(!PyString_Check(rhs)))
return boxBool(lhs->s() < srhs->s()); // return NotImplemented;
}
extern "C" Box* strLe(BoxedString* lhs, Box* rhs) {
assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls))
return NotImplemented;
BoxedString* slhs = static_cast<BoxedString*>(lhs);
BoxedString* srhs = static_cast<BoxedString*>(rhs); BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s() <= srhs->s());
}
extern "C" Box* strGt(BoxedString* lhs, Box* rhs) { switch (op) {
assert(isSubclass(lhs->cls, str_cls)); case Py_EQ:
if (unlikely(!PyString_Check(rhs)))
if (!isSubclass(rhs->cls, str_cls)) return NotImplemented;
return NotImplemented; return boxBool(slhs->s() == srhs->s());
case Py_NE:
BoxedString* srhs = static_cast<BoxedString*>(rhs); if (unlikely(!PyString_Check(rhs)))
return boxBool(lhs->s() > srhs->s()); return NotImplemented;
} return boxBool(slhs->s() != srhs->s());
case Py_LT:
extern "C" Box* strGe(BoxedString* lhs, Box* rhs) { if (unlikely(!PyString_Check(rhs)))
assert(isSubclass(lhs->cls, str_cls)); return NotImplemented;
return boxBool(slhs->s() < srhs->s());
if (!isSubclass(rhs->cls, str_cls)) case Py_LE:
return NotImplemented; if (unlikely(!PyString_Check(rhs)))
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs); return boxBool(slhs->s() <= srhs->s());
return boxBool(lhs->s() >= srhs->s()); case Py_GT:
} if (unlikely(!PyString_Check(rhs)))
return NotImplemented;
extern "C" Box* strEq(BoxedString* lhs, Box* rhs) { return boxBool(slhs->s() > srhs->s());
assert(isSubclass(lhs->cls, str_cls)); case Py_GE:
if (unlikely(!PyString_Check(rhs)))
if (!isSubclass(rhs->cls, str_cls)) return NotImplemented;
return NotImplemented; return boxBool(slhs->s() >= srhs->s());
default:
BoxedString* srhs = static_cast<BoxedString*>(rhs); llvm_unreachable("invalid op");
return boxBool(lhs->s() == srhs->s()); }
}
extern "C" Box* strNe(BoxedString* lhs, Box* rhs) {
assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls))
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s() != srhs->s());
} }
#define JUST_LEFT 0 #define JUST_LEFT 0
...@@ -2734,12 +2717,7 @@ void setupStr() { ...@@ -2734,12 +2717,7 @@ void setupStr() {
// TODO not sure if this is right in all cases: // TODO not sure if this is right in all cases:
str_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2))); str_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
str_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)strLt, UNKNOWN, 2))); str_cls->tp_richcompare = str_richcompare;
str_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)strLe, UNKNOWN, 2)));
str_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)strGt, UNKNOWN, 2)));
str_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)strGe, UNKNOWN, 2)));
str_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)strEq, UNKNOWN, 2)));
str_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)strNe, UNKNOWN, 2)));
BoxedString* spaceChar = boxStrConstant(" "); BoxedString* spaceChar = boxStrConstant(" ");
str_cls->giveAttr("ljust", str_cls->giveAttr("ljust",
...@@ -2763,6 +2741,7 @@ void setupStr() { ...@@ -2763,6 +2741,7 @@ void setupStr() {
str_cls->giveAttr("__new__", str_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)strNew, UNKNOWN, 2, 1, false, false), { EmptyString })); new BoxedFunction(boxRTFunction((void*)strNew, UNKNOWN, 2, 1, false, false), { EmptyString }));
add_operators(str_cls);
str_cls->freeze(); str_cls->freeze();
basestring_cls->giveAttr( basestring_cls->giveAttr(
......
...@@ -225,89 +225,6 @@ Box* tupleRepr(BoxedTuple* t) { ...@@ -225,89 +225,6 @@ Box* tupleRepr(BoxedTuple* t) {
return boxString(os.str()); return boxString(os.str());
} }
Box* _tupleCmp(BoxedTuple* lhs, BoxedTuple* rhs, AST_TYPE::AST_TYPE op_type) {
int lsz = lhs->size();
int rsz = rhs->size();
bool is_order
= (op_type == AST_TYPE::Lt || op_type == AST_TYPE::LtE || op_type == AST_TYPE::Gt || op_type == AST_TYPE::GtE);
int n = std::min(lsz, rsz);
for (int i = 0; i < n; i++) {
Box* is_eq = compareInternal(lhs->elts[i], rhs->elts[i], AST_TYPE::Eq, NULL);
bool bis_eq = nonzero(is_eq);
if (bis_eq)
continue;
if (op_type == AST_TYPE::Eq) {
return boxBool(false);
} else if (op_type == AST_TYPE::NotEq) {
return boxBool(true);
} else {
Box* r = compareInternal(lhs->elts[i], rhs->elts[i], op_type, NULL);
return r;
}
}
if (op_type == AST_TYPE::Lt)
return boxBool(lsz < rsz);
else if (op_type == AST_TYPE::LtE)
return boxBool(lsz <= rsz);
else if (op_type == AST_TYPE::Gt)
return boxBool(lsz > rsz);
else if (op_type == AST_TYPE::GtE)
return boxBool(lsz >= rsz);
else if (op_type == AST_TYPE::Eq)
return boxBool(lsz == rsz);
else if (op_type == AST_TYPE::NotEq)
return boxBool(lsz != rsz);
RELEASE_ASSERT(0, "%d", op_type);
}
Box* tupleLt(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::Lt);
}
Box* tupleLe(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::LtE);
}
Box* tupleGt(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::Gt);
}
Box* tupleGe(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::GtE);
}
Box* tupleEq(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::Eq);
}
Box* tupleNe(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::NotEq);
}
Box* tupleNonzero(BoxedTuple* self) { Box* tupleNonzero(BoxedTuple* self) {
RELEASE_ASSERT(isSubclass(self->cls, tuple_cls), ""); RELEASE_ASSERT(isSubclass(self->cls, tuple_cls), "");
return boxBool(self->size() != 0); return boxBool(self->size() != 0);
...@@ -442,6 +359,90 @@ static int64_t tuple_hash(BoxedTuple* v) noexcept { ...@@ -442,6 +359,90 @@ static int64_t tuple_hash(BoxedTuple* v) noexcept {
return x; return x;
} }
static PyObject* tuplerichcompare(PyObject* v, PyObject* w, int op) noexcept {
BoxedTuple* vt, *wt;
Py_ssize_t i;
Py_ssize_t vlen, wlen;
if (!PyTuple_Check(v) || !PyTuple_Check(w)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
vt = (BoxedTuple*)v;
wt = (BoxedTuple*)w;
vlen = Py_SIZE(vt);
wlen = Py_SIZE(wt);
/* Note: the corresponding code for lists has an "early out" test
* here when op is EQ or NE and the lengths differ. That pays there,
* but Tim was unable to find any real code where EQ/NE tuple
* compares don't have the same length, so testing for it here would
* have cost without benefit.
*/
/* Search for the first index where items are different.
* Note that because tuples are immutable, it's safe to reuse
* vlen and wlen across the comparison calls.
*/
for (i = 0; i < vlen && i < wlen; i++) {
int k = PyObject_RichCompareBool(vt->elts[i], wt->elts[i], Py_EQ);
if (k < 0)
return NULL;
if (!k)
break;
}
if (i >= vlen || i >= wlen) {
/* No more items to compare -- compare sizes */
int cmp;
PyObject* res;
switch (op) {
case Py_LT:
cmp = vlen < wlen;
break;
case Py_LE:
cmp = vlen <= wlen;
break;
case Py_EQ:
cmp = vlen == wlen;
break;
case Py_NE:
cmp = vlen != wlen;
break;
case Py_GT:
cmp = vlen > wlen;
break;
case Py_GE:
cmp = vlen >= wlen;
break;
default:
return NULL; /* cannot happen */
}
if (cmp)
res = Py_True;
else
res = Py_False;
Py_INCREF(res);
return res;
}
/* We have an item that differs -- shortcuts for EQ/NE */
if (op == Py_EQ) {
Py_INCREF(Py_False);
return Py_False;
}
if (op == Py_NE) {
Py_INCREF(Py_True);
return Py_True;
}
/* Compare the final item again using the proper operator */
return PyObject_RichCompare(vt->elts[i], wt->elts[i], op);
}
void setupTuple() { void setupTuple() {
tuple_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &tupleIteratorGCHandler, 0, 0, tuple_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &tupleIteratorGCHandler, 0, 0,
sizeof(BoxedTupleIterator), false, "tuple"); sizeof(BoxedTupleIterator), false, "tuple");
...@@ -460,12 +461,7 @@ void setupTuple() { ...@@ -460,12 +461,7 @@ void setupTuple() {
new BoxedFunction(boxRTFunction((void*)tupleIter, typeFromClass(tuple_iterator_cls), 1))); new BoxedFunction(boxRTFunction((void*)tupleIter, typeFromClass(tuple_iterator_cls), 1)));
tuple_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)tupleLt, UNKNOWN, 2))); tuple_cls->tp_richcompare = tuplerichcompare;
tuple_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)tupleLe, UNKNOWN, 2)));
tuple_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)tupleGt, UNKNOWN, 2)));
tuple_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)tupleGe, UNKNOWN, 2)));
tuple_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)tupleEq, UNKNOWN, 2)));
tuple_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)tupleNe, UNKNOWN, 2)));
tuple_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)tupleNonzero, BOXED_BOOL, 1))); tuple_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)tupleNonzero, BOXED_BOOL, 1)));
......
...@@ -2294,6 +2294,63 @@ Box* decodeUTF8StringPtr(const std::string* s) { ...@@ -2294,6 +2294,63 @@ Box* decodeUTF8StringPtr(const std::string* s) {
return rtn; return rtn;
} }
static PyObject* type_richcompare(PyObject* v, PyObject* w, int op) noexcept {
PyObject* result;
Py_uintptr_t vv, ww;
int c;
/* Make sure both arguments are types. */
if (!PyType_Check(v) || !PyType_Check(w) ||
/* If there is a __cmp__ method defined, let it be called instead
of our dumb function designed merely to warn. See bug
#7491. */
Py_TYPE(v)->tp_compare || Py_TYPE(w)->tp_compare) {
result = Py_NotImplemented;
goto out;
}
/* Py3K warning if comparison isn't == or != */
if (Py_Py3kWarningFlag && op != Py_EQ && op != Py_NE
&& PyErr_WarnEx(PyExc_DeprecationWarning, "type inequality comparisons not supported "
"in 3.x",
1) < 0) {
return NULL;
}
/* Compare addresses */
vv = (Py_uintptr_t)v;
ww = (Py_uintptr_t)w;
switch (op) {
case Py_LT:
c = vv < ww;
break;
case Py_LE:
c = vv <= ww;
break;
case Py_EQ:
c = vv == ww;
break;
case Py_NE:
c = vv != ww;
break;
case Py_GT:
c = vv > ww;
break;
case Py_GE:
c = vv >= ww;
break;
default:
result = Py_NotImplemented;
goto out;
}
result = c ? Py_True : Py_False;
/* incref and return */
out:
Py_INCREF(result);
return result;
}
bool TRACK_ALLOCATIONS = false; bool TRACK_ALLOCATIONS = false;
void setupRuntime() { void setupRuntime() {
...@@ -2563,6 +2620,8 @@ void setupRuntime() { ...@@ -2563,6 +2620,8 @@ void setupRuntime() {
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedClass, tp_mro))); new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedClass, tp_mro)));
type_cls->giveAttr("__subclasses__", new BoxedFunction(boxRTFunction((void*)typeSubclasses, UNKNOWN, 1))); type_cls->giveAttr("__subclasses__", new BoxedFunction(boxRTFunction((void*)typeSubclasses, UNKNOWN, 1)));
type_cls->giveAttr("mro", new BoxedFunction(boxRTFunction((void*)typeMro, UNKNOWN, 1))); type_cls->giveAttr("mro", new BoxedFunction(boxRTFunction((void*)typeMro, UNKNOWN, 1)));
type_cls->tp_richcompare = type_richcompare;
add_operators(type_cls);
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)));
......
def f(a, b): def f(a, b):
print a, b, "<", a < b print repr(a), repr(b), "<", a < b
print a, b, "<=", a <= b print repr(a), repr(b), "<=", a <= b
print a, b, ">", a > b print repr(a), repr(b), ">", a > b
print a, b, ">=", a >= b print repr(a), repr(b), ">=", a >= b
print a, b, "==", a == b print repr(a), repr(b), "==", a == b
print a, b, "!=", a != b print repr(a), repr(b), "!=", a != b
print a, b, "is", a is b print repr(a), repr(b), "is", a is b
print a, b, "is not", a is not b print repr(a), repr(b), "is not", a is not b
class C(object): class C(object):
pass pass
...@@ -14,7 +14,7 @@ class C(object): ...@@ -14,7 +14,7 @@ class C(object):
class Z(object): class Z(object):
pass pass
args = [0, 1, 0.1, 1.1, "hello", float('nan'), float('inf'), float('-inf')]#, C(), Z()] args = [0, 1, 0.1, 1.1, "hello", float('nan'), float('inf'), float('-inf'), 0L, 1L]#, C(), Z()]
for i in xrange(len(args)): for i in xrange(len(args)):
for j in xrange(i): for j in xrange(i):
......
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