GH-129386: Add test.support.reset_code (GH-129486)

This commit is contained in:
Brandt Bucher 2025-01-31 02:50:54 -08:00 committed by GitHub
parent e3eba8ce26
commit 674befbd7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 22 additions and 9 deletions

View file

@ -66,6 +66,7 @@ __all__ = [
"BrokenIter", "BrokenIter",
"in_systemd_nspawn_sync_suppressed", "in_systemd_nspawn_sync_suppressed",
"run_no_yield_async_fn", "run_yielding_async_fn", "async_yield", "run_no_yield_async_fn", "run_yielding_async_fn", "async_yield",
"reset_code",
] ]
@ -1286,6 +1287,12 @@ def requires_specialization_ft(test):
_opcode.ENABLE_SPECIALIZATION_FT, "requires specialization")(test) _opcode.ENABLE_SPECIALIZATION_FT, "requires specialization")(test)
def reset_code(f: types.FunctionType) -> types.FunctionType:
"""Clear all specializations, local instrumentation, and JIT code for the given function."""
f.__code__ = f.__code__.replace()
return f
#======================================================================= #=======================================================================
# Check for the presence of docstrings. # Check for the presence of docstrings.

View file

@ -9,7 +9,8 @@ import os
import _opcode import _opcode
from test.support import (script_helper, requires_specialization, from test.support import (script_helper, requires_specialization,
import_helper, Py_GIL_DISABLED, requires_jit_enabled) import_helper, Py_GIL_DISABLED, requires_jit_enabled,
reset_code)
_testinternalcapi = import_helper.import_module("_testinternalcapi") _testinternalcapi = import_helper.import_module("_testinternalcapi")
@ -19,11 +20,11 @@ from _testinternalcapi import TIER2_THRESHOLD
@contextlib.contextmanager @contextlib.contextmanager
def clear_executors(func): def clear_executors(func):
# Clear executors in func before and after running a block # Clear executors in func before and after running a block
func.__code__ = func.__code__.replace() reset_code(func)
try: try:
yield yield
finally: finally:
func.__code__ = func.__code__.replace() reset_code(func)
def get_first_executor(func): def get_first_executor(func):

View file

@ -15,7 +15,7 @@ import types
import unittest import unittest
from test.support import (captured_stdout, requires_debug_ranges, from test.support import (captured_stdout, requires_debug_ranges,
requires_specialization, cpython_only, requires_specialization, cpython_only,
os_helper, import_helper) os_helper, import_helper, reset_code)
from test.support.bytecode_helper import BytecodeTestCase from test.support.bytecode_helper import BytecodeTestCase
@ -1356,7 +1356,7 @@ class DisTests(DisTestBase):
self.code_quicken(f) self.code_quicken(f)
else: else:
# "copy" the code to un-quicken it: # "copy" the code to un-quicken it:
f.__code__ = f.__code__.replace() reset_code(f)
for instruction in _unroll_caches_as_Instructions(dis.get_instructions( for instruction in _unroll_caches_as_Instructions(dis.get_instructions(
f, show_caches=True, adaptive=adaptive f, show_caches=True, adaptive=adaptive
), show_caches=True): ), show_caches=True):

View file

@ -391,6 +391,7 @@ class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
import importlib._bootstrap import importlib._bootstrap
import opcode import opcode
import test.test_dis import test.test_dis
import test.support
def is_specialized(f): def is_specialized(f):
for instruction in dis.get_instructions(f, adaptive=True): for instruction in dis.get_instructions(f, adaptive=True):
@ -409,7 +410,7 @@ class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
func = importlib._bootstrap._handle_fromlist func = importlib._bootstrap._handle_fromlist
# "copy" the code to un-specialize it: # "copy" the code to un-specialize it:
func.__code__ = func.__code__.replace() test.support.reset_code(func)
assert not is_specialized(func), "specialized instructions found" assert not is_specialized(func), "specialized instructions found"

View file

@ -6,7 +6,7 @@ import types
import unittest import unittest
from test.support import (threading_helper, check_impl_detail, from test.support import (threading_helper, check_impl_detail,
requires_specialization, requires_specialization_ft, requires_specialization, requires_specialization_ft,
cpython_only, requires_jit_disabled) cpython_only, requires_jit_disabled, reset_code)
from test.support.import_helper import import_module from test.support.import_helper import import_module
# Skip this module on other interpreters, it is cpython specific: # Skip this module on other interpreters, it is cpython specific:
@ -579,9 +579,9 @@ class TestRacesDoNotCrash(TestBase):
# Reset: # Reset:
if check_items: if check_items:
for item in items: for item in items:
item.__code__ = item.__code__.replace() reset_code(item)
else: else:
read.__code__ = read.__code__.replace() reset_code(read)
# Specialize: # Specialize:
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
read(items) read(items)
@ -1552,6 +1552,7 @@ class TestSpecializer(TestBase):
class C: class C:
pass pass
@reset_code
def set_value(n): def set_value(n):
c = C() c = C()
for i in range(n): for i in range(n):
@ -1577,6 +1578,7 @@ class TestSpecializer(TestBase):
for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1): for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1):
setattr(c, f"_{i}", None) setattr(c, f"_{i}", None)
@reset_code
def set_value(n): def set_value(n):
for i in range(n): for i in range(n):
c.x = i c.x = i

View file

@ -0,0 +1,2 @@
Add ``test.support.reset_code``, which can be used to reset various
bytecode-level optimizations and local instrumentation for a function.