summaryrefslogtreecommitdiffstats
path: root/Python/specialize.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/specialize.c')
-rw-r--r--Python/specialize.c157
1 files changed, 56 insertions, 101 deletions
diff --git a/Python/specialize.c b/Python/specialize.c
index 5717991..61d7a5d 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -16,21 +16,6 @@
* ./adaptive.md
*/
-/* Map from opcode to adaptive opcode.
- Values of zero are ignored. */
-uint8_t _PyOpcode_Adaptive[256] = {
- [LOAD_ATTR] = LOAD_ATTR_ADAPTIVE,
- [LOAD_GLOBAL] = LOAD_GLOBAL_ADAPTIVE,
- [BINARY_SUBSCR] = BINARY_SUBSCR_ADAPTIVE,
- [STORE_SUBSCR] = STORE_SUBSCR_ADAPTIVE,
- [CALL] = CALL_ADAPTIVE,
- [STORE_ATTR] = STORE_ATTR_ADAPTIVE,
- [BINARY_OP] = BINARY_OP_ADAPTIVE,
- [COMPARE_OP] = COMPARE_OP_ADAPTIVE,
- [UNPACK_SEQUENCE] = UNPACK_SEQUENCE_ADAPTIVE,
- [FOR_ITER] = FOR_ITER_ADAPTIVE,
-};
-
#ifdef Py_STATS
PyStats _py_stats_struct = { 0 };
PyStats *_py_stats = &_py_stats_struct;
@@ -143,7 +128,7 @@ print_spec_stats(FILE *out, OpcodeStats *stats)
fprintf(out, "opcode[%d].specializable : 1\n", BINARY_SLICE);
fprintf(out, "opcode[%d].specializable : 1\n", STORE_SLICE);
for (int i = 0; i < 256; i++) {
- if (_PyOpcode_Adaptive[i]) {
+ if (_PyOpcode_Caches[i]) {
fprintf(out, "opcode[%d].specializable : 1\n", i);
}
PRINT_STAT(i, specialization.success);
@@ -275,74 +260,42 @@ do { \
#define SPECIALIZATION_FAIL(opcode, kind) ((void)0)
#endif
-// Insert adaptive instructions and superinstructions. This cannot fail.
+// Initialize warmup counters and insert superinstructions. This cannot fail.
void
_PyCode_Quicken(PyCodeObject *code)
{
- int previous_opcode = -1;
+ int previous_opcode = 0;
_Py_CODEUNIT *instructions = _PyCode_CODE(code);
for (int i = 0; i < Py_SIZE(code); i++) {
int opcode = _PyOpcode_Deopt[_Py_OPCODE(instructions[i])];
- uint8_t adaptive_opcode = _PyOpcode_Adaptive[opcode];
- if (adaptive_opcode) {
- _Py_SET_OPCODE(instructions[i], adaptive_opcode);
- instructions[i + 1] = adaptive_counter_start();
- previous_opcode = -1;
- i += _PyOpcode_Caches[opcode];
- }
- else {
- assert(!_PyOpcode_Caches[opcode]);
- switch (opcode) {
- case EXTENDED_ARG:
- _Py_SET_OPCODE(instructions[i], EXTENDED_ARG_QUICK);
- break;
- case LOAD_FAST:
- switch(previous_opcode) {
- case LOAD_FAST:
- _Py_SET_OPCODE(instructions[i - 1],
- LOAD_FAST__LOAD_FAST);
- break;
- case STORE_FAST:
- _Py_SET_OPCODE(instructions[i - 1],
- STORE_FAST__LOAD_FAST);
- break;
- case LOAD_CONST:
- _Py_SET_OPCODE(instructions[i - 1],
- LOAD_CONST__LOAD_FAST);
- break;
- }
- break;
- case STORE_FAST:
- if (previous_opcode == STORE_FAST) {
- _Py_SET_OPCODE(instructions[i - 1],
- STORE_FAST__STORE_FAST);
- }
- break;
- case LOAD_CONST:
- if (previous_opcode == LOAD_FAST) {
- _Py_SET_OPCODE(instructions[i - 1],
- LOAD_FAST__LOAD_CONST);
- }
- break;
- }
- previous_opcode = opcode;
+ int caches = _PyOpcode_Caches[opcode];
+ if (caches) {
+ instructions[i + 1] = adaptive_counter_warmup();
+ previous_opcode = 0;
+ i += caches;
+ continue;
+ }
+ switch (previous_opcode << 8 | opcode) {
+ case LOAD_CONST << 8 | LOAD_FAST:
+ _Py_SET_OPCODE(instructions[i - 1], LOAD_CONST__LOAD_FAST);
+ break;
+ case LOAD_FAST << 8 | LOAD_CONST:
+ _Py_SET_OPCODE(instructions[i - 1], LOAD_FAST__LOAD_CONST);
+ break;
+ case LOAD_FAST << 8 | LOAD_FAST:
+ _Py_SET_OPCODE(instructions[i - 1], LOAD_FAST__LOAD_FAST);
+ break;
+ case STORE_FAST << 8 | LOAD_FAST:
+ _Py_SET_OPCODE(instructions[i - 1], STORE_FAST__LOAD_FAST);
+ break;
+ case STORE_FAST << 8 | STORE_FAST:
+ _Py_SET_OPCODE(instructions[i - 1], STORE_FAST__STORE_FAST);
+ break;
}
+ previous_opcode = opcode;
}
}
-static inline int
-miss_counter_start(void) {
- /* Starting value for the counter.
- * This value needs to be not too low, otherwise
- * it would cause excessive de-optimization.
- * Neither should it be too high, or that would delay
- * de-optimization excessively when it is needed.
- * A value around 50 seems to work, and we choose a
- * prime number to avoid artifacts.
- */
- return 53;
-}
-
#define SIMPLE_FUNCTION 0
/* Common */
@@ -859,12 +812,13 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
fail:
STAT_INC(LOAD_ATTR, failure);
assert(!PyErr_Occurred());
+ _Py_SET_OPCODE(*instr, LOAD_ATTR);
cache->counter = adaptive_counter_backoff(cache->counter);
return 0;
success:
STAT_INC(LOAD_ATTR, success);
assert(!PyErr_Occurred());
- cache->counter = miss_counter_start();
+ cache->counter = adaptive_counter_cooldown();
return 0;
}
@@ -942,12 +896,13 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
fail:
STAT_INC(STORE_ATTR, failure);
assert(!PyErr_Occurred());
+ _Py_SET_OPCODE(*instr, STORE_ATTR);
cache->counter = adaptive_counter_backoff(cache->counter);
return 0;
success:
STAT_INC(STORE_ATTR, success);
assert(!PyErr_Occurred());
- cache->counter = miss_counter_start();
+ cache->counter = adaptive_counter_cooldown();
return 0;
}
@@ -1127,7 +1082,7 @@ fail:
return 0;
}
-int
+void
_Py_Specialize_LoadGlobal(
PyObject *globals, PyObject *builtins,
_Py_CODEUNIT *instr, PyObject *name)
@@ -1200,13 +1155,13 @@ _Py_Specialize_LoadGlobal(
fail:
STAT_INC(LOAD_GLOBAL, failure);
assert(!PyErr_Occurred());
+ _Py_SET_OPCODE(*instr, LOAD_GLOBAL);
cache->counter = adaptive_counter_backoff(cache->counter);
- return 0;
+ return;
success:
STAT_INC(LOAD_GLOBAL, success);
assert(!PyErr_Occurred());
- cache->counter = miss_counter_start();
- return 0;
+ cache->counter = adaptive_counter_cooldown();
}
#ifdef Py_STATS
@@ -1294,7 +1249,7 @@ function_get_version(PyObject *o, int opcode)
return version;
}
-int
+void
_Py_Specialize_BinarySubscr(
PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
{
@@ -1360,16 +1315,16 @@ _Py_Specialize_BinarySubscr(
fail:
STAT_INC(BINARY_SUBSCR, failure);
assert(!PyErr_Occurred());
+ _Py_SET_OPCODE(*instr, BINARY_SUBSCR);
cache->counter = adaptive_counter_backoff(cache->counter);
- return 0;
+ return;
success:
STAT_INC(BINARY_SUBSCR, success);
assert(!PyErr_Occurred());
- cache->counter = miss_counter_start();
- return 0;
+ cache->counter = adaptive_counter_cooldown();
}
-int
+void
_Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
{
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1);
@@ -1464,20 +1419,19 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
fail:
STAT_INC(STORE_SUBSCR, failure);
assert(!PyErr_Occurred());
+ _Py_SET_OPCODE(*instr, STORE_SUBSCR);
cache->counter = adaptive_counter_backoff(cache->counter);
- return 0;
+ return;
success:
STAT_INC(STORE_SUBSCR, success);
assert(!PyErr_Occurred());
- cache->counter = miss_counter_start();
- return 0;
+ cache->counter = adaptive_counter_cooldown();
}
static int
specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
PyObject *kwnames)
{
- assert(_Py_OPCODE(*instr) == CALL_ADAPTIVE);
PyTypeObject *tp = _PyType_CAST(callable);
if (tp->tp_new == PyBaseObject_Type.tp_new) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PYTHON_CLASS);
@@ -1539,7 +1493,6 @@ static int
specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr,
int nargs, PyObject *kwnames)
{
- assert(_Py_OPCODE(*instr) == CALL_ADAPTIVE);
if (kwnames) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
return -1;
@@ -1591,7 +1544,6 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
PyObject *kwnames, bool bound_method)
{
_PyCallCache *cache = (_PyCallCache *)(instr + 1);
- assert(_Py_OPCODE(*instr) == CALL_ADAPTIVE);
PyCodeObject *code = (PyCodeObject *)func->func_code;
int kind = function_kind(code);
/* Don't specialize if PEP 523 is active */
@@ -1646,7 +1598,6 @@ static int
specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
PyObject *kwnames)
{
- assert(_Py_OPCODE(*instr) == CALL_ADAPTIVE);
if (PyCFunction_GET_FUNCTION(callable) == NULL) {
return 1;
}
@@ -1743,7 +1694,7 @@ call_fail_kind(PyObject *callable)
/* TODO:
- Specialize calling classes.
*/
-int
+void
_Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
PyObject *kwnames)
{
@@ -1781,14 +1732,14 @@ _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
if (fail) {
STAT_INC(CALL, failure);
assert(!PyErr_Occurred());
+ _Py_SET_OPCODE(*instr, CALL);
cache->counter = adaptive_counter_backoff(cache->counter);
}
else {
STAT_INC(CALL, success);
assert(!PyErr_Occurred());
- cache->counter = miss_counter_start();
+ cache->counter = adaptive_counter_cooldown();
}
- return 0;
}
#ifdef Py_STATS
@@ -1928,17 +1879,18 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
// back to BINARY_OP (unless we're collecting stats, where it's more
// important to get accurate hit counts for the unadaptive version
// and each of the different failure types):
- _Py_SET_OPCODE(*instr, BINARY_OP);
+ _Py_SET_OPCODE(*instr, BINARY_OP_GENERIC);
return;
#endif
}
SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs));
STAT_INC(BINARY_OP, failure);
+ _Py_SET_OPCODE(*instr, BINARY_OP);
cache->counter = adaptive_counter_backoff(cache->counter);
return;
success:
STAT_INC(BINARY_OP, success);
- cache->counter = miss_counter_start();
+ cache->counter = adaptive_counter_cooldown();
}
@@ -2004,7 +1956,7 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
// counts for the unadaptive version and each of the different failure
// types):
#ifndef Py_STATS
- _Py_SET_OPCODE(*instr, COMPARE_OP);
+ _Py_SET_OPCODE(*instr, COMPARE_OP_GENERIC);
return;
#else
if (next_opcode == EXTENDED_ARG) {
@@ -2054,11 +2006,12 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs));
failure:
STAT_INC(COMPARE_OP, failure);
+ _Py_SET_OPCODE(*instr, COMPARE_OP);
cache->counter = adaptive_counter_backoff(cache->counter);
return;
success:
STAT_INC(COMPARE_OP, success);
- cache->counter = miss_counter_start();
+ cache->counter = adaptive_counter_cooldown();
}
#ifdef Py_STATS
@@ -2104,11 +2057,12 @@ _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg)
SPECIALIZATION_FAIL(UNPACK_SEQUENCE, unpack_sequence_fail_kind(seq));
failure:
STAT_INC(UNPACK_SEQUENCE, failure);
+ _Py_SET_OPCODE(*instr, UNPACK_SEQUENCE);
cache->counter = adaptive_counter_backoff(cache->counter);
return;
success:
STAT_INC(UNPACK_SEQUENCE, success);
- cache->counter = miss_counter_start();
+ cache->counter = adaptive_counter_cooldown();
}
#ifdef Py_STATS
@@ -2207,9 +2161,10 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
SPECIALIZATION_FAIL(FOR_ITER,
_PySpecialization_ClassifyIterator(iter));
STAT_INC(FOR_ITER, failure);
+ _Py_SET_OPCODE(*instr, FOR_ITER);
cache->counter = adaptive_counter_backoff(cache->counter);
return;
success:
STAT_INC(FOR_ITER, success);
- cache->counter = miss_counter_start();
+ cache->counter = adaptive_counter_cooldown();
}