@@ -285,110 +285,56 @@ PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void);
285
285
#define EVAL_CALL_STAT_INC_IF_FUNCTION (name , callable ) ((void)0)
286
286
#endif // !Py_STATS
287
287
288
- // Cache values are only valid in memory, so use native endianness.
289
- #ifdef WORDS_BIGENDIAN
288
+ // NOTE: These cache reading/writing utilities use memcpy to avoid voilating C's
289
+ // strict aliasing rules, while also avoiding the need to maintain big-endian
290
+ // versions of the same code. Compilers are smart enough to understand what
291
+ // we're really trying to do here (see https://blog.regehr.org/archives/959).
292
+
293
+ // When modifying these, great care must be taken to ensure that we don't break
294
+ // or slow down our inline caching! All of these functions should compile to
295
+ // simple "move" instructions on all supported compilers and platforms. You can
296
+ // use the Compiler Explorer at https://godbolt.org to help verify this.
290
297
291
298
static inline void
292
299
write_u32 (uint16_t * p , uint32_t val )
293
300
{
294
- p [0 ] = (uint16_t )(val >> 16 );
295
- p [1 ] = (uint16_t )(val >> 0 );
301
+ memcpy (p , & val , sizeof (val ));
296
302
}
297
303
298
304
static inline void
299
305
write_u64 (uint16_t * p , uint64_t val )
300
306
{
301
- p [0 ] = (uint16_t )(val >> 48 );
302
- p [1 ] = (uint16_t )(val >> 32 );
303
- p [2 ] = (uint16_t )(val >> 16 );
304
- p [3 ] = (uint16_t )(val >> 0 );
305
- }
306
-
307
- static inline uint32_t
308
- read_u32 (uint16_t * p )
309
- {
310
- uint32_t val = 0 ;
311
- val |= (uint32_t )p [0 ] << 16 ;
312
- val |= (uint32_t )p [1 ] << 0 ;
313
- return val ;
314
- }
315
-
316
- static inline uint64_t
317
- read_u64 (uint16_t * p )
318
- {
319
- uint64_t val = 0 ;
320
- val |= (uint64_t )p [0 ] << 48 ;
321
- val |= (uint64_t )p [1 ] << 32 ;
322
- val |= (uint64_t )p [2 ] << 16 ;
323
- val |= (uint64_t )p [3 ] << 0 ;
324
- return val ;
325
- }
326
-
327
- #else
328
-
329
- static inline void
330
- write_u32 (uint16_t * p , uint32_t val )
331
- {
332
- p [0 ] = (uint16_t )(val >> 0 );
333
- p [1 ] = (uint16_t )(val >> 16 );
307
+ memcpy (p , & val , sizeof (val ));
334
308
}
335
309
336
310
static inline void
337
- write_u64 (uint16_t * p , uint64_t val )
311
+ write_obj (uint16_t * p , PyObject * val )
338
312
{
339
- p [0 ] = (uint16_t )(val >> 0 );
340
- p [1 ] = (uint16_t )(val >> 16 );
341
- p [2 ] = (uint16_t )(val >> 32 );
342
- p [3 ] = (uint16_t )(val >> 48 );
313
+ memcpy (p , & val , sizeof (val ));
343
314
}
344
315
345
316
static inline uint32_t
346
317
read_u32 (uint16_t * p )
347
318
{
348
- uint32_t val = 0 ;
349
- val |= (uint32_t )p [0 ] << 0 ;
350
- val |= (uint32_t )p [1 ] << 16 ;
319
+ uint32_t val ;
320
+ memcpy (& val , p , sizeof (val ));
351
321
return val ;
352
322
}
353
323
354
324
static inline uint64_t
355
325
read_u64 (uint16_t * p )
356
326
{
357
- uint64_t val = 0 ;
358
- val |= (uint64_t )p [0 ] << 0 ;
359
- val |= (uint64_t )p [1 ] << 16 ;
360
- val |= (uint64_t )p [2 ] << 32 ;
361
- val |= (uint64_t )p [3 ] << 48 ;
327
+ uint64_t val ;
328
+ memcpy (& val , p , sizeof (val ));
362
329
return val ;
363
330
}
364
331
365
- #endif
366
-
367
- static inline void
368
- write_obj (uint16_t * p , PyObject * obj )
369
- {
370
- uintptr_t val = (uintptr_t )obj ;
371
- #if SIZEOF_VOID_P == 8
372
- write_u64 (p , val );
373
- #elif SIZEOF_VOID_P == 4
374
- write_u32 (p , val );
375
- #else
376
- #error "SIZEOF_VOID_P must be 4 or 8"
377
- #endif
378
- }
379
-
380
332
static inline PyObject *
381
333
read_obj (uint16_t * p )
382
334
{
383
- uintptr_t val ;
384
- #if SIZEOF_VOID_P == 8
385
- val = read_u64 (p );
386
- #elif SIZEOF_VOID_P == 4
387
- val = read_u32 (p );
388
- #else
389
- #error "SIZEOF_VOID_P must be 4 or 8"
390
- #endif
391
- return (PyObject * )val ;
335
+ PyObject * val ;
336
+ memcpy (& val , p , sizeof (val ));
337
+ return val ;
392
338
}
393
339
394
340
/* See Objects/exception_handling_notes.txt for details.
0 commit comments