mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
GH-101291: Rearrange the size bits in PyLongObject (GH-102464)
* Eliminate all remaining uses of Py_SIZE and Py_SET_SIZE on PyLongObject, adding asserts. * Change layout of size/sign bits in longobject to support future addition of immortal ints and tagged medium ints. * Add functions to hide some internals of long object, and for setting sign and digit count. * Replace uses of IS_MEDIUM_VALUE macro with _PyLong_IsCompact().
This commit is contained in:
parent
713df2c534
commit
7559f5fda9
25 changed files with 982 additions and 898 deletions
|
@ -2,6 +2,7 @@
|
|||
#include "Python.h"
|
||||
#include "pycore_ast.h" // _PyAST_GetDocString()
|
||||
#include "pycore_compile.h" // _PyASTOptimizeState
|
||||
#include "pycore_long.h" // _PyLong
|
||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||
#include "pycore_format.h" // F_LJUST
|
||||
|
||||
|
@ -152,7 +153,9 @@ check_complexity(PyObject *obj, Py_ssize_t limit)
|
|||
static PyObject *
|
||||
safe_multiply(PyObject *v, PyObject *w)
|
||||
{
|
||||
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) {
|
||||
if (PyLong_Check(v) && PyLong_Check(w) &&
|
||||
!_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w)
|
||||
) {
|
||||
size_t vbits = _PyLong_NumBits(v);
|
||||
size_t wbits = _PyLong_NumBits(w);
|
||||
if (vbits == (size_t)-1 || wbits == (size_t)-1) {
|
||||
|
@ -198,7 +201,9 @@ safe_multiply(PyObject *v, PyObject *w)
|
|||
static PyObject *
|
||||
safe_power(PyObject *v, PyObject *w)
|
||||
{
|
||||
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) {
|
||||
if (PyLong_Check(v) && PyLong_Check(w) &&
|
||||
!_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w)
|
||||
) {
|
||||
size_t vbits = _PyLong_NumBits(v);
|
||||
size_t wbits = PyLong_AsSize_t(w);
|
||||
if (vbits == (size_t)-1 || wbits == (size_t)-1) {
|
||||
|
@ -215,7 +220,9 @@ safe_power(PyObject *v, PyObject *w)
|
|||
static PyObject *
|
||||
safe_lshift(PyObject *v, PyObject *w)
|
||||
{
|
||||
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) {
|
||||
if (PyLong_Check(v) && PyLong_Check(w) &&
|
||||
!_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w)
|
||||
) {
|
||||
size_t vbits = _PyLong_NumBits(v);
|
||||
size_t wbits = PyLong_AsSize_t(w);
|
||||
if (vbits == (size_t)-1 || wbits == (size_t)-1) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "pycore_ast.h" // _PyAST_Validate()
|
||||
#include "pycore_call.h" // _PyObject_CallNoArgs()
|
||||
#include "pycore_compile.h" // _PyAST_Compile()
|
||||
#include "pycore_long.h" // _PyLong_CompactValue
|
||||
#include "pycore_object.h" // _Py_AddToAllObjects()
|
||||
#include "pycore_pyerrors.h" // _PyErr_NoMemory()
|
||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||
|
@ -2491,7 +2492,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
|
|||
*/
|
||||
if (PyLong_CheckExact(result)) {
|
||||
int overflow;
|
||||
long i_result = PyLong_AsLongAndOverflow(result, &overflow);
|
||||
Py_ssize_t i_result = PyLong_AsLongAndOverflow(result, &overflow);
|
||||
/* If this already overflowed, don't even enter the loop. */
|
||||
if (overflow == 0) {
|
||||
Py_SETREF(result, NULL);
|
||||
|
@ -2505,15 +2506,14 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
|
|||
return PyLong_FromLong(i_result);
|
||||
}
|
||||
if (PyLong_CheckExact(item) || PyBool_Check(item)) {
|
||||
long b;
|
||||
Py_ssize_t b;
|
||||
overflow = 0;
|
||||
/* Single digits are common, fast, and cannot overflow on unpacking. */
|
||||
switch (Py_SIZE(item)) {
|
||||
case -1: b = -(sdigit) ((PyLongObject*)item)->long_value.ob_digit[0]; break;
|
||||
// Note: the continue goes to the top of the "while" loop that iterates over the elements
|
||||
case 0: Py_DECREF(item); continue;
|
||||
case 1: b = ((PyLongObject*)item)->long_value.ob_digit[0]; break;
|
||||
default: b = PyLong_AsLongAndOverflow(item, &overflow); break;
|
||||
if (_PyLong_IsCompact((PyLongObject *)item)) {
|
||||
b = _PyLong_CompactValue((PyLongObject *)item);
|
||||
}
|
||||
else {
|
||||
b = PyLong_AsLongAndOverflow(item, &overflow);
|
||||
}
|
||||
if (overflow == 0 &&
|
||||
(i_result >= 0 ? (b <= LONG_MAX - i_result)
|
||||
|
|
|
@ -345,8 +345,7 @@ dummy_func(
|
|||
DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
|
||||
|
||||
// Deopt unless 0 <= sub < PyList_Size(list)
|
||||
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR);
|
||||
assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0);
|
||||
DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR);
|
||||
Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
|
||||
DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR);
|
||||
STAT_INC(BINARY_SUBSCR, hit);
|
||||
|
@ -363,8 +362,7 @@ dummy_func(
|
|||
DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR);
|
||||
|
||||
// Deopt unless 0 <= sub < PyTuple_Size(list)
|
||||
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR);
|
||||
assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0);
|
||||
DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR);
|
||||
Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
|
||||
DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR);
|
||||
STAT_INC(BINARY_SUBSCR, hit);
|
||||
|
@ -456,7 +454,7 @@ dummy_func(
|
|||
DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR);
|
||||
|
||||
// Ensure nonnegative, zero-or-one-digit ints.
|
||||
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR);
|
||||
DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR);
|
||||
Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
|
||||
// Ensure index < len(list)
|
||||
DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR);
|
||||
|
@ -1755,12 +1753,13 @@ dummy_func(
|
|||
assert(cframe.use_tracing == 0);
|
||||
DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH);
|
||||
DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH);
|
||||
DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH);
|
||||
DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH);
|
||||
DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH);
|
||||
DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH);
|
||||
STAT_INC(COMPARE_AND_BRANCH, hit);
|
||||
assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1);
|
||||
Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0];
|
||||
Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0];
|
||||
assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 &&
|
||||
_PyLong_DigitCount((PyLongObject *)right) <= 1);
|
||||
Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left);
|
||||
Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right);
|
||||
// 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg
|
||||
int sign_ish = COMPARISON_BIT(ileft, iright);
|
||||
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
|
||||
|
|
773
Python/generated_cases.c.h
generated
773
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,7 @@
|
|||
#include "Python.h"
|
||||
#include "pycore_call.h" // _PyObject_CallNoArgs()
|
||||
#include "pycore_code.h" // _PyCode_New()
|
||||
#include "pycore_long.h" // _PyLong_DigitCount
|
||||
#include "pycore_hashtable.h" // _Py_hashtable_t
|
||||
#include "marshal.h" // Py_MARSHAL_VERSION
|
||||
|
||||
|
@ -232,13 +233,13 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
|
|||
digit d;
|
||||
|
||||
W_TYPE(TYPE_LONG, p);
|
||||
if (Py_SIZE(ob) == 0) {
|
||||
if (_PyLong_IsZero(ob)) {
|
||||
w_long((long)0, p);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set l to number of base PyLong_MARSHAL_BASE digits */
|
||||
n = Py_ABS(Py_SIZE(ob));
|
||||
n = _PyLong_DigitCount(ob);
|
||||
l = (n-1) * PyLong_MARSHAL_RATIO;
|
||||
d = ob->long_value.ob_digit[n-1];
|
||||
assert(d != 0); /* a PyLong is always normalized */
|
||||
|
@ -251,7 +252,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
|
|||
p->error = WFERR_UNMARSHALLABLE;
|
||||
return;
|
||||
}
|
||||
w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p);
|
||||
w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p);
|
||||
|
||||
for (i=0; i < n-1; i++) {
|
||||
d = ob->long_value.ob_digit[i];
|
||||
|
@ -839,7 +840,7 @@ r_PyLong(RFILE *p)
|
|||
if (ob == NULL)
|
||||
return NULL;
|
||||
|
||||
Py_SET_SIZE(ob, n > 0 ? size : -size);
|
||||
_PyLong_SetSignAndDigitCount(ob, n < 0 ? -1 : 1, size);
|
||||
|
||||
for (i = 0; i < size-1; i++) {
|
||||
d = 0;
|
||||
|
|
|
@ -1308,7 +1308,7 @@ _Py_Specialize_BinarySubscr(
|
|||
PyTypeObject *container_type = Py_TYPE(container);
|
||||
if (container_type == &PyList_Type) {
|
||||
if (PyLong_CheckExact(sub)) {
|
||||
if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) {
|
||||
if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) {
|
||||
instr->op.code = BINARY_SUBSCR_LIST_INT;
|
||||
goto success;
|
||||
}
|
||||
|
@ -1321,7 +1321,7 @@ _Py_Specialize_BinarySubscr(
|
|||
}
|
||||
if (container_type == &PyTuple_Type) {
|
||||
if (PyLong_CheckExact(sub)) {
|
||||
if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) {
|
||||
if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) {
|
||||
instr->op.code = BINARY_SUBSCR_TUPLE_INT;
|
||||
goto success;
|
||||
}
|
||||
|
@ -1389,7 +1389,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
|
|||
PyTypeObject *container_type = Py_TYPE(container);
|
||||
if (container_type == &PyList_Type) {
|
||||
if (PyLong_CheckExact(sub)) {
|
||||
if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1)
|
||||
if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)
|
||||
&& ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container))
|
||||
{
|
||||
instr->op.code = STORE_SUBSCR_LIST_INT;
|
||||
|
@ -2007,7 +2007,7 @@ _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *inst
|
|||
goto success;
|
||||
}
|
||||
if (PyLong_CheckExact(lhs)) {
|
||||
if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) {
|
||||
if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) {
|
||||
instr->op.code = COMPARE_AND_BRANCH_INT;
|
||||
goto success;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue