Skip to content

Commit 36d0999

Browse files
committed
revert using sdigits, add _PyLong_AssignValue
1 parent 188b357 commit 36d0999

File tree

5 files changed

+54
-52
lines changed

5 files changed

+54
-52
lines changed

Include/internal/pycore_long.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right);
4747
PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right);
4848
PyObject *_PyLong_Subtract(PyLongObject *left, PyLongObject *right);
4949

50+
int _PyLong_AssignValue(PyObject **target, long value);
51+
5052
/* Used by Python/mystrtoul.c, _PyBytes_FromHex(),
5153
_PyBytes_DecodeEscape(), etc. */
5254
PyAPI_DATA(unsigned char) _PyLong_DigitValue[256];

Include/internal/pycore_range.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ extern "C" {
1010

1111
typedef struct {
1212
PyObject_HEAD
13-
sdigit index;
14-
sdigit start;
15-
sdigit step;
16-
sdigit len;
13+
long index;
14+
long start;
15+
long step;
16+
long len;
1717
} _PyRangeIterObject;
1818

1919
#ifdef __cplusplus

Objects/longobject.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,35 @@ _PyLong_FromSTwoDigits(stwodigits x)
262262
return _PyLong_FromLarge(x);
263263
}
264264

265+
int
266+
_PyLong_AssignValue(PyObject **target, long value)
267+
{
268+
PyObject *old = *target;
269+
if (IS_SMALL_INT(value)) {
270+
*target = get_small_int(Py_SAFE_DOWNCAST(value, long, sdigit));
271+
Py_XDECREF(old);
272+
return 0;
273+
}
274+
else if (old != NULL && PyLong_CheckExact(old) &&
275+
Py_REFCNT(old) == 1 && Py_SIZE(old) == 1 &&
276+
(unsigned long)value <= PyLong_MASK)
277+
{
278+
// Mutate in place if there are no other references to the old object.
279+
// This avoids an allocation in a common case.
280+
((PyLongObject *)old)->ob_digit[0]
281+
= Py_SAFE_DOWNCAST(value, long, digit);
282+
return 0;
283+
}
284+
else {
285+
*target = PyLong_FromLong(value);
286+
Py_XDECREF(old);
287+
if (*target == NULL) {
288+
return -1;
289+
}
290+
return 0;
291+
}
292+
}
293+
265294
/* If a freshly-allocated int is already shared, it must
266295
be a small integer, so negating it must go to PyLong_FromLong */
267296
Py_LOCAL_INLINE(void)

Objects/rangeobject.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -911,9 +911,9 @@ fast_range_iter(long start, long stop, long step, long len)
911911
_PyRangeIterObject *it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type);
912912
if (it == NULL)
913913
return NULL;
914-
it->start = Py_SAFE_DOWNCAST(start, long, sdigit);
915-
it->step = Py_SAFE_DOWNCAST(step, long, sdigit);
916-
it->len = Py_SAFE_DOWNCAST(len, long, sdigit);
914+
it->start = start;
915+
it->step = step;
916+
it->len = len;
917917
it->index = 0;
918918
return (PyObject *)it;
919919
}
@@ -1097,13 +1097,20 @@ range_iter(PyObject *seq)
10971097
goto long_range;
10981098
}
10991099
ulen = get_len_of_range(lstart, lstop, lstep);
1100-
if (ulen > (long)PyLong_MASK ||
1101-
lstart > (long)PyLong_MASK || lstart < -(long)PyLong_MASK ||
1102-
lstop > (long)PyLong_MASK || lstop < -(long)PyLong_MASK ||
1103-
lstep > (long)PyLong_MASK || lstep < -(long)PyLong_MASK)
1104-
{
1100+
if (ulen > (unsigned long)LONG_MAX) {
11051101
goto long_range;
11061102
}
1103+
/* check for potential overflow of lstart + ulen * lstep */
1104+
if (ulen) {
1105+
if (lstep > 0) {
1106+
if (lstop > LONG_MAX - (lstep - 1))
1107+
goto long_range;
1108+
}
1109+
else {
1110+
if (lstop < LONG_MIN + (-1 - lstep))
1111+
goto long_range;
1112+
}
1113+
}
11071114
return fast_range_iter(lstart, lstop, lstep, (long)ulen);
11081115

11091116
long_range:
@@ -1190,13 +1197,6 @@ range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored))
11901197

11911198
new_stop = lstart - lstep;
11921199
new_start = (long)(new_stop + ulen * lstep);
1193-
if (ulen > (long)PyLong_MASK ||
1194-
new_start > (long)PyLong_MASK || new_start < -(long)PyLong_MASK ||
1195-
new_stop > (long)PyLong_MASK || new_stop < -(long)PyLong_MASK ||
1196-
lstep > (long)PyLong_MASK || lstep < -(long)PyLong_MASK)
1197-
{
1198-
goto long_range;
1199-
}
12001200
return fast_range_iter(new_start, new_stop, -lstep, (long)ulen);
12011201

12021202
long_range:

Python/ceval.c

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4502,44 +4502,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
45024502
STAT_INC(FOR_ITER, hit);
45034503
_Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER];
45044504
assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == STORE_FAST);
4505-
PyObject **local_ptr = &GETLOCAL(_Py_OPARG(next));
4506-
PyObject *local = *local_ptr;
45074505
if (r->index >= r->len) {
45084506
goto iterator_exhausted_no_error;
45094507
}
4510-
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1);
4511-
sdigit value = r->start + (digit)(r->index++) * r->step;
4512-
if (value < _PY_NSMALLPOSINTS && value >= -_PY_NSMALLNEGINTS) {
4513-
*local_ptr = Py_NewRef(&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS+value]);
4514-
Py_XDECREF(local);
4515-
NOTRACE_DISPATCH();
4516-
}
4517-
if (local && PyLong_CheckExact(local) && Py_REFCNT(local) == 1) {
4518-
/* A value from a range iterator is to be stored in a
4519-
local variable, and that local variable's existing
4520-
value is a PyLongObject not referenced elsewhere.
4521-
To avoid an allocation, re-use the existing
4522-
PyLongObject for the new value. */
4523-
if (value > 0) {
4524-
assert((digit)value <= PyLong_MASK);
4525-
((PyLongObject *)local)->ob_digit[0] = value;
4526-
Py_SET_SIZE(local, 1);
4527-
}
4528-
else {
4529-
assert(value >= -(sdigit)PyLong_MASK);
4530-
((PyLongObject *)local)->ob_digit[0] = -value;
4531-
Py_SET_SIZE(local, (Py_ssize_t)-1);
4532-
}
4533-
NOTRACE_DISPATCH();
4534-
}
4535-
PyObject *res = PyLong_FromLong(value);
4536-
if (res == NULL) {
4537-
// undo the JUMPBY
4538-
next_instr -= INLINE_CACHE_ENTRIES_FOR_ITER + 1;
4508+
long value = (long)(r->start +
4509+
(unsigned long)(r->index++) * r->step);
4510+
if (_PyLong_AssignValue(&GETLOCAL(_Py_OPARG(next)), value) < 0) {
45394511
goto error;
45404512
}
4541-
*local_ptr = res;
4542-
Py_XDECREF(local);
4513+
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1);
45434514
NOTRACE_DISPATCH();
45444515
}
45454516

0 commit comments

Comments
 (0)