Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
78be7d2
wip
kumaraditya303 Mar 31, 2026
86aac31
Merge branch 'main' of https://github.com/python/cpython into jit-dic…
kumaraditya303 Apr 5, 2026
2fdf76f
fix tests
kumaraditya303 Apr 5, 2026
0dad4a0
improve tests
kumaraditya303 Apr 5, 2026
c953a69
fix test
kumaraditya303 Apr 5, 2026
959bdfa
Merge branch 'main' into jit-dict-opt
kumaraditya303 Apr 7, 2026
38cd1d3
fix _BINARY_OP_SUBSCR_DICT_KNOWN_HASH
kumaraditya303 Apr 7, 2026
e38a5d3
add more tests
kumaraditya303 Apr 7, 2026
1c6b354
Merge branch 'jit-dict-opt' of https://github.com/kumaraditya303/cpyt…
kumaraditya303 Apr 7, 2026
6feb117
add type assertions
kumaraditya303 Apr 7, 2026
3e88c41
address review
kumaraditya303 Apr 30, 2026
af3dbab
Merge branch 'main' of https://github.com/python/cpython into jit-dic…
kumaraditya303 Apr 30, 2026
61bb5ba
fix conflict
kumaraditya303 Apr 30, 2026
f7e97bd
reduce diff
kumaraditya303 Apr 30, 2026
f2dc858
fix test
kumaraditya303 Apr 30, 2026
17fb6b8
fix formatting
kumaraditya303 Apr 30, 2026
7aa3c6b
remove assertions and incorrect immutable checks
kumaraditya303 Apr 30, 2026
b40e922
remove more leftover assertions
kumaraditya303 Apr 30, 2026
3387bff
add watchers in all cases
kumaraditya303 May 1, 2026
94a7cbb
Merge branch 'main' of https://github.com/python/cpython into jit-dic…
kumaraditya303 May 1, 2026
f116f96
Merge branch 'main' into jit-dict-opt
kumaraditya303 May 1, 2026
d6b9e26
Merge branch 'main' of https://github.com/python/cpython into jit-dic…
kumaraditya303 May 3, 2026
686d630
Merge branch 'jit-dict-opt' of https://github.com/kumaraditya303/cpyt…
kumaraditya303 May 3, 2026
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
4 changes: 4 additions & 0 deletions Include/internal/pycore_dict.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ extern int _PyDict_Next(

extern int _PyDict_HasOnlyStringKeys(PyObject *mp);

PyAPI_FUNC(PyObject *) _PyDict_Subscript(PyObject *self, PyObject *key);
PyAPI_FUNC(PyObject *) _PyDict_SubscriptKnownHash(PyObject *self, PyObject *key, Py_hash_t hash);
PyAPI_FUNC(int) _PyDict_StoreSubscript(PyObject *self, PyObject *key, PyObject *value);

// Export for '_ctypes' shared extension
PyAPI_FUNC(Py_ssize_t) _PyDict_SizeOf(PyDictObject *);

Expand Down
8 changes: 4 additions & 4 deletions Include/internal/pycore_opcode_metadata.h

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

30 changes: 15 additions & 15 deletions Include/internal/pycore_uop_ids.h

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

64 changes: 32 additions & 32 deletions Include/internal/pycore_uop_metadata.h

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

82 changes: 80 additions & 2 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2273,10 +2273,49 @@ def f(n):
self.assertEqual(res, TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertEqual(uops.count("_GUARD_NOS_DICT"), 0)
self.assertEqual(uops.count("_STORE_SUBSCR_DICT_KNOWN_HASH"), 1)
self.assertEqual(uops.count("_GUARD_NOS_DICT_SUBSCRIPT"), 0)
self.assertEqual(uops.count("_GUARD_NOS_DICT_STORE_SUBSCRIPT"), 0)
self.assertEqual(uops.count("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH"), 1)

def test_dict_subclass_subscr(self):
import collections

def f(n):
x = 0
d = collections.defaultdict(int)
for _ in range(n):
d["key"] = 1
x += d["key"]
return x

res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
self.assertEqual(res, TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertEqual(uops.count("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH"), 1)
self.assertEqual(uops.count("_STORE_SUBSCR_DICT_KNOWN_HASH"), 1)
self.assertEqual(uops.count("_GUARD_NOS_DICT_SUBSCRIPT"), 0)
self.assertEqual(uops.count("_GUARD_NOS_DICT_STORE_SUBSCRIPT"), 0)
self.assertEqual(uops.count("_GUARD_TYPE"), 1)

def test_dict_subclass_subscr_with_override(self):
class MyDict(dict):
def __getitem__(self, key):
return 42

def f(n):
d = MyDict()
x = 0
for _ in range(n):
x += d["anything"]
return x

res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
self.assertEqual(res, 42 * TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertEqual(uops.count("_BINARY_OP_SUBSCR_INIT_CALL"), 1)

def test_remove_guard_for_known_type_list(self):
def f(n):
x = 0
Expand Down Expand Up @@ -2599,6 +2638,23 @@ def testfunc(n):
self.assertIn("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH", uops)
self.assertNotIn("_BINARY_OP_SUBSCR_DICT", uops)

def test_binary_op_subscr_defaultdict_known_hash(self):
# str, int, bytes, float, complex, tuple and any python object which has generic hash
import collections

def testfunc(n):
x = 0
d = collections.defaultdict(lambda: 1)
for _ in range(n):
x += d['a'] + d[1] + d[b'b'] + d[(1, 2)] + d[_GENERIC_KEY] + d[1.5] + d[1+2j]
return x

res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertEqual(res, 7 * TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH", uops)
self.assertNotIn("_BINARY_OP_SUBSCR_DICT", uops)

def test_binary_op_subscr_constant_frozendict_known_hash(self):
def testfunc(n):
Expand Down Expand Up @@ -2635,6 +2691,28 @@ def testfunc(n):
self.assertIn("_STORE_SUBSCR_DICT_KNOWN_HASH", uops)
self.assertNotIn("_STORE_SUBSCR_DICT", uops)

def test_store_subscr_defaultdict_known_hash(self):
import collections

def testfunc(n):
d = collections.defaultdict(lambda: 0)
for _ in range(n):
d['a'] += 1
d[1] += 2
d[b'b'] += 3
d[(1, 2)] += 4
d[_GENERIC_KEY] += 5
d[1.5] += 6
d[1+2j] += 7
return d['a'] + d[1] + d[b'b'] + d[(1, 2)] + d[_GENERIC_KEY] + d[1.5] + d[1+2j]

res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertEqual(res, 28 * TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_STORE_SUBSCR_DICT_KNOWN_HASH", uops)
self.assertNotIn("_STORE_SUBSCR_DICT", uops)

def test_contains_op(self):
def testfunc(n):
x = 0
Expand Down
62 changes: 61 additions & 1 deletion Lib/test/test_opcache.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import collections
import copy
import pickle
import dis
Expand Down Expand Up @@ -1863,7 +1864,43 @@ class MyFrozenDict(frozendict):
self.assertEqual(a[2], 3)

binary_subscr_frozen_dict_subclass()
self.assert_no_opcode(binary_subscr_frozen_dict_subclass, "BINARY_OP_SUBSCR_DICT")
self.assert_specialized(binary_subscr_frozen_dict_subclass, "BINARY_OP_SUBSCR_DICT")
self.assert_no_opcode(binary_subscr_frozen_dict_subclass, "BINARY_OP")

def binary_subscr_defaultdict():
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = collections.defaultdict(lambda: 42, {1: 2, 2: 3})
self.assertEqual(a[1], 2)
self.assertEqual(a[2], 3)
self.assertEqual(a[7], 42)

binary_subscr_defaultdict()
self.assert_specialized(binary_subscr_defaultdict, "BINARY_OP_SUBSCR_DICT")
self.assert_no_opcode(binary_subscr_defaultdict, "BINARY_OP")

def binary_subscr_counter():
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = collections.Counter('abcdeabcdabcaba')
self.assertEqual(a['a'], 5)
self.assertEqual(a['b'], 4)
self.assertEqual(a['m'], 0)

binary_subscr_counter()
self.assert_specialized(binary_subscr_counter, "BINARY_OP_SUBSCR_DICT")
self.assert_no_opcode(binary_subscr_counter, "BINARY_OP")

def binary_subscr_dict_subclass_override():
class MyDict(dict):
def __getitem__(self, key):
return 42

for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = MyDict()
self.assertEqual(a['a'], 42)
self.assertEqual(a['b'], 42)

binary_subscr_dict_subclass_override()
self.assert_no_opcode(binary_subscr_dict_subclass_override, "BINARY_OP_SUBSCR_DICT")

def binary_subscr_str_int():
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
Expand Down Expand Up @@ -1924,6 +1961,29 @@ def store_subscr_frozen_dict():
self.assert_specialized(store_subscr_frozen_dict, "STORE_SUBSCR_DICT")
self.assert_no_opcode(store_subscr_frozen_dict, "STORE_SUBSCR")

def store_subscr_defaultdict():
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = collections.defaultdict(int)
a[1] = 4
self.assertEqual(a[1], 4)

store_subscr_defaultdict()
self.assert_specialized(store_subscr_defaultdict, "STORE_SUBSCR_DICT")
self.assert_no_opcode(store_subscr_defaultdict, "STORE_SUBSCR")

def store_subscr_dict_subclass_override():
class MyDict(dict):
def __setitem__(self, key, value):
super().__setitem__(key, value * 2)

for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
a = MyDict()
a['x'] = 5
self.assertEqual(a['x'], 10)

store_subscr_dict_subclass_override()
self.assert_no_opcode(store_subscr_dict_subclass_override, "STORE_SUBSCR_DICT")

@cpython_only
@requires_specialization
def test_compare_op(self):
Expand Down
Loading
Loading