Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-100712: make it possible to disable specialization (for debugging) #100713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
hasfree = []
hasexc = []


ENABLE_SPECIALIZATION = True

def is_pseudo(op):
return op >= MIN_PSEUDO_OPCODE and op <= MAX_PSEUDO_OPCODE

Expand Down
5 changes: 4 additions & 1 deletion Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import contextlib
import functools
import getpass
import opcode
import os
import re
import stat
Expand Down Expand Up @@ -46,7 +47,7 @@
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
"check__all__", "skip_if_buggy_ucrt_strfptime",
"check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer",
"requires_limited_api",
"requires_limited_api", "requires_specialization",
# sys
"is_jython", "is_android", "is_emscripten", "is_wasi",
"check_impl_detail", "unix_shell", "setswitchinterval",
Expand Down Expand Up @@ -1077,6 +1078,8 @@ def requires_limited_api(test):
return unittest.skipUnless(
_testcapi.LIMITED_API_AVAILABLE, 'needs Limited API support')(test)

def requires_specialization(test):
return unittest.skipUnless(opcode.ENABLE_SPECIALIZATION, "requires specialization")

def _filter_suite(suite, pred):
"""Recursively filter test cases in a suite based on a predicate."""
Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
import textwrap
import warnings
from test import support
from test.support import script_helper, requires_debug_ranges
from test.support import (script_helper, requires_debug_ranges,
requires_specialization)
from test.support.os_helper import FakePath


Expand Down Expand Up @@ -1251,6 +1252,7 @@ def test_multiline_expression(self):
self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
line=1, end_line=3, column=0, end_column=1)

@requires_specialization
def test_multiline_boolean_expression(self):
snippet = """\
if (a or
Expand Down
8 changes: 7 additions & 1 deletion Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import sys
import types
import unittest
from test.support import captured_stdout, requires_debug_ranges, cpython_only
from test.support import (captured_stdout, requires_debug_ranges,
requires_specialization, cpython_only)
from test.support.bytecode_helper import BytecodeTestCase

import opcode
Expand Down Expand Up @@ -1086,12 +1087,14 @@ def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY):
f()

@cpython_only
@requires_specialization
def test_super_instructions(self):
self.code_quicken(lambda: load_test(0, 0))
got = self.get_disassembly(load_test, adaptive=True)
self.do_disassembly_compare(got, dis_load_test_quickened_code, True)

@cpython_only
@requires_specialization
def test_binary_specialize(self):
binary_op_quicken = """\
0 0 RESUME 0
Expand Down Expand Up @@ -1130,6 +1133,7 @@ def test_binary_specialize(self):
self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_DICT", True)

@cpython_only
@requires_specialization
def test_load_attr_specialize(self):
load_attr_quicken = """\
0 0 RESUME 0
Expand All @@ -1144,6 +1148,7 @@ def test_load_attr_specialize(self):
self.do_disassembly_compare(got, load_attr_quicken, True)

@cpython_only
@requires_specialization
def test_call_specialize(self):
call_quicken = """\
0 RESUME 0
Expand All @@ -1160,6 +1165,7 @@ def test_call_specialize(self):
self.do_disassembly_compare(got, call_quicken)

@cpython_only
@requires_specialization
def test_loop_quicken(self):
# Loop can trigger a quicken where the loop is located
self.code_quicken(loop_test, 1)
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from test import support
from test.support import import_helper
from test.support import os_helper
from test.support import requires_specialization
import unittest

from collections import namedtuple
Expand Down Expand Up @@ -346,6 +347,7 @@ def test_simple_initialization_api(self):
out, err = self.run_embedded_interpreter("test_repeated_simple_init")
self.assertEqual(out, 'Finalized\n' * INIT_LOOPS)

@requires_specialization
def test_specialized_static_code_gets_unspecialized_at_Py_FINALIZE(self):
# https://github.com/python/cpython/issues/92031

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added option to build cpython with specialization disabled, by setting ``ENABLE_SPECIALIZATION=False`` in :mod:`opcode`, followed by ``make regen-all``.
24 changes: 24 additions & 0 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ dummy_func(
};

