summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/src/umath/dispatching.c30
-rw-r--r--numpy/core/src/umath/ufunc_object.c32
2 files changed, 45 insertions, 17 deletions
diff --git a/numpy/core/src/umath/dispatching.c b/numpy/core/src/umath/dispatching.c
index 8585757ed..878ab97d7 100644
--- a/numpy/core/src/umath/dispatching.c
+++ b/numpy/core/src/umath/dispatching.c
@@ -505,7 +505,7 @@ legacy_promote_using_legacy_type_resolver(PyUFuncObject *ufunc,
Py_XDECREF(type_tuple);
for (int i = 0; i < nargs; i++) {
- operation_DTypes[i] = NPY_DTYPE(out_descrs[i]);
+ Py_XSETREF(operation_DTypes[i], NPY_DTYPE(out_descrs[i]));
Py_INCREF(operation_DTypes[i]);
Py_DECREF(out_descrs[i]);
}
@@ -641,23 +641,40 @@ promote_and_get_info_and_ufuncimpl(PyUFuncObject *ufunc,
return NULL;
}
- PyArray_DTypeMeta *new_op_dtypes[NPY_MAXARGS];
+ PyArray_DTypeMeta *new_op_dtypes[NPY_MAXARGS] = {NULL};
int cacheable = 1; /* TODO: only the comparison deprecation needs this */
if (legacy_promote_using_legacy_type_resolver(ufunc,
ops, signature, new_op_dtypes, &cacheable) < 0) {
return NULL;
}
- return promote_and_get_info_and_ufuncimpl(ufunc,
+ info = promote_and_get_info_and_ufuncimpl(ufunc,
ops, signature, new_op_dtypes, 0, cacheable);
+ for (int i = 0; i < ufunc->nargs; i++) {
+ Py_XDECREF(new_op_dtypes);
+ }
+ return info;
}
-/*
+/**
* The central entry-point for the promotion and dispatching machinery.
*
- * It currently works with the operands (although it would be possible to
+ * It currently may work with the operands (although it would be possible to
* only work with DType (classes/types). This is because it has to ensure
* that legacy (value-based promotion) is used when necessary.
+ *
+ * @param ufunc The ufunc object, used mainly for the fallback.
+ * @param ops The array operands (used only for the fallback).
+ * @param signature As input, the DType signature fixed explicitly by the user.
+ * The signature is *filled* in with the operation signature we end up
+ * using.
+ * @param op_dtypes The operand DTypes (without casting) which are specified
+ * either by the `signature` or by an `operand`.
+ * (outputs and the second input can be NULL for reductions).
+ * NOTE: In some cases, the promotion machinery may currently modify
+ * these.
+ * @param force_legacy_promotion If set, we have to use the old type resolution
+ * to implement value-based promotion/casting.
*/
NPY_NO_EXPORT PyArrayMethodObject *
promote_and_get_ufuncimpl(PyUFuncObject *ufunc,
@@ -676,7 +693,8 @@ promote_and_get_ufuncimpl(PyUFuncObject *ufunc,
* ignore the operand input, we cannot overwrite signature yet
* since it is fixed (cannot be promoted!)
*/
- op_dtypes[i] = signature[i];
+ Py_INCREF(signature[i]);
+ Py_XSETREF(op_dtypes[i], signature[i]);
assert(i >= ufunc->nin || !signature[i]->abstract);
}
}
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 0bc019c6c..1e1d7baad 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -922,7 +922,7 @@ _wheremask_converter(PyObject *obj, PyArrayObject **wheremask)
static int
convert_ufunc_arguments(PyUFuncObject *ufunc,
ufunc_full_args full_args, PyArrayObject *out_op[],
- PyArray_DTypeMeta *out_borrowed_op_DTypes[], int *force_legacy_promotion,
+ PyArray_DTypeMeta *out_op_DTypes[], int *force_legacy_promotion,
PyObject *order_obj, NPY_ORDER *out_order,
PyObject *casting_obj, NPY_CASTING *out_casting,
PyObject *subok_obj, npy_bool *out_subok,
@@ -952,8 +952,10 @@ convert_ufunc_arguments(PyUFuncObject *ufunc,
goto fail;
}
}
- out_borrowed_op_DTypes[i] = NPY_DTYPE(PyArray_DESCR(out_op[i]));
- if (!out_borrowed_op_DTypes[i]->legacy) {
+ out_op_DTypes[i] = NPY_DTYPE(PyArray_DESCR(out_op[i]));
+ Py_INCREF(out_op_DTypes[i]);
+
+ if (!out_op_DTypes[i]->legacy) {
all_legacy = NPY_FALSE;
}
if (PyArray_NDIM(out_op[i]) != 0) {
@@ -965,14 +967,19 @@ convert_ufunc_arguments(PyUFuncObject *ufunc,
}
/* Special case if it was a Python scalar, to allow "weak" promotion */
if ((PyObject *)out_op[i] != obj) {
+ PyArray_DTypeMeta *scalar_DType = NULL;
if (PyLong_CheckExact(obj)) {
- out_borrowed_op_DTypes[i] = &PyArray_PyIntAbstractDType;
+ scalar_DType = &PyArray_PyIntAbstractDType;
}
else if (PyFloat_CheckExact(obj)) {
- out_borrowed_op_DTypes[i] = &PyArray_PyFloatAbstractDType;
+ scalar_DType = &PyArray_PyFloatAbstractDType;
}
else if (PyComplex_CheckExact(obj)) {
- out_borrowed_op_DTypes[i] = &PyArray_PyComplexAbstractDType;
+ scalar_DType = &PyArray_PyComplexAbstractDType;
+ }
+ if (scalar_DType != NULL) {
+ Py_INCREF(scalar_DType);
+ Py_SETREF(out_op_DTypes[i], scalar_DType);
}
}
}
@@ -985,7 +992,6 @@ convert_ufunc_arguments(PyUFuncObject *ufunc,
}
/* Convert and fill in output arguments */
- memset(out_borrowed_op_DTypes + nin, 0, nout * sizeof(*out_borrowed_op_DTypes));
if (full_args.out != NULL) {
for (int i = 0; i < nout; i++) {
obj = PyTuple_GET_ITEM(full_args.out, i);
@@ -993,7 +999,8 @@ convert_ufunc_arguments(PyUFuncObject *ufunc,
goto fail;
}
if (out_op[i] != NULL) {
- out_borrowed_op_DTypes[i + nin] = NPY_DTYPE(PyArray_DESCR(out_op[i]));
+ out_op_DTypes[i + nin] = NPY_DTYPE(PyArray_DESCR(out_op[i]));
+ Py_INCREF(out_op_DTypes[i + nin]);
}
}
}
@@ -4633,11 +4640,13 @@ ufunc_generic_fastcall(PyUFuncObject *ufunc,
PyArray_DTypeMeta *signature[NPY_MAXARGS];
PyArrayObject *operands[NPY_MAXARGS];
+ PyArray_DTypeMeta *operand_DTypes[NPY_MAXARGS];
PyArray_Descr *operation_descrs[NPY_MAXARGS];
PyObject *output_array_prepare[NPY_MAXARGS];
/* Initialize all arrays (we usually only need a small part) */
memset(signature, 0, nop * sizeof(*signature));
memset(operands, 0, nop * sizeof(*operands));
+ memset(operand_DTypes, 0, nop * sizeof(*operation_descrs));
memset(operation_descrs, 0, nop * sizeof(*operation_descrs));
memset(output_array_prepare, 0, nout * sizeof(*output_array_prepare));
@@ -4819,11 +4828,10 @@ ufunc_generic_fastcall(PyUFuncObject *ufunc,
npy_bool subok = NPY_TRUE;
int keepdims = -1; /* We need to know if it was passed */
int force_legacy_promotion = 0;
- PyArray_DTypeMeta *borrowed_operand_DTypes[NPY_MAXARGS];
if (convert_ufunc_arguments(ufunc,
/* extract operand related information: */
full_args, operands,
- borrowed_operand_DTypes, &force_legacy_promotion,
+ operand_DTypes, &force_legacy_promotion,
/* extract general information: */
order_obj, &order,
casting_obj, &casting,
@@ -4843,7 +4851,7 @@ ufunc_generic_fastcall(PyUFuncObject *ufunc,
*/
PyArrayMethodObject *ufuncimpl = promote_and_get_ufuncimpl(ufunc,
operands, signature,
- borrowed_operand_DTypes, force_legacy_promotion);
+ operand_DTypes, force_legacy_promotion);
if (ufuncimpl == NULL) {
goto fail;
}
@@ -4883,6 +4891,7 @@ ufunc_generic_fastcall(PyUFuncObject *ufunc,
*/
Py_XDECREF(wheremask);
for (int i = 0; i < nop; i++) {
+ Py_XDECREF(operand_DTypes[i]);
Py_DECREF(operation_descrs[i]);
if (i < nin) {
Py_DECREF(operands[i]);
@@ -4905,6 +4914,7 @@ fail:
Py_XDECREF(wheremask);
for (int i = 0; i < ufunc->nargs; i++) {
Py_XDECREF(operands[i]);
+ Py_XDECREF(operand_DTypes[i]);
Py_XDECREF(operation_descrs[i]);
if (i < nout) {
Py_XDECREF(output_array_prepare[i]);