diff -r e981b6cc56b0 Include/longintrepr.h --- a/Include/longintrepr.h Thu Oct 07 03:12:19 2010 +0200 +++ b/Include/longintrepr.h Thu Oct 07 13:53:41 2010 +0200 @@ -95,6 +95,47 @@ PyAPI_FUNC(PyLongObject *) _PyLong_New(P /* Return a copy of src. */ PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); + +/* Small integers are preallocated in an array so that they + can be shared. + The integers that are preallocated are those in the range + -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). +*/ + +#ifndef _PyLong_NSMALLPOSINTS +#define _PyLong_NSMALLPOSINTS 4096 +#endif +#ifndef _PyLong_NSMALLNEGINTS +#define _PyLong_NSMALLNEGINTS 511 +#endif +#define _PyLong_NSMALLINTS (_PyLong_NSMALLPOSINTS + _PyLong_NSMALLNEGINTS) + +extern PyLongObject _PyLong_small_ints[_PyLong_NSMALLINTS]; + +#define _PyLong_SMALL_INTS_ZERO \ + (_PyLong_small_ints + _PyLong_NSMALLNEGINTS) +#define _PyLong_SMALL_INTS_END \ + (_PyLong_small_ints + _PyLong_NSMALLNEGINTS + _PyLong_NSMALLPOSINTS) + +#define _PyLong_IS_SMALL_INT(v) \ + (((PyLongObject *)(v)) >= _PyLong_small_ints && \ + ((PyLongObject *)(v)) < _PyLong_SMALL_INTS_END) +/* These macros purposedly avoid a cast to int, since it is most of time + useless, and sometimes detrimental (because of truncation). + XXX _PyLong_AS_SMALL_INT might be slower if sizeof(PyLongObject) is not + a power of two. + */ +#define _PyLong_AS_SMALL_INT(v) \ + ((PyLongObject *)(v) - _PyLong_SMALL_INTS_ZERO) +#define _PyLong_AS_SMALL_INT_PTRDISP(v) \ + ((void *)(v) - (void *) _PyLong_SMALL_INTS_ZERO) +/* The result of this macro should be INCREF'ed */ +#define _PyLong_FROM_SMALL_INT(n) \ + ( (n) >= -_PyLong_NSMALLNEGINTS && \ + (n) < _PyLong_NSMALLPOSINTS \ + ? (PyObject *) (_PyLong_SMALL_INTS_ZERO + (n)) \ + : NULL ) + #ifdef __cplusplus } #endif diff -r e981b6cc56b0 Objects/abstract.c --- a/Objects/abstract.c Thu Oct 07 03:12:19 2010 +0200 +++ b/Objects/abstract.c Thu Oct 07 13:53:41 2010 +0200 @@ -1228,7 +1228,12 @@ PyNumber_AsSsize_t(PyObject *item, PyObj { Py_ssize_t result; PyObject *runerr; - PyObject *value = PyNumber_Index(item); + PyObject *value; + + if (_PyLong_IS_SMALL_INT(item)) + return _PyLong_AS_SMALL_INT(item); + + value = PyNumber_Index(item); if (value == NULL) return -1; diff -r e981b6cc56b0 Objects/longobject.c --- a/Objects/longobject.c Thu Oct 07 03:12:19 2010 +0200 +++ b/Objects/longobject.c Thu Oct 07 13:53:41 2010 +0200 @@ -10,26 +10,13 @@ #include #include -#ifndef NSMALLPOSINTS -#define NSMALLPOSINTS 257 -#endif -#ifndef NSMALLNEGINTS -#define NSMALLNEGINTS 5 -#endif - /* convert a PyLong of size 1, 0 or -1 to an sdigit */ -#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \ - (Py_SIZE(x) == 0 ? (sdigit)0 : \ - (sdigit)(x)->ob_digit[0])) +#define MEDIUM_VALUE(x) ((sdigit) Py_SIZE(x) * (sdigit)(x)->ob_digit[0]) #define ABS(x) ((x) < 0 ? -(x) : (x)) -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 -/* Small integers are preallocated in this array so that they - can be shared. - The integers that are preallocated are those in the range - -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). -*/ -static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; +PyLongObject _PyLong_small_ints[_PyLong_NSMALLINTS]; + +#if _PyLong_NSMALLNEGINTS + _PyLong_NSMALLPOSINTS > 0 #ifdef COUNT_ALLOCS int quick_int_allocs, quick_neg_int_allocs; #endif @@ -37,7 +24,7 @@ int quick_int_allocs, quick_neg_int_allo static PyObject * get_small_int(sdigit ival) { - PyObject *v = (PyObject*)(small_ints + ival + NSMALLNEGINTS); + PyObject *v = (PyObject*)(_PyLong_small_ints + ival + _PyLong_NSMALLNEGINTS); Py_INCREF(v); #ifdef COUNT_ALLOCS if (ival >= 0) @@ -48,7 +35,7 @@ get_small_int(sdigit ival) return v; } #define CHECK_SMALL_INT(ival) \ - do if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { \ + do if (-_PyLong_NSMALLNEGINTS <= ival && ival < _PyLong_NSMALLPOSINTS) { \ return get_small_int((sdigit)ival); \ } while(0) @@ -57,7 +44,7 @@ maybe_small_long(PyLongObject *v) { if (v && ABS(Py_SIZE(v)) <= 1) { sdigit ival = MEDIUM_VALUE(v); - if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { + if (-_PyLong_NSMALLNEGINTS <= ival && ival < _PyLong_NSMALLPOSINTS) { Py_DECREF(v); return (PyLongObject *)get_small_int(ival); } @@ -343,6 +330,9 @@ PyLong_AsLongAndOverflow(PyObject *vv, i return -1; } + if (_PyLong_IS_SMALL_INT(vv)) + return (long) _PyLong_AS_SMALL_INT(vv); + if (!PyLong_Check(vv)) { PyNumberMethods *nb; nb = vv->ob_type->tp_as_number; @@ -441,6 +431,8 @@ PyLong_AsSsize_t(PyObject *vv) { PyErr_BadInternalCall(); return -1; } + if (_PyLong_IS_SMALL_INT(vv)) + return (Py_ssize_t) _PyLong_AS_SMALL_INT(vv); if (!PyLong_Check(vv)) { PyErr_SetString(PyExc_TypeError, "an integer is required"); return -1; @@ -4820,11 +4812,11 @@ PyLong_GetInfo(void) int _PyLong_Init(void) { -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 +#if _PyLong_NSMALLNEGINTS + _PyLong_NSMALLPOSINTS > 0 int ival, size; - PyLongObject *v = small_ints; - - for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++, v++) { + PyLongObject *v = _PyLong_small_ints; + + for (ival = -_PyLong_NSMALLNEGINTS; ival < _PyLong_NSMALLPOSINTS; ival++, v++) { size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1); if (Py_TYPE(v) == &PyLong_Type) { /* The element is already initialized, most likely @@ -4862,10 +4854,10 @@ PyLong_Fini(void) /* Integers are currently statically allocated. Py_DECREF is not needed, but Python must forget about the reference or multiple reinitializations will fail. */ -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 +#if _PyLong_NSMALLNEGINTS + _PyLong_NSMALLPOSINTS > 0 int i; - PyLongObject *v = small_ints; - for (i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++, v++) { + PyLongObject *v = _PyLong_small_ints; + for (i = 0; i < _PyLong_NSMALLNEGINTS + _PyLong_NSMALLPOSINTS; i++, v++) { _Py_DEC_REFTOTAL; _Py_ForgetReference((PyObject*)v); } diff -r e981b6cc56b0 Objects/rangeobject.c --- a/Objects/rangeobject.c Thu Oct 07 03:12:19 2010 +0200 +++ b/Objects/rangeobject.c Thu Oct 07 13:53:41 2010 +0200 @@ -1,6 +1,7 @@ /* Range object implementation */ #include "Python.h" +#include "longintrepr.h" /* Support objects whose length is > PY_SSIZE_T_MAX. @@ -493,11 +494,17 @@ typedef struct { static PyObject * rangeiter_next(rangeiterobject *r) { - if (r->index < r->len) + if (r->index < r->len) { /* cast to unsigned to avoid possible signed overflow in intermediate calculations. */ - return PyLong_FromLong((long)(r->start + - (unsigned long)(r->index++) * r->step)); + long val = (long)(r->start + (unsigned long)(r->index++) * r->step); + PyObject *x = _PyLong_FROM_SMALL_INT(val); + if (x) { + Py_INCREF(x); + return x; + } + return PyLong_FromLong(val); + } return NULL; } diff -r e981b6cc56b0 Python/ceval.c --- a/Python/ceval.c Thu Oct 07 03:12:19 2010 +0200 +++ b/Python/ceval.c Thu Oct 07 13:53:41 2010 +0200 @@ -16,6 +16,7 @@ #include "eval.h" #include "opcode.h" #include "structmember.h" +#include "longintrepr.h" #include @@ -1461,7 +1462,15 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(UNARY_NEGATIVE) v = TOP(); - x = PyNumber_Negative(v); + x = NULL; + if (_PyLong_IS_SMALL_INT(v)) { + Py_ssize_t n = - _PyLong_AS_SMALL_INT(v); + x = _PyLong_FROM_SMALL_INT(n); + } + if (x) + Py_INCREF(x); + else + x = PyNumber_Negative(v); Py_DECREF(v); SET_TOP(x); if (x != NULL) DISPATCH(); @@ -1506,7 +1515,15 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(BINARY_MULTIPLY) w = POP(); v = TOP(); - x = PyNumber_Multiply(v, w); + x = NULL; + if (_PyLong_IS_SMALL_INT(w) && _PyLong_IS_SMALL_INT(v)) { + Py_ssize_t n = _PyLong_AS_SMALL_INT(v) * _PyLong_AS_SMALL_INT(w); + x = _PyLong_FROM_SMALL_INT(n); + } + if (x) + Py_INCREF(x); + else + x = PyNumber_Multiply(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); @@ -1549,15 +1566,23 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(BINARY_ADD) w = POP(); v = TOP(); + if (_PyLong_IS_SMALL_INT(w)) { + x = (PyObject *) (_PyLong_AS_SMALL_INT_PTRDISP(w) + + (void *) v); + if (_PyLong_IS_SMALL_INT(x)) { + Py_INCREF(x); + goto BINARY_ADD_end; + } + } if (PyUnicode_CheckExact(v) && PyUnicode_CheckExact(w)) { x = unicode_concatenate(v, w, f, next_instr); /* unicode_concatenate consumed the ref to v */ goto skip_decref_vx; } - else { + else x = PyNumber_Add(v, w); - } + BINARY_ADD_end: Py_DECREF(v); skip_decref_vx: Py_DECREF(w); @@ -1568,7 +1593,15 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(BINARY_SUBTRACT) w = POP(); v = TOP(); + if (_PyLong_IS_SMALL_INT(w)) { + x = (PyObject *) ((void *) v - _PyLong_AS_SMALL_INT_PTRDISP(w)); + if (_PyLong_IS_SMALL_INT(x)) { + Py_INCREF(x); + goto BINARY_SUBTRACT_end; + } + } x = PyNumber_Subtract(v, w); + BINARY_SUBTRACT_end: Py_DECREF(v); Py_DECREF(w); SET_TOP(x); @@ -1578,7 +1611,34 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(BINARY_SUBSCR) w = POP(); v = TOP(); + if (_PyLong_IS_SMALL_INT(w)) { + PyObject **items; + Py_ssize_t i, seqlen; + if (PyTuple_CheckExact(v)) + items = ((PyTupleObject *)(v))->ob_item; + else if (PyList_CheckExact(v)) + items = ((PyListObject *)(v))->ob_item; + else + goto BINARY_SUBSCR_fallback; + i = _PyLong_AS_SMALL_INT(w); + seqlen = PyTuple_GET_SIZE(v); + if (i < 0) { + i += seqlen; + if (i >= 0) { + x = items[i]; + Py_INCREF(x); + goto BINARY_SUBSCR_end; + } + } + else if (i < seqlen) { + x = items[i]; + Py_INCREF(x); + goto BINARY_SUBSCR_end; + } + } + BINARY_SUBSCR_fallback: x = PyObject_GetItem(v, w); + BINARY_SUBSCR_end: Py_DECREF(v); Py_DECREF(w); SET_TOP(x); @@ -1670,7 +1730,15 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(INPLACE_MULTIPLY) w = POP(); v = TOP(); - x = PyNumber_InPlaceMultiply(v, w); + x = NULL; + if (_PyLong_IS_SMALL_INT(w) && _PyLong_IS_SMALL_INT(v)) { + Py_ssize_t n = _PyLong_AS_SMALL_INT(w) * _PyLong_AS_SMALL_INT(v); + x = _PyLong_FROM_SMALL_INT(n); + } + if (x) + Py_INCREF(x); + else + x = PyNumber_InPlaceMultiply(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); @@ -1710,15 +1778,22 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(INPLACE_ADD) w = POP(); v = TOP(); + if (_PyLong_IS_SMALL_INT(w)) { + x = (PyObject *) (_PyLong_AS_SMALL_INT_PTRDISP(w) + + (void *) v); + if (_PyLong_IS_SMALL_INT(x)) { + Py_INCREF(x); + goto INPLACE_ADD_end; + } + } if (PyUnicode_CheckExact(v) && PyUnicode_CheckExact(w)) { x = unicode_concatenate(v, w, f, next_instr); /* unicode_concatenate consumed the ref to v */ goto skip_decref_v; } - else { - x = PyNumber_InPlaceAdd(v, w); - } + x = PyNumber_InPlaceAdd(v, w); + INPLACE_ADD_end: Py_DECREF(v); skip_decref_v: Py_DECREF(w); @@ -1729,7 +1804,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(INPLACE_SUBTRACT) w = POP(); v = TOP(); + x = NULL; + if (_PyLong_IS_SMALL_INT(w)) { + x = (PyObject *) ((void *) v - _PyLong_AS_SMALL_INT_PTRDISP(w)); + if (_PyLong_IS_SMALL_INT(x)) { + Py_INCREF(x); + goto INPLACE_SUBSTRACT_end; + } + } x = PyNumber_InPlaceSubtract(v, w); + INPLACE_SUBSTRACT_end: Py_DECREF(v); Py_DECREF(w); SET_TOP(x);