inst(BINARY_SUBSCR, (unused/4, container, sub -- res)) {
#if ENABLE_SPECIALIZATION
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit:

Typically, we unindent #if/#else/#endif one level for easier readability. I find this a bit easier to parse:

Suggested change
#if ENABLE_SPECIALIZATION
#if ENABLE_SPECIALIZATION

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that's traditional, but honestly I'm not too happy with that convention and I find it less readable that what Irit proposes here. Also, she tried outdenting it in an early regmachine branch and the generated code was indentded weirdly.

_PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
Expand All @@ -313,6 +314,7 @@ dummy_func(
}
STAT_INC(BINARY_SUBSCR, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
res = PyObject_GetItem(container, sub);
DECREF_INPUTS();
ERROR_IF(res == NULL, error);
Expand Down Expand Up @@ -441,6 +443,7 @@ dummy_func(
};

inst(STORE_SUBSCR, (counter/1, v, container, sub -- )) {
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
assert(cframe.use_tracing == 0);
next_instr--;
Expand All @@ -450,6 +453,9 @@ dummy_func(
STAT_INC(STORE_SUBSCR, deferred);
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#else
(void)counter; // Unused.
#endif /* ENABLE_SPECIALIZATION */
/* container[sub] = v */
int err = PyObject_SetItem(container, sub, v);
DECREF_INPUTS();
Expand Down Expand Up @@ -872,6 +878,7 @@ dummy_func(

// stack effect: (__0 -- __array[oparg])
inst(UNPACK_SEQUENCE) {
#if ENABLE_SPECIALIZATION
_PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
Expand All @@ -882,6 +889,7 @@ dummy_func(
}
STAT_INC(UNPACK_SEQUENCE, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
PyObject *seq = POP();
PyObject **top = stack_pointer + oparg;
if (!unpack_iterable(tstate, seq, oparg, -1, top)) {
Expand Down Expand Up @@ -956,6 +964,7 @@ dummy_func(
};

inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) {
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(names, oparg);
Expand All @@ -966,6 +975,9 @@ dummy_func(
STAT_INC(STORE_ATTR, deferred);
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#else
(void)counter; // Unused.
#endif /* ENABLE_SPECIALIZATION */
PyObject *name = GETITEM(names, oparg);
int err = PyObject_SetAttr(owner, name, v);
Py_DECREF(v);
Expand Down Expand Up @@ -1064,6 +1076,7 @@ dummy_func(

// error: LOAD_GLOBAL has irregular stack effect
inst(LOAD_GLOBAL) {
#if ENABLE_SPECIALIZATION
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
Expand All @@ -1074,6 +1087,7 @@ dummy_func(
}
STAT_INC(LOAD_GLOBAL, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
int push_null = oparg & 1;
PEEK(0) = NULL;
PyObject *name = GETITEM(names, oparg>>1);
Expand Down Expand Up @@ -1430,6 +1444,7 @@ dummy_func(

// error: LOAD_ATTR has irregular stack effect
inst(LOAD_ATTR) {
#if ENABLE_SPECIALIZATION
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
Expand All @@ -1441,6 +1456,7 @@ dummy_func(
}
STAT_INC(LOAD_ATTR, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
PyObject *name = GETITEM(names, oparg >> 1);
PyObject *owner = TOP();
if (oparg & 1) {
Expand Down Expand Up @@ -1778,6 +1794,7 @@ dummy_func(
};

inst(COMPARE_AND_BRANCH, (unused/2, left, right -- )) {
#if ENABLE_SPECIALIZATION
_PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
Expand All @@ -1787,6 +1804,7 @@ dummy_func(
}
STAT_INC(COMPARE_AND_BRANCH, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
assert((oparg >> 4) <= Py_GE);
PyObject *cond = PyObject_RichCompare(left, right, oparg>>4);
Py_DECREF(left);
Expand Down Expand Up @@ -2194,6 +2212,7 @@ dummy_func(

// stack effect: ( -- __0)
inst(FOR_ITER) {
#if ENABLE_SPECIALIZATION
_PyForIterCache *cache = (_PyForIterCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
Expand All @@ -2203,6 +2222,7 @@ dummy_func(
}
STAT_INC(FOR_ITER, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
/* before: [iter]; after: [iter, iter()] *or* [] */
PyObject *iter = TOP();
PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
Expand Down Expand Up @@ -2518,6 +2538,7 @@ dummy_func(

// stack effect: (__0, __array[oparg] -- )
inst(CALL) {
#if ENABLE_SPECIALIZATION
_PyCallCache *cache = (_PyCallCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
Expand All @@ -2530,6 +2551,7 @@ dummy_func(
}
STAT_INC(CALL, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
int total_args, is_meth;
is_meth = is_method(stack_pointer, oparg);
PyObject *function = PEEK(oparg + 1);
Expand Down Expand Up @@ -3262,6 +3284,7 @@ dummy_func(
}

inst(BINARY_OP, (unused/1, lhs, rhs -- res)) {
#if ENABLE_SPECIALIZATION
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
Expand All @@ -3271,6 +3294,7 @@ dummy_func(
}
STAT_INC(BINARY_OP, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
assert(0 <= oparg);
assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops));
assert(binary_ops[oparg]);
Expand Down
Loading