Skip to content

Commit 69d5022

Browse files
committed
use sliceobject function implementations from CPython
1 parent 25cc370 commit 69d5022

File tree

3 files changed

+101
-113
lines changed

3 files changed

+101
-113
lines changed

graalpython/com.oracle.graal.python.cext/src/sliceobject.c

Lines changed: 100 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,9 @@
1-
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3-
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1+
/* Copyright (c) 2018, 2019, Oracle and/or its affiliates.
2+
* Copyright (C) 1996-2017 Python Software Foundation
43
*
5-
* The Universal Permissive License (UPL), Version 1.0
6-
*
7-
* Subject to the condition set forth below, permission is hereby granted to any
8-
* person obtaining a copy of this software, associated documentation and/or
9-
* data (collectively the "Software"), free of charge and under any and all
10-
* copyright rights in the Software, and any and all patent rights owned or
11-
* freely licensable by each licensor hereunder covering either (i) the
12-
* unmodified Software as contributed to or provided by such licensor, or (ii)
13-
* the Larger Works (as defined below), to deal in both
14-
*
15-
* (a) the Software, and
16-
*
17-
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18-
* one is included with the Software each a "Larger Work" to which the Software
19-
* is contributed by such licensors),
20-
*
21-
* without restriction, including without limitation the rights to copy, create
22-
* derivative works of, display, perform, and distribute the Software and make,
23-
* use, sell, offer for sale, import, export, have made, and have sold the
24-
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25-
* either these or other terms.
26-
*
27-
* This license is subject to the following condition:
28-
*
29-
* The above copyright notice and either this complete permission notice or at a
30-
* minimum a reference to the UPL must be included in all copies or substantial
31-
* portions of the Software.
32-
*
33-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39-
* SOFTWARE.
4+
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
405
*/
6+
417
#include "capi.h"
428

439
PyTypeObject PyEllipsis_Type = PY_TRUFFLE_TYPE("ellipsis", &PyType_Type, Py_TPFLAGS_DEFAULT, 0);
@@ -48,27 +14,110 @@ PyObject _Py_EllipsisObject = {
4814
1, &PyEllipsis_Type
4915
};
5016

51-
UPCALL_ID(PySlice_GetIndicesEx);
17+
// Taken from CPython ceval.c
18+
/* Extract a slice index from a PyLong or an object with the
19+
nb_index slot defined, and store in *pi.
20+
Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
21+
and silently boost values less than PY_SSIZE_T_MIN to PY_SSIZE_T_MIN.
22+
Return 0 on error, 1 on success. */
23+
int _PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi) {
24+
if (v != Py_None) {
25+
Py_ssize_t x;
26+
if (PyIndex_Check(v)) {
27+
x = PyNumber_AsSsize_t(v, NULL);
28+
if (x == -1 && PyErr_Occurred())
29+
return 0;
30+
}
31+
else {
32+
PyErr_SetString(PyExc_TypeError,
33+
"slice indices must be integers or "
34+
"None or have an __index__ method");
35+
return 0;
36+
}
37+
*pi = x;
38+
}
39+
return 1;
40+
}
41+
42+
// Taken from CPython
5243
int PySlice_Unpack(PyObject *_r, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step) {
5344
PySliceObject *r = (PySliceObject*)_r;
54-
PyObject* result = UPCALL_CEXT_O(_jls_PySlice_GetIndicesEx, native_to_java(r->start), native_to_java(r->stop), native_to_java(r->step), PY_SSIZE_T_MAX);
55-
if (result == NULL) {
56-
return -1;
45+
/* this is harder to get right than you might think */
46+
47+
if (r->step == Py_None) {
48+
*step = 1;
49+
}
50+
else {
51+
if (!_PyEval_SliceIndex(r->step, step)) return -1;
52+
if (*step == 0) {
53+
PyErr_SetString(PyExc_ValueError,
54+
"slice step cannot be zero");
55+
return -1;
56+
}
57+
/* Here *step might be -PY_SSIZE_T_MAX-1; in this case we replace it
58+
* with -PY_SSIZE_T_MAX. This doesn't affect the semantics, and it
59+
* guards against later undefined behaviour resulting from code that
60+
* does "step = -step" as part of a slice reversal.
61+
*/
62+
if (*step < -PY_SSIZE_T_MAX)
63+
*step = -PY_SSIZE_T_MAX;
64+
}
65+
66+
if (r->start == Py_None) {
67+
*start = *step < 0 ? PY_SSIZE_T_MAX : 0;
5768
}
58-
*start = PyLong_AsSsize_t(PyTuple_GetItem(result, 0));
59-
*stop = PyLong_AsSsize_t(PyTuple_GetItem(result, 1));
60-
*step = PyLong_AsSsize_t(PyTuple_GetItem(result, 2));
69+
else {
70+
if (!_PyEval_SliceIndex(r->start, start)) return -1;
71+
}
72+
73+
if (r->stop == Py_None) {
74+
*stop = *step < 0 ? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
75+
}
76+
else {
77+
if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
78+
}
79+
6180
return 0;
6281
}
6382

83+
// taken from CPython
6484
Py_ssize_t PySlice_AdjustIndices(Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t step) {
65-
PyObject* result = UPCALL_CEXT_O(_jls_PySlice_GetIndicesEx, *start, *stop, step, length);
66-
if (result == NULL) {
67-
return -1;
85+
/* this is harder to get right than you might think */
86+
87+
assert(step != 0);
88+
assert(step >= -PY_SSIZE_T_MAX);
89+
90+
if (*start < 0) {
91+
*start += length;
92+
if (*start < 0) {
93+
*start = (step < 0) ? -1 : 0;
94+
}
95+
}
96+
else if (*start >= length) {
97+
*start = (step < 0) ? length - 1 : length;
6898
}
69-
*start = PyLong_AsSsize_t(PyTuple_GetItem(result, 0));
70-
*stop = PyLong_AsSsize_t(PyTuple_GetItem(result, 1));
71-
return PyLong_AsSsize_t(PyTuple_GetItem(result, 3)); // adjusted length
99+
100+
if (*stop < 0) {
101+
*stop += length;
102+
if (*stop < 0) {
103+
*stop = (step < 0) ? -1 : 0;
104+
}
105+
}
106+
else if (*stop >= length) {
107+
*stop = (step < 0) ? length - 1 : length;
108+
}
109+
110+
if (step < 0) {
111+
if (*stop < *start) {
112+
return (*start - *stop - 1) / (-step) + 1;
113+
}
114+
}
115+
else {
116+
if (*start < *stop) {
117+
return (*stop - *start - 1) / step + 1;
118+
}
119+
}
120+
return 0;
72121
}
73122

74123
UPCALL_ID(PySlice_New);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TruffleCextBuiltins.java

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,17 @@
101101
import com.oracle.graal.python.builtins.objects.dict.PDict;
102102
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
103103
import com.oracle.graal.python.builtins.objects.frame.PFrame;
104-
import com.oracle.graal.python.builtins.objects.function.Signature;
105104
import com.oracle.graal.python.builtins.objects.function.PArguments;
106105
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
107106
import com.oracle.graal.python.builtins.objects.function.PFunction;
108107
import com.oracle.graal.python.builtins.objects.function.PKeyword;
108+
import com.oracle.graal.python.builtins.objects.function.Signature;
109109
import com.oracle.graal.python.builtins.objects.ints.PInt;
110110
import com.oracle.graal.python.builtins.objects.iterator.PSequenceIterator;
111111
import com.oracle.graal.python.builtins.objects.list.PList;
112112
import com.oracle.graal.python.builtins.objects.module.PythonModule;
113113
import com.oracle.graal.python.builtins.objects.object.PythonObject;
114114
import com.oracle.graal.python.builtins.objects.set.PBaseSet;
115-
import com.oracle.graal.python.builtins.objects.slice.PSlice;
116-
import com.oracle.graal.python.builtins.objects.slice.PSlice.SliceInfo;
117115
import com.oracle.graal.python.builtins.objects.str.PString;
118116
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
119117
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
@@ -148,8 +146,6 @@
148146
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
149147
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
150148
import com.oracle.graal.python.nodes.object.GetClassNode;
151-
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
152-
import com.oracle.graal.python.nodes.subscript.SliceLiteralNode;
153149
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
154150
import com.oracle.graal.python.nodes.truffle.PythonTypes;
155151
import com.oracle.graal.python.nodes.util.CastToByteNode;
@@ -1417,58 +1413,6 @@ PThreadState get() {
14171413
}
14181414
}
14191415

1420-
@Builtin(name = "PyTruffleSlice_GetIndicesEx", minNumOfPositionalArgs = 4)
1421-
@TypeSystemReference(PythonArithmeticTypes.class)
1422-
@GenerateNodeFactory
1423-
abstract static class PyTruffleSlice_GetIndicesEx extends NativeBuiltin {
1424-
@Specialization
1425-
Object doUnpack(int start, int stop, int step, int length) {
1426-
PSlice tmpSlice = factory().createSlice(start, stop, step);
1427-
SliceInfo actualIndices = tmpSlice.computeIndices(length);
1428-
return factory().createTuple(new Object[]{actualIndices.start, actualIndices.stop, actualIndices.step, actualIndices.length});
1429-
}
1430-
1431-
@Specialization(rewriteOn = ArithmeticException.class)
1432-
Object doUnpackLong(long start, long stop, long step, long length) {
1433-
PSlice tmpSlice = factory().createSlice(PInt.intValueExact(start), PInt.intValueExact(stop), PInt.intValueExact(step));
1434-
SliceInfo actualIndices = tmpSlice.computeIndices(PInt.intValueExact(length));
1435-
return factory().createTuple(new Object[]{actualIndices.start, actualIndices.stop, actualIndices.step, actualIndices.length});
1436-
}
1437-
1438-
@Specialization(replaces = {"doUnpackLong", "doUnpack"})
1439-
Object doUnpackLongOvf0(long start, long stop, long step, long length) {
1440-
try {
1441-
PSlice tmpSlice = factory().createSlice(PInt.intValueExact(start), PInt.intValueExact(stop), PInt.intValueExact(step));
1442-
SliceInfo actualIndices = tmpSlice.computeIndices(length > Integer.MAX_VALUE ? Integer.MAX_VALUE : PInt.intValueExact(length));
1443-
return factory().createTuple(new Object[]{actualIndices.start, actualIndices.stop, actualIndices.step, actualIndices.length});
1444-
} catch (ArithmeticException e) {
1445-
throw raiseIndexError();
1446-
}
1447-
}
1448-
1449-
@Specialization(replaces = {"doUnpackLongOvf0"})
1450-
Object doUnpackLongOvf1(Object start, Object stop, Object step, Object lengthObj,
1451-
@Cached("createOverflow()") CastToIndexNode castToIndexNode,
1452-
@Cached("create()") IsBuiltinClassProfile profile,
1453-
@Cached("create()") SliceLiteralNode sliceLiteralNode) {
1454-
1455-
int length;
1456-
try {
1457-
length = castToIndexNode.execute(lengthObj);
1458-
} catch (PException e) {
1459-
e.expect(OverflowError, profile);
1460-
length = Integer.MAX_VALUE;
1461-
}
1462-
1463-
try {
1464-
SliceInfo actualIndices = sliceLiteralNode.execute(start, stop, step).computeIndices(length);
1465-
return factory().createTuple(new Object[]{actualIndices.start, actualIndices.stop, actualIndices.step, actualIndices.length});
1466-
} catch (ArithmeticException e) {
1467-
throw raiseIndexError();
1468-
}
1469-
}
1470-
}
1471-
14721416
@Builtin(name = "PyTruffle_GetSetDescriptor", parameterNames = {"fget", "fset", "name", "owner"})
14731417
@GenerateNodeFactory
14741418
public abstract static class GetSetDescriptorNode extends PythonBuiltinNode {

graalpython/lib-graalpython/python_cext.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,11 +1330,6 @@ def PyThread_release_lock(lock):
13301330
return lock.release()
13311331

13321332

1333-
@may_raise
1334-
def PySlice_GetIndicesEx(start, stop, step, length):
1335-
return PyTruffleSlice_GetIndicesEx(start, stop, step, length)
1336-
1337-
13381333
@may_raise
13391334
def PySlice_New(start, stop, step):
13401335
return slice(start, stop, step)

0 commit comments

Comments
 (0)