5
5
6
6
#include "pycore_code.h" // _PyCodeConstructor
7
7
#include "pycore_frame.h" // FRAME_SPECIALS_SIZE
8
+ #include "pycore_hashtable.h" // _Py_hashtable_t
9
+ #include "pycore_initconfig.h" // _PyStatus_OK()
8
10
#include "pycore_interp.h" // PyInterpreterState.co_extra_freefuncs
9
11
#include "pycore_object.h" // _PyObject_SetDeferredRefcount
10
12
#include "pycore_opcode_metadata.h" // _PyOpcode_Deopt, _PyOpcode_Caches
@@ -118,6 +120,10 @@ all_name_chars(PyObject *o)
118
120
return 1 ;
119
121
}
120
122
123
+ #ifdef Py_GIL_DISABLED
124
+ static PyObject * intern_one_constant (PyObject * op );
125
+ #endif
126
+
121
127
static int
122
128
intern_strings (PyObject * tuple )
123
129
{
@@ -135,9 +141,11 @@ intern_strings(PyObject *tuple)
135
141
return 0 ;
136
142
}
137
143
138
- /* Intern selected string constants */
144
+ /* Intern constants. In the default build, this interns selected string
145
+ constants. In the free-threaded build, this also interns non-string
146
+ constants. */
139
147
static int
140
- intern_string_constants (PyObject * tuple , int * modified )
148
+ intern_constants (PyObject * tuple , int * modified )
141
149
{
142
150
for (Py_ssize_t i = PyTuple_GET_SIZE (tuple ); -- i >= 0 ; ) {
143
151
PyObject * v = PyTuple_GET_ITEM (tuple , i );
@@ -154,7 +162,7 @@ intern_string_constants(PyObject *tuple, int *modified)
154
162
}
155
163
}
156
164
else if (PyTuple_CheckExact (v )) {
157
- if (intern_string_constants (v , NULL ) < 0 ) {
165
+ if (intern_constants (v , NULL ) < 0 ) {
158
166
return -1 ;
159
167
}
160
168
}
@@ -165,7 +173,7 @@ intern_string_constants(PyObject *tuple, int *modified)
165
173
return -1 ;
166
174
}
167
175
int tmp_modified = 0 ;
168
- if (intern_string_constants (tmp , & tmp_modified ) < 0 ) {
176
+ if (intern_constants (tmp , & tmp_modified ) < 0 ) {
169
177
Py_DECREF (tmp );
170
178
return -1 ;
171
179
}
@@ -184,6 +192,28 @@ intern_string_constants(PyObject *tuple, int *modified)
184
192
}
185
193
Py_DECREF (tmp );
186
194
}
195
+ #ifdef Py_GIL_DISABLED
196
+ // Intern non-string consants in the free-threaded build, but only if
197
+ // we are also immortalizing objects that use deferred reference
198
+ // counting.
199
+ PyThreadState * tstate = PyThreadState_GET ();
200
+ if (!_Py_IsImmortal (v ) && !PyCode_Check (v ) &&
201
+ !PyUnicode_CheckExact (v ) &&
202
+ tstate -> interp -> gc .immortalize .enable_on_thread_created )
203
+ {
204
+ PyObject * interned = intern_one_constant (v );
205
+ if (interned == NULL ) {
206
+ return -1 ;
207
+ }
208
+ else if (interned != v ) {
209
+ PyTuple_SET_ITEM (tuple , i , interned );
210
+ Py_SETREF (v , interned );
211
+ if (modified ) {
212
+ * modified = 1 ;
213
+ }
214
+ }
215
+ }
216
+ #endif
187
217
}
188
218
return 0 ;
189
219
}
@@ -542,18 +572,41 @@ remove_column_info(PyObject *locations)
542
572
return res ;
543
573
}
544
574
545
- /* The caller is responsible for ensuring that the given data is valid. */
546
-
547
- PyCodeObject *
548
- _PyCode_New (struct _PyCodeConstructor * con )
575
+ static int
576
+ intern_code_constants (struct _PyCodeConstructor * con )
549
577
{
578
+ #ifdef Py_GIL_DISABLED
579
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
580
+ struct _py_code_state * state = & interp -> code_state ;
581
+ PyMutex_Lock (& state -> mutex );
582
+ #endif
550
583
if (intern_strings (con -> names ) < 0 ) {
551
- return NULL ;
584
+ goto error ;
552
585
}
553
- if (intern_string_constants (con -> consts , NULL ) < 0 ) {
554
- return NULL ;
586
+ if (intern_constants (con -> consts , NULL ) < 0 ) {
587
+ goto error ;
555
588
}
556
589
if (intern_strings (con -> localsplusnames ) < 0 ) {
590
+ goto error ;
591
+ }
592
+ #ifdef Py_GIL_DISABLED
593
+ PyMutex_Unlock (& state -> mutex );
594
+ #endif
595
+ return 0 ;
596
+
597
+ error :
598
+ #ifdef Py_GIL_DISABLED
599
+ PyMutex_Unlock (& state -> mutex );
600
+ #endif
601
+ return -1 ;
602
+ }
603
+
604
+ /* The caller is responsible for ensuring that the given data is valid. */
605
+
606
+ PyCodeObject *
607
+ _PyCode_New (struct _PyCodeConstructor * con )
608
+ {
609
+ if (intern_code_constants (con ) < 0 ) {
557
610
return NULL ;
558
611
}
559
612
@@ -2399,3 +2452,183 @@ _PyCode_ConstantKey(PyObject *op)
2399
2452
}
2400
2453
return key ;
2401
2454
}
2455
+
2456
+ #ifdef Py_GIL_DISABLED
2457
+ static PyObject *
2458
+ intern_one_constant (PyObject * op )
2459
+ {
2460
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
2461
+ _Py_hashtable_t * consts = interp -> code_state .constants ;
2462
+
2463
+ assert (!PyUnicode_CheckExact (op )); // strings are interned separately
2464
+
2465
+ _Py_hashtable_entry_t * entry = _Py_hashtable_get_entry (consts , op );
2466
+ if (entry == NULL ) {
2467
+ if (_Py_hashtable_set (consts , op , op ) != 0 ) {
2468
+ return NULL ;
2469
+ }
2470
+
2471
+ #ifdef Py_REF_DEBUG
2472
+ Py_ssize_t refcnt = Py_REFCNT (op );
2473
+ if (refcnt != 1 ) {
2474
+ // Adjust the reftotal to account for the fact that we only
2475
+ // restore a single reference in _PyCode_Fini.
2476
+ _Py_AddRefTotal (_PyThreadState_GET (), - (refcnt - 1 ));
2477
+ }
2478
+ #endif
2479
+
2480
+ _Py_SetImmortal (op );
2481
+ return op ;
2482
+ }
2483
+
2484
+ assert (_Py_IsImmortal (entry -> value ));
2485
+ return (PyObject * )entry -> value ;
2486
+ }
2487
+
2488
+ static int
2489
+ compare_constants (const void * key1 , const void * key2 ) {
2490
+ PyObject * op1 = (PyObject * )key1 ;
2491
+ PyObject * op2 = (PyObject * )key2 ;
2492
+ if (op1 == op2 ) {
2493
+ return 1 ;
2494
+ }
2495
+ if (Py_TYPE (op1 ) != Py_TYPE (op2 )) {
2496
+ return 0 ;
2497
+ }
2498
+ // We compare container contents by identity because we have already
2499
+ // internalized the items.
2500
+ if (PyTuple_CheckExact (op1 )) {
2501
+ Py_ssize_t size = PyTuple_GET_SIZE (op1 );
2502
+ if (size != PyTuple_GET_SIZE (op2 )) {
2503
+ return 0 ;
2504
+ }
2505
+ for (Py_ssize_t i = 0 ; i < size ; i ++ ) {
2506
+ if (PyTuple_GET_ITEM (op1 , i ) != PyTuple_GET_ITEM (op2 , i )) {
2507
+ return 0 ;
2508
+ }
2509
+ }
2510
+ return 1 ;
2511
+ }
2512
+ else if (PyFrozenSet_CheckExact (op1 )) {
2513
+ if (PySet_GET_SIZE (op1 ) != PySet_GET_SIZE (op2 )) {
2514
+ return 0 ;
2515
+ }
2516
+ Py_ssize_t pos1 = 0 , pos2 = 0 ;
2517
+ PyObject * obj1 , * obj2 ;
2518
+ Py_hash_t hash1 , hash2 ;
2519
+ while ((_PySet_NextEntry (op1 , & pos1 , & obj1 , & hash1 )) &&
2520
+ (_PySet_NextEntry (op2 , & pos2 , & obj2 , & hash2 )))
2521
+ {
2522
+ if (obj1 != obj2 ) {
2523
+ return 0 ;
2524
+ }
2525
+ }
2526
+ return 1 ;
2527
+ }
2528
+ else if (PySlice_Check (op1 )) {
2529
+ PySliceObject * s1 = (PySliceObject * )op1 ;
2530
+ PySliceObject * s2 = (PySliceObject * )op2 ;
2531
+ return (s1 -> start == s2 -> start &&
2532
+ s1 -> stop == s2 -> stop &&
2533
+ s1 -> step == s2 -> step );
2534
+ }
2535
+ else if (PyBytes_CheckExact (op1 ) || PyLong_CheckExact (op1 )) {
2536
+ return PyObject_RichCompareBool (op1 , op2 , Py_EQ );
2537
+ }
2538
+ else if (PyFloat_CheckExact (op1 )) {
2539
+ // Ensure that, for example, +0.0 and -0.0 are distinct
2540
+ double f1 = PyFloat_AS_DOUBLE (op1 );
2541
+ double f2 = PyFloat_AS_DOUBLE (op2 );
2542
+ return memcmp (& f1 , & f2 , sizeof (double )) == 0 ;
2543
+ }
2544
+ else if (PyComplex_CheckExact (op1 )) {
2545
+ Py_complex c1 = ((PyComplexObject * )op1 )-> cval ;
2546
+ Py_complex c2 = ((PyComplexObject * )op2 )-> cval ;
2547
+ return memcmp (& c1 , & c2 , sizeof (Py_complex )) == 0 ;
2548
+ }
2549
+ _Py_FatalErrorFormat ("unexpected type in compare_constants: %s" ,
2550
+ Py_TYPE (op1 )-> tp_name );
2551
+ return 0 ;
2552
+ }
2553
+
2554
+ static Py_uhash_t
2555
+ hash_const (const void * key )
2556
+ {
2557
+ PyObject * op = (PyObject * )key ;
2558
+ if (PySlice_Check (op )) {
2559
+ PySliceObject * s = (PySliceObject * )op ;
2560
+ PyObject * data [3 ] = { s -> start , s -> stop , s -> step };
2561
+ return _Py_HashBytes (& data , sizeof (data ));
2562
+ }
2563
+ else if (PyTuple_CheckExact (op )) {
2564
+ Py_ssize_t size = PyTuple_GET_SIZE (op );
2565
+ PyObject * * data = _PyTuple_ITEMS (op );
2566
+ return _Py_HashBytes (data , sizeof (PyObject * ) * size );
2567
+ }
2568
+ Py_hash_t h = PyObject_Hash (op );
2569
+ if (h == -1 ) {
2570
+ // This should never happen: all the constants we support have
2571
+ // infallible hash functions.
2572
+ Py_FatalError ("code: hash failed" );
2573
+ }
2574
+ return (Py_uhash_t )h ;
2575
+ }
2576
+
2577
+ static int
2578
+ clear_containers (_Py_hashtable_t * ht , const void * key , const void * value ,
2579
+ void * user_data )
2580
+ {
2581
+ // First clear containers to avoid recursive deallocation later on in
2582
+ // destroy_key.
2583
+ PyObject * op = (PyObject * )key ;
2584
+ if (PyTuple_CheckExact (op )) {
2585
+ for (Py_ssize_t i = 0 ; i < PyTuple_GET_SIZE (op ); i ++ ) {
2586
+ Py_CLEAR (_PyTuple_ITEMS (op )[i ]);
2587
+ }
2588
+ }
2589
+ else if (PySlice_Check (op )) {
2590
+ PySliceObject * slice = (PySliceObject * )op ;
2591
+ Py_SETREF (slice -> start , Py_None );
2592
+ Py_SETREF (slice -> stop , Py_None );
2593
+ Py_SETREF (slice -> step , Py_None );
2594
+ }
2595
+ else if (PyFrozenSet_CheckExact (op )) {
2596
+ _PySet_ClearInternal ((PySetObject * )op );
2597
+ }
2598
+ return 0 ;
2599
+ }
2600
+
2601
+ static void
2602
+ destroy_key (void * key )
2603
+ {
2604
+ _Py_ClearImmortal (key );
2605
+ }
2606
+ #endif
2607
+
2608
+ PyStatus
2609
+ _PyCode_Init (PyInterpreterState * interp )
2610
+ {
2611
+ #ifdef Py_GIL_DISABLED
2612
+ struct _py_code_state * state = & interp -> code_state ;
2613
+ state -> constants = _Py_hashtable_new_full (& hash_const , & compare_constants ,
2614
+ & destroy_key , NULL , NULL );
2615
+ if (state -> constants == NULL ) {
2616
+ return _PyStatus_NO_MEMORY ();
2617
+ }
2618
+ #endif
2619
+ return _PyStatus_OK ();
2620
+ }
2621
+
2622
+ void
2623
+ _PyCode_Fini (PyInterpreterState * interp )
2624
+ {
2625
+ #ifdef Py_GIL_DISABLED
2626
+ // Free interned constants
2627
+ struct _py_code_state * state = & interp -> code_state ;
2628
+ if (state -> constants ) {
2629
+ _Py_hashtable_foreach (state -> constants , & clear_containers , NULL );
2630
+ _Py_hashtable_destroy (state -> constants );
2631
+ state -> constants = NULL ;
2632
+ }
2633
+ #endif
2634
+ }
0 commit comments