[pypy-commit] pypy cpyext-fast-typecheck: (anto, matti) introduce a new way to implement Py*_Check efficiently: we add a
antocuni
pypy.commits at gmail.com
Tue Mar 20 10:38:56 EDT 2018
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: cpyext-fast-typecheck
Changeset: r94031:185b284722b0
Date: 2018-03-20 15:25 +0100
http://bitbucket.org/pypy/pypy/changeset/185b284722b0/
Log: (anto, matti) introduce a new way to implement Py*_Check
efficiently: we add a new field to typeobject which containts flags
for types like float, which don't have an official
Py_TPFLAGS_*_SUBCLASS.
Then, we can implement Py*_Check and Py*_CheckExact as a C macro,
avoiding the slow roundtrip to RPython
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -133,6 +133,11 @@
'TYPE', 'STRING'): # 'STRING' -> 'BYTES' in py3
constant_names.append('Py_TPFLAGS_%s_SUBCLASS' % name)
+# PyPy-specific flags
+for name in ('FLOAT',):
+ constant_names.append('Py_TPPYPYFLAGS_%s_SUBCLASS' % name)
+
+
for name in constant_names:
setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
globals().update(rffi_platform.configure(CConfig_constants))
diff --git a/pypy/module/cpyext/floatobject.py b/pypy/module/cpyext/floatobject.py
--- a/pypy/module/cpyext/floatobject.py
+++ b/pypy/module/cpyext/floatobject.py
@@ -1,7 +1,7 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (PyObjectFields, bootstrap_function,
cpython_struct,
- CANNOT_FAIL, cpython_api, PyObject, build_type_checkers, CONST_STRING)
+ CANNOT_FAIL, cpython_api, PyObject, CONST_STRING)
from pypy.module.cpyext.pyobject import (
make_typedescr, track_reference, from_ref)
from pypy.interpreter.error import OperationError
@@ -38,8 +38,6 @@
track_reference(space, obj, w_obj)
return w_obj
-PyFloat_Check, PyFloat_CheckExact = build_type_checkers("Float")
-
@cpython_api([lltype.Float], PyObject)
def PyFloat_FromDouble(space, value):
return space.newfloat(value)
diff --git a/pypy/module/cpyext/include/floatobject.h b/pypy/module/cpyext/include/floatobject.h
--- a/pypy/module/cpyext/include/floatobject.h
+++ b/pypy/module/cpyext/include/floatobject.h
@@ -32,6 +32,11 @@
return PyFloat_FromDouble(-Py_HUGE_VAL); \
} while(0)
+#define PyFloat_Check(op) \
+ _PyPy_Type_FastSubclass((op)->ob_type, Py_TPPYPYFLAGS_FLOAT_SUBCLASS)
+#define PyFloat_CheckExact(op) ((op)->ob_type == &PyFloat_Type)
+
+
#ifdef __cplusplus
}
#endif
diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -228,6 +228,11 @@
#define Py_TPFLAGS_BASE_EXC_SUBCLASS (1L<<30)
#define Py_TPFLAGS_TYPE_SUBCLASS (1L<<31)
+/* These are conceptually the same as the flags above, but they are
+ PyPy-specific and are stored inside tp_pypy_flags */
+#define Py_TPPYPYFLAGS_FLOAT_SUBCLASS (1L<<0)
+
+
#define Py_TPFLAGS_DEFAULT_EXTERNAL ( \
Py_TPFLAGS_HAVE_GETCHARBUFFER | \
Py_TPFLAGS_HAVE_SEQUENCE_IN | \
@@ -247,6 +252,8 @@
#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0)
#define PyType_FastSubclass(t,f) PyType_HasFeature(t,f)
+#define _PyPy_Type_FastSubclass(t,f) (((t)->tp_pypy_flags & (f)) != 0)
+
#define PyType_Check(op) \
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS)
#define PyType_CheckExact(op) (Py_TYPE(op) == &PyType_Type)
diff --git a/pypy/module/cpyext/parse/cpyext_object.h b/pypy/module/cpyext/parse/cpyext_object.h
--- a/pypy/module/cpyext/parse/cpyext_object.h
+++ b/pypy/module/cpyext/parse/cpyext_object.h
@@ -311,6 +311,10 @@
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag;
+ /* PyPy specific extra fields: make sure that they are ALWAYS at the end,
+ for compatibility with CPython */
+ long tp_pypy_flags;
+
} PyTypeObject;
typedef struct _heaptypeobject {
diff --git a/pypy/module/cpyext/test/test_floatobject.py b/pypy/module/cpyext/test/test_floatobject.py
--- a/pypy/module/cpyext/test/test_floatobject.py
+++ b/pypy/module/cpyext/test/test_floatobject.py
@@ -102,9 +102,11 @@
"""
PyObject* pyobj = PyFloat_FromDouble(1.0);
PyFloatObject* pfo = (PyFloatObject*)pyobj;
- int res = PyFloat_Check(pyobj) && PyFloat_CheckExact(pyobj) &&
- PyFloat_Check(pfo) && PyFloat_CheckExact(pfo);
+ int res = (PyFloat_Check(pyobj) +
+ PyFloat_CheckExact(pyobj) * 10 +
+ PyFloat_Check(pfo) * 100 +
+ PyFloat_CheckExact(pfo) * 1000);
Py_DecRef(pyobj);
return PyLong_FromLong(res);"""),
])
- assert module.test() == 1
+ assert module.test() == 1111
diff --git a/pypy/module/cpyext/test/test_number.py b/pypy/module/cpyext/test/test_number.py
--- a/pypy/module/cpyext/test/test_number.py
+++ b/pypy/module/cpyext/test/test_number.py
@@ -11,7 +11,6 @@
PyNumber_Index, PyNumber_Coerce, PyNumber_CoerceEx, PyNumber_Add,
PyNumber_Multiply, PyNumber_InPlaceMultiply, PyNumber_Absolute,
PyNumber_Power, PyNumber_InPlacePower)
-from pypy.module.cpyext.floatobject import PyFloat_Check
from pypy.module.cpyext.intobject import PyInt_CheckExact
from pypy.module.cpyext.longobject import PyLong_CheckExact
from pypy.module.cpyext.object import PyObject_Size
@@ -86,7 +85,7 @@
w_res = from_ref(space, ppl[0])
- assert PyFloat_Check(space, w_res)
+ assert space.isinstance_w(w_res, space.w_float)
assert space.unwrap(w_res) == 123.
decref(space, pl)
decref(space, pf)
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -1537,4 +1537,29 @@
pass
assert module.test_flags(MyList, Py_TPFLAGS_LIST_SUBCLASS) == 0
+ def test_has_pypy_subclass_flag(self):
+ module = self.import_extension('foo', [
+ ("test_pypy_flags", "METH_VARARGS",
+ '''
+ long long in_flag, my_flag;
+ PyObject * obj;
+ if (!PyArg_ParseTuple(args, "OL", &obj, &in_flag))
+ return NULL;
+ if (!PyType_Check(obj))
+ {
+ PyErr_SetString(PyExc_ValueError, "input must be type");
+ return NULL;
+ }
+ my_flag = ((PyTypeObject*)obj)->tp_pypy_flags;
+ if ((my_flag & in_flag) != in_flag)
+ return PyLong_FromLong(-1);
+ return PyLong_FromLong(0);
+ '''),])
+ # copied from object.h
+ Py_TPPYPYFLAGS_FLOAT_SUBCLASS = (1L<<0)
+ class MyFloat(float):
+ pass
+ assert module.test_pypy_flags(float, Py_TPPYPYFLAGS_FLOAT_SUBCLASS) == 0
+ assert module.test_pypy_flags(MyFloat, Py_TPPYPYFLAGS_FLOAT_SUBCLASS) == 0
+
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -22,6 +22,7 @@
Py_TPFLAGS_DICT_SUBCLASS, Py_TPFLAGS_BASE_EXC_SUBCLASS,
Py_TPFLAGS_TYPE_SUBCLASS,
Py_TPFLAGS_INT_SUBCLASS, Py_TPFLAGS_STRING_SUBCLASS, # change on py3
+ Py_TPPYPYFLAGS_FLOAT_SUBCLASS,
)
from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction, PyMethodDef,
@@ -426,6 +427,9 @@
pto.c_tp_flags |= Py_TPFLAGS_LIST_SUBCLASS
elif space.issubtype_w(w_obj, space.w_dict):
pto.c_tp_flags |= Py_TPFLAGS_DICT_SUBCLASS
+ # the following types are a pypy-specific extensions, using tp_pypy_flags
+ elif space.issubtype_w(w_obj, space.w_float):
+ pto.c_tp_pypy_flags |= Py_TPPYPYFLAGS_FLOAT_SUBCLASS
def check_descr(space, w_self, w_type):
if not space.isinstance_w(w_self, w_type):
More information about the pypy-commit
mailing list