diff --git a/third_party/python/Include/pyport.h b/third_party/python/Include/pyport.h index cd7a44257..7db929870 100644 --- a/third_party/python/Include/pyport.h +++ b/third_party/python/Include/pyport.h @@ -235,6 +235,28 @@ typedef int Py_ssize_clean_t; #define Py_DEPRECATED(VERSION_UNUSED) #endif +/* _Py_HOT_FUNCTION + * The hot attribute on a function is used to inform the compiler that the + * function is a hot spot of the compiled program. The function is optimized + * more aggressively and on many target it is placed into special subsection of + * the text section so all hot functions appears close together improving + * locality. + * + * Usage: + * int _Py_HOT_FUNCTION x(void) { return 3; } + * + * Issue #28618: This attribute must not be abused, otherwise it can have a + * negative effect on performance. Only the functions were Python spend most of + * its time must use it. Use a profiler when running performance benchmark + * suite to find these functions. + */ +#if !IsModeDbg() && defined(__GNUC__) \ + && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) +#define _Py_HOT_FUNCTION __attribute__((hot)) +#else +#define _Py_HOT_FUNCTION +#endif + #define RTYPE RTYPE #ifdef __cplusplus #define PyMODINIT_FUNC extern "C" PyObject * diff --git a/third_party/python/Objects/call.c b/third_party/python/Objects/call.c index bd1d8b4ea..2ff0e4f0b 100644 --- a/third_party/python/Objects/call.c +++ b/third_party/python/Objects/call.c @@ -279,7 +279,7 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) /* --- PyFunction call functions ---------------------------------- */ -static PyObject* +static PyObject* _Py_HOT_FUNCTION function_code_fastcall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, PyObject *globals) { diff --git a/third_party/python/Objects/dictobject.c b/third_party/python/Objects/dictobject.c index 05490d235..cae1ff315 100644 --- a/third_party/python/Objects/dictobject.c +++ b/third_party/python/Objects/dictobject.c @@ -748,7 +748,7 @@ the value. For both, when the key isn't found a DKIX_EMPTY is returned. hashpos returns where the key index should be inserted. */ -static Py_ssize_t +static Py_ssize_t _Py_HOT_FUNCTION lookdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { @@ -862,7 +862,7 @@ top: } /* Specialized version for string-only keys */ -static Py_ssize_t +static Py_ssize_t _Py_HOT_FUNCTION lookdict_unicode(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { @@ -936,7 +936,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, /* Faster version of lookdict_unicode when it is known that no keys * will be present. */ -static Py_ssize_t +static Py_ssize_t _Py_HOT_FUNCTION lookdict_unicode_nodummy(PyDictObject *restrict mp, PyObject *restrict key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) @@ -1003,7 +1003,7 @@ lookdict_unicode_nodummy(PyDictObject *restrict mp, PyObject *restrict key, * Split tables only contain unicode keys and no dummy keys, * so algorithm is the same as lookdict_unicode_nodummy. */ -static Py_ssize_t +static Py_ssize_t _Py_HOT_FUNCTION lookdict_split(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { diff --git a/third_party/python/Objects/frameobject.c b/third_party/python/Objects/frameobject.c index f5fbb512c..0d08ace6c 100644 --- a/third_party/python/Objects/frameobject.c +++ b/third_party/python/Objects/frameobject.c @@ -461,7 +461,7 @@ static int numfree; static PyFrameObject *free_list; #define PyFrame_MAXFREELIST 200 -static void +static void _Py_HOT_FUNCTION frame_dealloc(PyFrameObject *restrict f) { PyObject **p, **valuestack; @@ -660,7 +660,7 @@ int _PyFrame_Init() return 1; } -PyFrameObject* +PyFrameObject* _Py_HOT_FUNCTION _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, PyObject *locals) { diff --git a/third_party/python/Python/ceval.c b/third_party/python/Python/ceval.c index 5ee2d60a3..0e30f4ad2 100644 --- a/third_party/python/Python/ceval.c +++ b/third_party/python/Python/ceval.c @@ -732,7 +732,7 @@ PyObject * return tstate->interp->eval_frame(f, throwflag); } -PyObject * +PyObject * _Py_HOT_FUNCTION _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) { #ifdef DXPAIRS @@ -4813,7 +4813,7 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \ x = call; \ } -static PyObject * +forceinline PyObject * _Py_HOT_FUNCTION call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames) { PyObject **pfunc = (*pp_stack) - oparg - 1; diff --git a/third_party/python/Python/errors.c b/third_party/python/Python/errors.c index 0c8a2e416..2a1039b2b 100644 --- a/third_party/python/Python/errors.c +++ b/third_party/python/Python/errors.c @@ -153,7 +153,7 @@ PyErr_SetString(PyObject *exception, const char *string) Py_XDECREF(value); } -PyObject * +PyObject * _Py_HOT_FUNCTION PyErr_Occurred(void) { PyThreadState *tstate = _PyThreadState_UncheckedGet();