From a9e262d0cbd4c7468c60afa5eebfb56fbe2523eb Mon Sep 17 00:00:00 2001 From: Boxiang Sun Date: Sat, 1 Jul 2017 20:18:32 +0800 Subject: [PATCH 1/6] Make the bool object become subclass of long object. In Python 2, the bool object just a int object. In Python 3, the bool object become long object. So change the bool object to the subclass of long object, prepare for other Python 3 updates. --- from_cpython/Include/boolobject.h | 4 +--- src/runtime/bool.cpp | 16 ++++++++-------- src/runtime/types.cpp | 10 +++++----- src/runtime/types.h | 17 +++++++++++++++-- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/from_cpython/Include/boolobject.h b/from_cpython/Include/boolobject.h index ec82e01a4..cd3f94d5d 100644 --- a/from_cpython/Include/boolobject.h +++ b/from_cpython/Include/boolobject.h @@ -9,8 +9,6 @@ extern "C" { #endif -typedef PyIntObject PyBoolObject; - // Pyston change: this is no longer a static object PyAPI_DATA(PyTypeObject*) bool_cls; #define PyBool_Type (*bool_cls) @@ -22,7 +20,7 @@ Don't forget to apply Py_INCREF() when returning either!!! */ // Pyston change: these are currently stored as pointers, not as static globals /* Don't use these directly */ -//PyAPI_DATA(PyIntObject) _Py_ZeroStruct, _Py_TrueStruct; +// PyAPI_DATA(struct _longobject) _Py_FalseStruct, _Py_TrueStruct; PyAPI_DATA(PyObject) *pyston_True, *pyston_False; /* Use these macros */ #define Py_False ((PyObject *) pyston_False) diff --git a/src/runtime/bool.cpp b/src/runtime/bool.cpp index 6b4d9a734..d47aecd5d 100644 --- a/src/runtime/bool.cpp +++ b/src/runtime/bool.cpp @@ -14,7 +14,7 @@ #include "core/common.h" #include "core/types.h" -#include "runtime/int.h" +#include "runtime/long.h" #include "runtime/objmodel.h" #include "runtime/types.h" @@ -62,9 +62,9 @@ extern "C" Box* boolAnd(BoxedBool* lhs, BoxedBool* rhs) { getTypeName(lhs)); if (!PyBool_Check(rhs)) - return intAnd(lhs, rhs); + return longAnd(lhs, rhs); - return boxBool(lhs->n && rhs->n); + return boxBool((lhs == Py_True) & (rhs == Py_True)); } extern "C" Box* boolOr(BoxedBool* lhs, BoxedBool* rhs) { @@ -72,9 +72,9 @@ extern "C" Box* boolOr(BoxedBool* lhs, BoxedBool* rhs) { raiseExcHelper(TypeError, "descriptor '__or__' requires a 'bool' object but received a '%s'", getTypeName(lhs)); if (!PyBool_Check(rhs)) - return intOr(lhs, rhs); + return longOr(lhs, rhs); - return boxBool(lhs->n || rhs->n); + return boxBool((lhs == Py_True) | (rhs == Py_True)); } extern "C" Box* boolXor(BoxedBool* lhs, BoxedBool* rhs) { @@ -83,9 +83,9 @@ extern "C" Box* boolXor(BoxedBool* lhs, BoxedBool* rhs) { getTypeName(lhs)); if (!PyBool_Check(rhs)) - return intXor(lhs, rhs); + return longXor(lhs, rhs); - return boxBool(lhs->n ^ rhs->n); + return boxBool((lhs == Py_True) ^ (rhs == Py_True)); } @@ -111,6 +111,6 @@ void setupBool() { bool_cls->freeze(); bool_cls->tp_hash = (hashfunc)bool_hash; bool_cls->tp_repr = boolRepr; - bool_as_number.nb_int = int_cls->tp_as_number->nb_int; + bool_as_number.nb_int = long_cls->tp_as_number->nb_int; } } diff --git a/src/runtime/types.cpp b/src/runtime/types.cpp index a43a56a68..18756df30 100644 --- a/src/runtime/types.cpp +++ b/src/runtime/types.cpp @@ -4262,11 +4262,11 @@ void setupRuntime() { int_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedInt), false, "int", true, BoxedInt::tp_dealloc, /*BoxedInt::tp_free*/ NULL, false); int_cls->tp_flags |= Py_TPFLAGS_INT_SUBCLASS; - bool_cls = new (0) BoxedClass(int_cls, 0, 0, sizeof(BoxedBool), false, "bool", false, NULL, NULL, false); complex_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedComplex), false, "complex", true, NULL, NULL, false); long_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedLong), false, "long", true, BoxedLong::tp_dealloc, NULL, false); long_cls->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS; + bool_cls = new (0) BoxedClass(long_cls, 0, 0, sizeof(BoxedLong), false, "bool", false, NULL, NULL, false); float_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedFloat), false, "float", true, BoxedFloat::tp_dealloc, NULL, false); function_cls = new (0) BoxedClass(object_cls, offsetof(BoxedFunction, attrs), offsetof(BoxedFunction, weakreflist), @@ -4304,9 +4304,9 @@ void setupRuntime() { attrwrapper_cls->tp_mro = BoxedTuple::create({ attrwrapper_cls, object_cls }); dict_cls->tp_mro = BoxedTuple::create({ dict_cls, object_cls }); int_cls->tp_mro = BoxedTuple::create({ int_cls, object_cls }); - bool_cls->tp_mro = BoxedTuple::create({ bool_cls, int_cls, object_cls }); complex_cls->tp_mro = BoxedTuple::create({ complex_cls, object_cls }); long_cls->tp_mro = BoxedTuple::create({ long_cls, object_cls }); + bool_cls->tp_mro = BoxedTuple::create({ bool_cls, long_cls, object_cls }); float_cls->tp_mro = BoxedTuple::create({ float_cls, object_cls }); function_cls->tp_mro = BoxedTuple::create({ function_cls, object_cls }); builtin_function_or_method_cls->tp_mro = BoxedTuple::create({ builtin_function_or_method_cls, object_cls }); @@ -4318,13 +4318,13 @@ void setupRuntime() { STR = typeFromClass(str_cls); BOXED_INT = typeFromClass(int_cls); BOXED_FLOAT = typeFromClass(float_cls); - BOXED_BOOL = typeFromClass(bool_cls); NONE = typeFromClass(none_cls); LIST = typeFromClass(list_cls); MODULE = typeFromClass(module_cls); DICT = typeFromClass(dict_cls); BOXED_TUPLE = typeFromClass(tuple_cls); LONG = typeFromClass(long_cls); + BOXED_BOOL = typeFromClass(bool_cls); BOXED_COMPLEX = typeFromClass(complex_cls); pyston_True = new BoxedBool(true); @@ -4362,9 +4362,9 @@ void setupRuntime() { attrwrapper_cls->finishInitialization(); dict_cls->finishInitialization(); int_cls->finishInitialization(); - bool_cls->finishInitialization(); complex_cls->finishInitialization(); long_cls->finishInitialization(); + bool_cls->finishInitialization(); float_cls->finishInitialization(); function_cls->finishInitialization(); builtin_function_or_method_cls->finishInitialization(); @@ -4495,8 +4495,8 @@ void setupRuntime() { assert(object_cls->tp_new == object_new); assert(object_cls->tp_str == object_str); - setupBool(); setupLong(); + setupBool(); setupFloat(); setupComplex(); setupStr(); diff --git a/src/runtime/types.h b/src/runtime/types.h index 35f232732..74bf4aba3 100644 --- a/src/runtime/types.h +++ b/src/runtime/types.h @@ -15,6 +15,7 @@ #ifndef PYSTON_RUNTIME_TYPES_H #define PYSTON_RUNTIME_TYPES_H +#include #include #include #include @@ -541,6 +542,18 @@ class BoxedInt : public Box { static_assert(sizeof(BoxedInt) == sizeof(PyIntObject), ""); static_assert(offsetof(BoxedInt, n) == offsetof(PyIntObject, ob_ival), ""); +class BoxedLong : public Box { +public: + mpz_t n; + + BoxedLong() __attribute__((visibility("default"))){}; + BoxedLong(int64_t ival) __attribute__((visibility("default"))) { mpz_init_set_si(n, ival); } + + static void tp_dealloc(Box* b) noexcept; + + DEFAULT_CLASS_SIMPLE(long_cls, false); +}; + extern "C" int PyFloat_ClearFreeList() noexcept; class BoxedFloat : public Box { private: @@ -593,9 +606,9 @@ static_assert(sizeof(BoxedComplex) == sizeof(PyComplexObject), ""); static_assert(offsetof(BoxedComplex, real) == offsetof(PyComplexObject, cval.real), ""); static_assert(offsetof(BoxedComplex, imag) == offsetof(PyComplexObject, cval.imag), ""); -class BoxedBool : public BoxedInt { +class BoxedBool : public BoxedLong { public: - BoxedBool(bool b) __attribute__((visibility("default"))) : BoxedInt(b ? 1 : 0) {} + BoxedBool(bool b) __attribute__((visibility("default"))) { mpz_init_set_si(n, b ? 1 : 0); } DEFAULT_CLASS_SIMPLE(bool_cls, false); }; From d73dc8f87066413754e32c1a3dda7218a8b8c81b Mon Sep 17 00:00:00 2001 From: Boxiang Sun Date: Sat, 1 Jul 2017 20:19:23 +0800 Subject: [PATCH 2/6] Modify the long object API to adapt the changes of bool object. --- src/runtime/long.cpp | 26 ++++++++++++++------------ src/runtime/long.h | 15 +++------------ 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/runtime/long.cpp b/src/runtime/long.cpp index 6d2746e0a..e258f51bb 100644 --- a/src/runtime/long.cpp +++ b/src/runtime/long.cpp @@ -777,19 +777,20 @@ template Box* longNew(Box* _cls, Box* val, Box* base) noexcep return rtn; } +static Box* long_int(Box* v) noexcept { + int overflow = 0; + long n = PyLong_AsLongAndOverflow(v, &overflow); + static_assert(sizeof(BoxedInt::n) == sizeof(long), ""); + BoxedLong* rtn = new BoxedLong(); + mpz_init_set(rtn->n, ((BoxedLong*)v)->n); + return rtn; +} + Box* longInt(Box* v) { if (!PyLong_Check(v)) raiseExcHelper(TypeError, "descriptor '__int__' requires a 'long' object but received a '%s'", getTypeName(v)); - int overflow = 0; - long n = PyLong_AsLongAndOverflow(v, &overflow); - static_assert(sizeof(BoxedInt::n) == sizeof(long), ""); - if (overflow) { - BoxedLong* rtn = new BoxedLong(); - mpz_init_set(rtn->n, ((BoxedLong*)v)->n); - return rtn; - } else - return boxInt(n); + return long_int(v); } Box* longToLong(Box* self) noexcept { @@ -949,7 +950,7 @@ Box* longAdd(BoxedLong* v1, Box* _v2) { } // TODO: split common code out into a helper function -extern "C" Box* longAnd(BoxedLong* v1, Box* _v2) { +Box* longAnd(BoxedLong* v1, Box* _v2) { if (!PyLong_Check(v1)) raiseExcHelper(TypeError, "descriptor '__and__' requires a 'long' object but received a '%s'", getTypeName(v1)); if (PyLong_Check(_v2)) { @@ -975,7 +976,7 @@ extern "C" Box* longAnd(BoxedLong* v1, Box* _v2) { return incref(NotImplemented); } -extern "C" Box* longOr(BoxedLong* v1, Box* _v2) { +Box* longOr(BoxedLong* v1, Box* _v2) { if (!PyLong_Check(v1)) raiseExcHelper(TypeError, "descriptor '__or__' requires a 'long' object but received a '%s'", getTypeName(v1)); if (PyLong_Check(_v2)) { @@ -1001,7 +1002,7 @@ extern "C" Box* longOr(BoxedLong* v1, Box* _v2) { return incref(NotImplemented); } -extern "C" Box* longXor(BoxedLong* v1, Box* _v2) { +Box* longXor(BoxedLong* v1, Box* _v2) { if (!PyLong_Check(v1)) raiseExcHelper(TypeError, "descriptor '__xor__' requires a 'long' object but received a '%s'", getTypeName(v1)); if (PyLong_Check(_v2)) { @@ -1811,6 +1812,7 @@ void setupLong() { long_cls->freeze(); long_cls->tp_as_number->nb_power = long_pow; + long_cls->tp_as_number->nb_int = long_int; long_cls->tp_hash = long_hash; long_cls->tp_repr = longRepr; long_cls->tp_str = longStr; diff --git a/src/runtime/long.h b/src/runtime/long.h index 5ed51a92f..6c23ad8df 100644 --- a/src/runtime/long.h +++ b/src/runtime/long.h @@ -16,7 +16,6 @@ #define PYSTON_RUNTIME_LONG_H #include -#include #include "core/types.h" #include "runtime/types.h" @@ -27,23 +26,15 @@ void setupLong(); extern BoxedClass* long_cls; -class BoxedLong : public Box { -public: - mpz_t n; - - BoxedLong() __attribute__((visibility("default"))) {} - - static void tp_dealloc(Box* b) noexcept; - - DEFAULT_CLASS_SIMPLE(long_cls, false); -}; - extern "C" Box* createLong(llvm::StringRef s); extern "C" BoxedLong* boxLong(int64_t n); Box* longNeg(BoxedLong* lhs); Box* longAbs(BoxedLong* v1); +Box* longAnd(BoxedLong* lhs, Box* rhs); +Box* longOr(BoxedLong* lhs, Box* rhs); +Box* longXor(BoxedLong* lhs, Box* rhs); Box* longAdd(BoxedLong* lhs, Box* rhs); Box* longSub(BoxedLong* lhs, Box* rhs); Box* longMul(BoxedLong* lhs, Box* rhs); From bce623dad2fc058f0f805dca0406742f25109655 Mon Sep 17 00:00:00 2001 From: Boxiang Sun Date: Sat, 1 Jul 2017 20:21:43 +0800 Subject: [PATCH 3/6] Update parts of bool object usage according to the long based bool implementation --- from_cpython/Modules/_sre.c | 10 ++++++++-- src/runtime/builtin_modules/pyston.cpp | 2 +- src/runtime/objmodel.cpp | 10 ++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/from_cpython/Modules/_sre.c b/from_cpython/Modules/_sre.c index 2795c22ab..f6e7b3cbe 100644 --- a/from_cpython/Modules/_sre.c +++ b/from_cpython/Modules/_sre.c @@ -3310,9 +3310,15 @@ static Py_ssize_t match_getindex(MatchObject* self, PyObject* index) { Py_ssize_t i; + + // py3update, bool become long object, temporary fixing. + if (index == NULL) + /* Default value */ + return 0; - if (PyInt_Check(index)) - return PyInt_AsSsize_t(index); + if (PyIndex_Check(index)) { + return PyNumber_AsSsize_t(index, NULL); + } i = -1; diff --git a/src/runtime/builtin_modules/pyston.cpp b/src/runtime/builtin_modules/pyston.cpp index 14a4f8a1b..0676b5742 100644 --- a/src/runtime/builtin_modules/pyston.cpp +++ b/src/runtime/builtin_modules/pyston.cpp @@ -60,7 +60,7 @@ static Box* dumpStats(Box* includeZeros) { if (includeZeros->cls != bool_cls) raiseExcHelper(TypeError, "includeZeros must be a 'bool' object but received a '%s'", getTypeName(includeZeros)); - Stats::dump(((BoxedBool*)includeZeros)->n != 0); + Stats::dump(((BoxedBool*)includeZeros) != Py_False); Py_RETURN_NONE; } diff --git a/src/runtime/objmodel.cpp b/src/runtime/objmodel.cpp index 67f583f37..a4fa00c38 100644 --- a/src/runtime/objmodel.cpp +++ b/src/runtime/objmodel.cpp @@ -3255,7 +3255,7 @@ static bool nonzeroHelper(STOLEN(Box*) r) { // I believe this behavior is handled by the slot wrappers in CPython: if (r->cls == bool_cls) { BoxedBool* b = static_cast(r); - bool rtn = b->n; + bool rtn = (b == Py_True); return rtn; } else if (r->cls == int_cls) { BoxedInt* b = static_cast(r); @@ -3285,14 +3285,8 @@ extern "C" bool nonzero(Box* obj) { // able to at least generate rewrites that are as good as the ones we write here. // But for now we can't and these should be a bit faster: if (obj->cls == bool_cls) { - // TODO: is it faster to compare to True? (especially since it will be a constant we can embed in the rewrite) - if (rewriter.get()) { - RewriterVar* b = r_obj->getAttr(offsetof(BoxedBool, n), rewriter->getReturnDestination()); - rewriter->commitReturningNonPython(b); - } - BoxedBool* bool_obj = static_cast(obj); - return bool_obj->n; + return bool_obj == Py_True; } else if (obj->cls == int_cls) { if (rewriter.get()) { RewriterVar* n = r_obj->getAttr(offsetof(BoxedInt, n), rewriter->getReturnDestination()); From 0eddc7b82983bda6f345469d765f1db6c004d8f8 Mon Sep 17 00:00:00 2001 From: Boxiang Sun Date: Sat, 1 Jul 2017 20:23:33 +0800 Subject: [PATCH 4/6] Disable all python tests for now. If any tests ready to python 3, we need to add 'py3ready' flag in the beginning of the file --- tools/tester.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/tester.py b/tools/tester.py index bfa5e3f1e..a700ad6e8 100644 --- a/tools/tester.py +++ b/tools/tester.py @@ -152,6 +152,9 @@ def run_test(fn, check_stats, run_memcheck): opts = get_test_options(fn, check_stats, run_memcheck) del check_stats, run_memcheck + if opts.expected != "py3ready": + opts.skip = True + if opts.skip: return ("(skipped: %s)" % opts.skip) if DISPLAY_SKIPS else "" @@ -224,7 +227,7 @@ def get_test_options(fn, check_stats, run_memcheck): elif os.path.basename(fn).split('.')[0] in TESTS_TO_SKIP: opts.skip = 'command line option' - assert opts.expected in ("success", "fail", "statfail"), opts.expected + assert opts.expected in ("success", "fail", "statfail", "py3ready"), opts.expected if TEST_PYPY: opts.jit_args = [] From 08d69322b7de02449163f9a63a42239e9e9ff884 Mon Sep 17 00:00:00 2001 From: Boxiang Sun Date: Sun, 2 Jul 2017 01:53:21 +0800 Subject: [PATCH 5/6] use cmake 3 to build pyston. cmake 2 can not build target Ninja. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index d1cd71167..0aa65c081 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,11 +30,13 @@ addons: - kubuntu-backports - llvm-toolchain-precise-3.5 - ubuntu-toolchain-r-test + - george-edison55-precise-backports packages: - autoconf - ccache - clang-3.5 - cmake + - cmake-data - g++-4.8 - gdb - gfortran From d4915315eb98b1cbc976b49a7ca8916eed979d13 Mon Sep 17 00:00:00 2001 From: Boxiang Sun Date: Wed, 12 Jul 2017 03:55:38 +0800 Subject: [PATCH 6/6] add test for long based bool --- test/tests/bool_test.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 test/tests/bool_test.py diff --git a/test/tests/bool_test.py b/test/tests/bool_test.py new file mode 100644 index 000000000..37cda558f --- /dev/null +++ b/test/tests/bool_test.py @@ -0,0 +1,6 @@ +# expected: fail + +long_ = type(31415926535897932384626) +assert isinstance(True, long_) +assert issubclass(bool, long_) +print(bool.__bases__)