Skip to content

Commit 9dc536b

Browse files
Merge remote-tracking branch 'upstream/main' into opt_guard_code_version
2 parents 470219b + 1efd993 commit 9dc536b

File tree

7 files changed

+69
-0
lines changed

7 files changed

+69
-0
lines changed

Lib/encodings/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from . import aliases
3535

3636
_cache = {}
37+
_MAXCACHE = 500
3738
_unknown = '--unknown--'
3839
_import_tail = ['*']
3940
_aliases = aliases.aliases
@@ -111,6 +112,8 @@ def search_function(encoding):
111112

112113
if mod is None:
113114
# Cache misses
115+
if len(_cache) >= _MAXCACHE:
116+
_cache.clear()
114117
_cache[encoding] = None
115118
return None
116119

@@ -132,6 +135,8 @@ def search_function(encoding):
132135
entry = codecs.CodecInfo(*entry)
133136

134137
# Cache the codec registry entry
138+
if len(_cache) >= _MAXCACHE:
139+
_cache.clear()
135140
_cache[encoding] = entry
136141

137142
# Register its aliases (without overwriting previously registered

Lib/test/test_capi/test_opt.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3984,6 +3984,22 @@ def testfunc(n):
39843984
self.assertIn("_POP_TOP_NOP", uops)
39853985
self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2)
39863986

3987+
def test_iter_check_list(self):
3988+
def testfunc(n):
3989+
x = 0
3990+
for _ in range(n):
3991+
l = [1]
3992+
for num in l: # unguarded
3993+
x += num
3994+
return x
3995+
3996+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
3997+
self.assertEqual(res, TIER2_THRESHOLD)
3998+
uops = get_opnames(ex)
3999+
4000+
self.assertIn("_BUILD_LIST", uops)
4001+
self.assertNotIn("_ITER_CHECK_LIST", uops)
4002+
39874003
def test_match_class(self):
39884004
def testfunc(n):
39894005
class A:

Lib/test/test_codecs.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3908,5 +3908,16 @@ def test_encodings_normalize_encoding(self):
39083908
self.assertEqual(normalize('utf\xE9\u20AC\U0010ffff-8'), 'utf_8')
39093909

39103910

3911+
class CodecCacheTest(unittest.TestCase):
3912+
def test_cache_bounded(self):
3913+
for i in range(encodings._MAXCACHE + 1000):
3914+
try:
3915+
b'x'.decode(f'nonexist_{i}')
3916+
except LookupError:
3917+
pass
3918+
3919+
self.assertLessEqual(len(encodings._cache), encodings._MAXCACHE)
3920+
3921+
39113922
if __name__ == "__main__":
39123923
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Optimize ``_ITER_CHECK_RANGE`` and ``_ITER_CHECK_LIST`` in the JIT
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Limit the size of :func:`encodings.search_function` cache.
2+
Found by OSS Fuzz in :oss-fuzz:`493449985`.

Python/optimizer_bytecodes.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,24 @@ dummy_func(void) {
10951095
sym_set_type(iter, &PyTuple_Type);
10961096
}
10971097

1098+
op(_ITER_CHECK_LIST, (iter, null_or_index -- iter, null_or_index)) {
1099+
if (sym_matches_type(iter, &PyList_Type)) {
1100+
ADD_OP(_NOP, 0, 0);
1101+
}
1102+
else {
1103+
sym_set_type(iter, &PyList_Type);
1104+
}
1105+
}
1106+
1107+
op(_ITER_CHECK_RANGE, (iter, null_or_index -- iter, null_or_index)) {
1108+
if (sym_matches_type(iter, &PyRange_Type)) {
1109+
ADD_OP(_NOP, 0, 0);
1110+
}
1111+
else {
1112+
sym_set_type(iter, &PyRange_Type);
1113+
}
1114+
}
1115+
10981116
op(_ITER_NEXT_RANGE, (iter, null_or_index -- iter, null_or_index, next)) {
10991117
next = sym_new_type(ctx, &PyLong_Type);
11001118
}

Python/optimizer_cases.c.h

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)