Skip to content

Commit 30f894f

Browse files
authored
Merge branch 'main' into Optimize_SET_UPDATE
2 parents bc5ac8a + 1efd993 commit 30f894f

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
@@ -3981,6 +3981,22 @@ def testfunc(n):
39813981
self.assertIn("_POP_TOP_NOP", uops)
39823982
self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2)
39833983

3984+
def test_iter_check_list(self):
3985+
def testfunc(n):
3986+
x = 0
3987+
for _ in range(n):
3988+
l = [1]
3989+
for num in l: # unguarded
3990+
x += num
3991+
return x
3992+
3993+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
3994+
self.assertEqual(res, TIER2_THRESHOLD)
3995+
uops = get_opnames(ex)
3996+
3997+
self.assertIn("_BUILD_LIST", uops)
3998+
self.assertNotIn("_ITER_CHECK_LIST", uops)
3999+
39844000
def test_match_class(self):
39854001
def testfunc(n):
39864002
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
@@ -1091,6 +1091,24 @@ dummy_func(void) {
10911091
sym_set_type(iter, &PyTuple_Type);
10921092
}
10931093

1094+
op(_ITER_CHECK_LIST, (iter, null_or_index -- iter, null_or_index)) {
1095+
if (sym_matches_type(iter, &PyList_Type)) {
1096+
ADD_OP(_NOP, 0, 0);
1097+
}
1098+
else {
1099+
sym_set_type(iter, &PyList_Type);
1100+
}
1101+
}
1102+
1103+
op(_ITER_CHECK_RANGE, (iter, null_or_index -- iter, null_or_index)) {
1104+
if (sym_matches_type(iter, &PyRange_Type)) {
1105+
ADD_OP(_NOP, 0, 0);
1106+
}
1107+
else {
1108+
sym_set_type(iter, &PyRange_Type);
1109+
}
1110+
}
1111+
10941112
op(_ITER_NEXT_RANGE, (iter, null_or_index -- iter, null_or_index, next)) {
10951113
next = sym_new_type(ctx, &PyLong_Type);
10961114
}

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)