aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2021-07-15 13:13:12 +0100
committerGitHub <noreply@github.com>2021-07-15 13:13:12 +0100
commit641345d636320a6fca04a5271fa4c4c5ba3e5437 (patch)
tree94bc416ec61aa551bf4691fa70b3ad92373783ed /Python/ceval.c
parenta0551059ba6a83d32a36fb3b87911c77f26f5b9f (diff)
downloadcpython-641345d636320a6fca04a5271fa4c4c5ba3e5437.tar.gz
cpython-641345d636320a6fca04a5271fa4c4c5ba3e5437.zip
bpo-26280: Port BINARY_SUBSCR to PEP 659 adaptive interpreter (GH-27043)
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index 22184058af2..1467c12fd5e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -15,6 +15,7 @@
#include "pycore_ceval.h" // _PyEval_SignalAsyncExc()
#include "pycore_code.h"
#include "pycore_initconfig.h" // _PyStatus_OK()
+#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_object.h" // _PyObject_GC_TRACK()
#include "pycore_moduleobject.h"
#include "pycore_pyerrors.h" // _PyErr_Fetch()
@@ -1398,6 +1399,8 @@ eval_frame_handle_pending(PyThreadState *tstate)
#define DEOPT_IF(cond, instname) if (cond) { goto instname ## _miss; }
+#define UPDATE_PREV_INSTR_OPARG(instr, oparg) ((uint8_t*)(instr))[-1] = (oparg)
+
#define GLOBALS() specials[FRAME_SPECIALS_GLOBALS_OFFSET]
#define BUILTINS() specials[FRAME_SPECIALS_BUILTINS_OFFSET]
#define LOCALS() specials[FRAME_SPECIALS_LOCALS_OFFSET]
@@ -1913,6 +1916,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
}
case TARGET(BINARY_SUBSCR): {
+ PREDICTED(BINARY_SUBSCR);
+ STAT_INC(BINARY_SUBSCR, unquickened);
PyObject *sub = POP();
PyObject *container = TOP();
PyObject *res = PyObject_GetItem(container, sub);
@@ -1924,6 +1929,91 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
DISPATCH();
}
+ case TARGET(BINARY_SUBSCR_ADAPTIVE): {
+ if (oparg == 0) {
+ PyObject *sub = TOP();
+ PyObject *container = SECOND();
+ next_instr--;
+ if (_Py_Specialize_BinarySubscr(container, sub, next_instr) < 0) {
+ goto error;
+ }
+ DISPATCH();
+ }
+ else {
+ STAT_INC(BINARY_SUBSCR, deferred);
+ // oparg is the adaptive cache counter
+ UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1);
+ assert(_Py_OPCODE(next_instr[-1]) == BINARY_SUBSCR_ADAPTIVE);
+ assert(_Py_OPARG(next_instr[-1]) == oparg - 1);
+ JUMP_TO_INSTRUCTION(BINARY_SUBSCR);
+ }
+ }
+
+ case TARGET(BINARY_SUBSCR_LIST_INT): {
+ PyObject *sub = TOP();
+ PyObject *list = SECOND();
+ DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
+ DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
+
+ // Deopt unless 0 <= sub < PyList_Size(list)
+ Py_ssize_t signed_magnitude = Py_SIZE(sub);
+ DEOPT_IF(((size_t)signed_magnitude) > 1, BINARY_SUBSCR);
+ assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0);
+ Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
+ DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR);
+
+ STAT_INC(BINARY_SUBSCR, hit);
+ PyObject *res = PyList_GET_ITEM(list, index);
+ assert(res != NULL);
+ Py_INCREF(res);
+ STACK_SHRINK(1);
+ Py_DECREF(sub);
+ SET_TOP(res);
+ Py_DECREF(list);
+ DISPATCH();
+ }
+
+ case TARGET(BINARY_SUBSCR_TUPLE_INT): {
+ PyObject *sub = TOP();
+ PyObject *tuple = SECOND();
+ DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
+ DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR);
+
+ // Deopt unless 0 <= sub < PyTuple_Size(list)
+ Py_ssize_t signed_magnitude = Py_SIZE(sub);
+ DEOPT_IF(((size_t)signed_magnitude) > 1, BINARY_SUBSCR);
+ assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0);
+ Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
+ DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR);
+
+ STAT_INC(BINARY_SUBSCR, hit);
+ PyObject *res = PyTuple_GET_ITEM(tuple, index);
+ assert(res != NULL);
+ Py_INCREF(res);
+ STACK_SHRINK(1);
+ Py_DECREF(sub);
+ SET_TOP(res);
+ Py_DECREF(tuple);
+ DISPATCH();
+ }
+
+ case TARGET(BINARY_SUBSCR_DICT): {
+ PyObject *dict = SECOND();
+ DEOPT_IF(!PyDict_CheckExact(SECOND()), BINARY_SUBSCR);
+ STAT_INC(BINARY_SUBSCR, hit);
+ PyObject *sub = TOP();
+ PyObject *res = PyDict_GetItemWithError(dict, sub);
+ if (res == NULL) {
+ goto binary_subscr_dict_error;
+ }
+ Py_INCREF(res);
+ STACK_SHRINK(1);
+ Py_DECREF(sub);
+ SET_TOP(res);
+ Py_DECREF(dict);
+ DISPATCH();
+ }
+
case TARGET(BINARY_LSHIFT): {
PyObject *right = POP();
PyObject *left = TOP();
@@ -4327,8 +4417,34 @@ opname ## _miss: \
JUMP_TO_INSTRUCTION(opname); \
}
+#define MISS_WITH_OPARG_COUNTER(opname) \
+opname ## _miss: \
+ { \
+ STAT_INC(opname, miss); \
+ uint8_t oparg = saturating_decrement(_Py_OPARG(next_instr[-1])); \
+ UPDATE_PREV_INSTR_OPARG(next_instr, oparg); \
+ assert(_Py_OPARG(next_instr[-1]) == oparg); \
+ if (oparg == saturating_zero()) /* too many cache misses */ { \
+ oparg = ADAPTIVE_CACHE_BACKOFF; \
+ next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
+ STAT_INC(opname, deopt); \
+ } \
+ JUMP_TO_INSTRUCTION(opname); \
+ }
+
MISS_WITH_CACHE(LOAD_ATTR)
MISS_WITH_CACHE(LOAD_GLOBAL)
+MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR)
+
+binary_subscr_dict_error:
+ {
+ PyObject *sub = POP();
+ if (!_PyErr_Occurred(tstate)) {
+ _PyErr_SetKeyError(sub);
+ }
+ Py_DECREF(sub);
+ goto error;
+ }
error:
/* Double-check exception status. */