|
1 | 1 | """ Tests for the internal type cache in CPython. """ |
2 | 2 | importunittest |
| 3 | +importdis |
3 | 4 | fromtestimportsupport |
4 | 5 | fromtest.supportimportimport_helper |
5 | 6 | try: |
|
8 | 9 | _clear_type_cache=None |
9 | 10 |
|
10 | 11 | # Skip this test if the _testcapi module isn't available. |
11 | | -type_get_version=import_helper.import_module('_testcapi').type_get_version |
12 | | -type_assign_version=import_helper.import_module('_testcapi').type_assign_version |
| 12 | +_testcapi=import_helper.import_module("_testcapi") |
| 13 | +type_get_version=_testcapi.type_get_version |
| 14 | +type_assign_specific_version_unsafe=_testcapi.type_assign_specific_version_unsafe |
| 15 | +type_assign_version=_testcapi.type_assign_version |
| 16 | +type_modified=_testcapi.type_modified |
13 | 17 |
|
14 | 18 |
|
15 | 19 | @support.cpython_only |
@@ -56,6 +60,183 @@ class C: |
56 | 60 | self.assertNotEqual(type_get_version(C),0) |
57 | 61 | self.assertNotEqual(type_get_version(C),c_ver) |
58 | 62 |
|
| 63 | +deftest_type_assign_specific_version(self): |
| 64 | +"""meta-test for type_assign_specific_version_unsafe""" |
| 65 | +classC: |
| 66 | +pass |
| 67 | + |
| 68 | +type_assign_version(C) |
| 69 | +orig_version=type_get_version(C) |
| 70 | +self.assertNotEqual(orig_version,0) |
| 71 | + |
| 72 | +type_modified(C) |
| 73 | +type_assign_specific_version_unsafe(C,orig_version+5) |
| 74 | +type_assign_version(C)# this should do nothing |
| 75 | + |
| 76 | +new_version=type_get_version(C) |
| 77 | +self.assertEqual(new_version,orig_version+5) |
| 78 | + |
| 79 | +_clear_type_cache() |
| 80 | + |
| 81 | + |
| 82 | +@support.cpython_only |
| 83 | +classTypeCacheWithSpecializationTests(unittest.TestCase): |
| 84 | +deftearDown(self): |
| 85 | +_clear_type_cache() |
| 86 | + |
| 87 | +def_assign_and_check_valid_version(self,user_type): |
| 88 | +type_modified(user_type) |
| 89 | +type_assign_version(user_type) |
| 90 | +self.assertNotEqual(type_get_version(user_type),0) |
| 91 | + |
| 92 | +def_assign_and_check_version_0(self,user_type): |
| 93 | +type_modified(user_type) |
| 94 | +type_assign_specific_version_unsafe(user_type,0) |
| 95 | +self.assertEqual(type_get_version(user_type),0) |
| 96 | + |
| 97 | +def_all_opnames(self,func): |
| 98 | +returnset(instr.opnameforinstrindis.Bytecode(func,adaptive=True)) |
| 99 | + |
| 100 | +def_check_specialization(self,func,arg,opname,*,should_specialize): |
| 101 | +self.assertIn(opname,self._all_opnames(func)) |
| 102 | + |
| 103 | +for_inrange(100): |
| 104 | +func(arg) |
| 105 | + |
| 106 | +ifshould_specialize: |
| 107 | +self.assertNotIn(opname,self._all_opnames(func)) |
| 108 | +else: |
| 109 | +self.assertIn(opname,self._all_opnames(func)) |
| 110 | + |
| 111 | +deftest_class_load_attr_specialization_user_type(self): |
| 112 | +classA: |
| 113 | +deffoo(self): |
| 114 | +pass |
| 115 | + |
| 116 | +self._assign_and_check_valid_version(A) |
| 117 | + |
| 118 | +defload_foo_1(type_): |
| 119 | +type_.foo |
| 120 | + |
| 121 | +self._check_specialization(load_foo_1,A,"LOAD_ATTR",should_specialize=True) |
| 122 | +delload_foo_1 |
| 123 | + |
| 124 | +self._assign_and_check_version_0(A) |
| 125 | + |
| 126 | +defload_foo_2(type_): |
| 127 | +returntype_.foo |
| 128 | + |
| 129 | +self._check_specialization(load_foo_2,A,"LOAD_ATTR",should_specialize=False) |
| 130 | + |
| 131 | +deftest_class_load_attr_specialization_static_type(self): |
| 132 | +self._assign_and_check_valid_version(str) |
| 133 | +self._assign_and_check_valid_version(bytes) |
| 134 | + |
| 135 | +defget_capitalize_1(type_): |
| 136 | +returntype_.capitalize |
| 137 | + |
| 138 | +self._check_specialization(get_capitalize_1,str,"LOAD_ATTR",should_specialize=True) |
| 139 | +self.assertEqual(get_capitalize_1(str)('hello'),'Hello') |
| 140 | +self.assertEqual(get_capitalize_1(bytes)(b'hello'),b'Hello') |
| 141 | +delget_capitalize_1 |
| 142 | + |
| 143 | +# Permanently overflow the static type version counter, and force str and bytes |
| 144 | +# to have tp_version_tag == 0 |
| 145 | +for_inrange(2**16): |
| 146 | +type_modified(str) |
| 147 | +type_assign_version(str) |
| 148 | +type_modified(bytes) |
| 149 | +type_assign_version(bytes) |
| 150 | + |
| 151 | +self.assertEqual(type_get_version(str),0) |
| 152 | +self.assertEqual(type_get_version(bytes),0) |
| 153 | + |
| 154 | +defget_capitalize_2(type_): |
| 155 | +returntype_.capitalize |
| 156 | + |
| 157 | +self._check_specialization(get_capitalize_2,str,"LOAD_ATTR",should_specialize=False) |
| 158 | +self.assertEqual(get_capitalize_2(str)('hello'),'Hello') |
| 159 | +self.assertEqual(get_capitalize_2(bytes)(b'hello'),b'Hello') |
| 160 | + |
| 161 | +deftest_property_load_attr_specialization_user_type(self): |
| 162 | +classG: |
| 163 | +@property |
| 164 | +defx(self): |
| 165 | +return9 |
| 166 | + |
| 167 | +self._assign_and_check_valid_version(G) |
| 168 | + |
| 169 | +defload_x_1(instance): |
| 170 | +instance.x |
| 171 | + |
| 172 | +self._check_specialization(load_x_1,G(),"LOAD_ATTR",should_specialize=True) |
| 173 | +delload_x_1 |
| 174 | + |
| 175 | +self._assign_and_check_version_0(G) |
| 176 | + |
| 177 | +defload_x_2(instance): |
| 178 | +instance.x |
| 179 | + |
| 180 | +self._check_specialization(load_x_2,G(),"LOAD_ATTR",should_specialize=False) |
| 181 | + |
| 182 | +deftest_store_attr_specialization_user_type(self): |
| 183 | +classB: |
| 184 | +__slots__= ("bar",) |
| 185 | + |
| 186 | +self._assign_and_check_valid_version(B) |
| 187 | + |
| 188 | +defstore_bar_1(type_): |
| 189 | +type_.bar=10 |
| 190 | + |
| 191 | +self._check_specialization(store_bar_1,B(),"STORE_ATTR",should_specialize=True) |
| 192 | +delstore_bar_1 |
| 193 | + |
| 194 | +self._assign_and_check_version_0(B) |
| 195 | + |
| 196 | +defstore_bar_2(type_): |
| 197 | +type_.bar=10 |
| 198 | + |
| 199 | +self._check_specialization(store_bar_2,B(),"STORE_ATTR",should_specialize=False) |
| 200 | + |
| 201 | +deftest_class_call_specialization_user_type(self): |
| 202 | +classF: |
| 203 | +def__init__(self): |
| 204 | +pass |
| 205 | + |
| 206 | +self._assign_and_check_valid_version(F) |
| 207 | + |
| 208 | +defcall_class_1(type_): |
| 209 | +type_() |
| 210 | + |
| 211 | +self._check_specialization(call_class_1,F,"CALL",should_specialize=True) |
| 212 | +delcall_class_1 |
| 213 | + |
| 214 | +self._assign_and_check_version_0(F) |
| 215 | + |
| 216 | +defcall_class_2(type_): |
| 217 | +type_() |
| 218 | + |
| 219 | +self._check_specialization(call_class_2,F,"CALL",should_specialize=False) |
| 220 | + |
| 221 | +deftest_to_bool_specialization_user_type(self): |
| 222 | +classH: |
| 223 | +pass |
| 224 | + |
| 225 | +self._assign_and_check_valid_version(H) |
| 226 | + |
| 227 | +defto_bool_1(instance): |
| 228 | +notinstance |
| 229 | + |
| 230 | +self._check_specialization(to_bool_1,H(),"TO_BOOL",should_specialize=True) |
| 231 | +delto_bool_1 |
| 232 | + |
| 233 | +self._assign_and_check_version_0(H) |
| 234 | + |
| 235 | +defto_bool_2(instance): |
| 236 | +notinstance |
| 237 | + |
| 238 | +self._check_specialization(to_bool_2,H(),"TO_BOOL",should_specialize=False) |
| 239 | + |
59 | 240 |
|
60 | 241 | if__name__=="__main__": |
61 | 242 | unittest.main() |