[Python-checkins] bpo-40302: Add pycore_byteswap.h header file (GH-19552)

Victor Stinner webhook-mailer at python.org
Fri Apr 17 11:47:28 EDT 2020


https://github.com/python/cpython/commit/1ae035b7e847064d09df01ca62b8a761e9b5aae3
commit: 1ae035b7e847064d09df01ca62b8a761e9b5aae3
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-04-17T17:47:20+02:00
summary:

bpo-40302: Add pycore_byteswap.h header file (GH-19552)

Add a new internal pycore_byteswap.h header file with the following
functions:

* _Py_bswap16()
* _Py_bswap32()
* _Py_bswap64()

Use these functions in _ctypes, sha256 and sha512 modules,
and also use in the UTF-32 encoder.

sha256, sha512 and _ctypes modules are now built with the internal
C API.

files:
A Include/internal/pycore_byteswap.h
M Include/pyport.h
M Lib/test/test_capi.py
M Makefile.pre.in
M Modules/Setup
M Modules/_ctypes/cfield.c
M Modules/_testinternalcapi.c
M Modules/sha256module.c
M Modules/sha512module.c
M Objects/stringlib/codecs.h
M PCbuild/pythoncore.vcxproj
M PCbuild/pythoncore.vcxproj.filters
M setup.py

diff --git a/Include/internal/pycore_byteswap.h b/Include/internal/pycore_byteswap.h
new file mode 100644
index 0000000000000..5e64704a004c8
--- /dev/null
+++ b/Include/internal/pycore_byteswap.h
@@ -0,0 +1,89 @@
+/* Bytes swap functions, reverse order of bytes:
+
+   - _Py_bswap16(uint16_t)
+   - _Py_bswap32(uint32_t)
+   - _Py_bswap64(uint64_t)
+*/
+
+#ifndef Py_INTERNAL_BSWAP_H
+#define Py_INTERNAL_BSWAP_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+#  error "this header requires Py_BUILD_CORE define"
+#endif
+
+#if defined(__clang__) || \
+    (defined(__GNUC__) && \
+     ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)))
+   /* __builtin_bswap16() is available since GCC 4.8,
+      __builtin_bswap32() is available since GCC 4.3,
+      __builtin_bswap64() is available since GCC 4.3. */
+#  define _PY_HAVE_BUILTIN_BSWAP
+#endif
+
+#ifdef _MSC_VER
+   /* Get _byteswap_ushort(), _byteswap_ulong(), _byteswap_uint64() */
+#  include <intrin.h>
+#endif
+
+static inline uint16_t
+_Py_bswap16(uint16_t word)
+{
+#ifdef _PY_HAVE_BUILTIN_BSWAP
+    return __builtin_bswap16(word);
+#elif defined(_MSC_VER)
+    Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned short));
+    return _byteswap_ushort(word);
+#else
+    // Portable implementation which doesn't rely on circular bit shift
+    return ( ((word & UINT16_C(0x00FF)) << 8)
+           | ((word & UINT16_C(0xFF00)) >> 8));
+#endif
+}
+
+static inline uint32_t
+_Py_bswap32(uint32_t word)
+{
+#ifdef _PY_HAVE_BUILTIN_BSWAP
+    return __builtin_bswap32(word);
+#elif defined(_MSC_VER)
+    Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned long));
+    return _byteswap_ulong(word);
+#else
+    // Portable implementation which doesn't rely on circular bit shift
+    return ( ((word & UINT32_C(0x000000FF)) << 24)
+           | ((word & UINT32_C(0x0000FF00)) <<  8)
+           | ((word & UINT32_C(0x00FF0000)) >>  8)
+           | ((word & UINT32_C(0xFF000000)) >> 24));
+#endif
+}
+
+static inline uint64_t
+_Py_bswap64(uint64_t word)
+{
+#ifdef _PY_HAVE_BUILTIN_BSWAP
+    return __builtin_bswap64(word);
+#elif defined(_MSC_VER)
+    return _byteswap_uint64(word);
+#else
+    // Portable implementation which doesn't rely on circular bit shift
+    return ( ((word & UINT64_C(0x00000000000000FF)) << 56)
+           | ((word & UINT64_C(0x000000000000FF00)) << 40)
+           | ((word & UINT64_C(0x0000000000FF0000)) << 24)
+           | ((word & UINT64_C(0x00000000FF000000)) <<  8)
+           | ((word & UINT64_C(0x000000FF00000000)) >>  8)
+           | ((word & UINT64_C(0x0000FF0000000000)) >> 24)
+           | ((word & UINT64_C(0x00FF000000000000)) >> 40)
+           | ((word & UINT64_C(0xFF00000000000000)) >> 56));
+#endif
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_BSWAP_H */
+
diff --git a/Include/pyport.h b/Include/pyport.h
index 72e74e046a5ee..63d3b81de5d23 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -768,11 +768,11 @@ extern char * _getpty(int *, int, mode_t, int);
  */
 
 #ifdef WORDS_BIGENDIAN
-#define PY_BIG_ENDIAN 1
-#define PY_LITTLE_ENDIAN 0
+#  define PY_BIG_ENDIAN 1
+#  define PY_LITTLE_ENDIAN 0
 #else
-#define PY_BIG_ENDIAN 0
-#define PY_LITTLE_ENDIAN 1
+#  define PY_BIG_ENDIAN 0
+#  define PY_LITTLE_ENDIAN 1
 #endif
 
 #ifdef Py_BUILD_CORE
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 024343963b605..f9578d3afa81f 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -24,6 +24,8 @@
 # Skip this test if the _testcapi module isn't available.
 _testcapi = support.import_module('_testcapi')
 
+import _testinternalcapi
+
 # Were we compiled --with-pydebug or with #define Py_DEBUG?
 Py_DEBUG = hasattr(sys, 'gettotalrefcount')
 
@@ -658,6 +660,12 @@ class Test_testcapi(unittest.TestCase):
                     if name.startswith('test_') and not name.endswith('_code'))
 
 
+class Test_testinternalcapi(unittest.TestCase):
+    locals().update((name, getattr(_testinternalcapi, name))
+                    for name in dir(_testinternalcapi)
+                    if name.startswith('test_'))
+
+
 class PyMemDebugTests(unittest.TestCase):
     PYTHONMALLOC = 'debug'
     # '0x04c06e0' or '04C06E0'
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 6b265226c4966..4511e607d89aa 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1083,6 +1083,7 @@ PYTHON_HEADERS= \
 		$(srcdir)/Include/internal/pycore_abstract.h \
 		$(srcdir)/Include/internal/pycore_accu.h \
 		$(srcdir)/Include/internal/pycore_atomic.h \
+		$(srcdir)/Include/internal/pycore_byteswap.h \
 		$(srcdir)/Include/internal/pycore_bytes_methods.h \
 		$(srcdir)/Include/internal/pycore_call.h \
 		$(srcdir)/Include/internal/pycore_ceval.h \
diff --git a/Modules/Setup b/Modules/Setup
index 40266a192bc5e..9dcca13100078 100644
--- a/Modules/Setup
+++ b/Modules/Setup
@@ -247,8 +247,8 @@ _symtable symtablemodule.c
 # The _sha module implements the SHA checksum algorithms.
 # (NIST's Secure Hash Algorithms.)
 #_sha1 sha1module.c
-#_sha256 sha256module.c
-#_sha512 sha512module.c
+#_sha256 sha256module.c -DPy_BUILD_CORE_BUILTIN
+#_sha512 sha512module.c -DPy_BUILD_CORE_BUILTIN
 #_sha3 _sha3/sha3module.c
 
 # _blake module
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 2060d15a64de5..a72682d7292ca 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -1,4 +1,5 @@
 #include "Python.h"
+#include "pycore_byteswap.h"      // _Py_bswap32()
 
 #include <ffi.h>
 #ifdef MS_WIN32
@@ -448,46 +449,32 @@ get_ulonglong(PyObject *v, unsigned long long *p)
      ( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \
      : (type)v)
 
-/* byte swapping macros */
-#define SWAP_2(v)                               \
-    ( ( (v >> 8) & 0x00FF) |                    \
-      ( (v << 8) & 0xFF00) )
-
-#define SWAP_4(v)                       \
-    ( ( (v & 0x000000FF) << 24 ) |  \
-      ( (v & 0x0000FF00) <<  8 ) |  \
-      ( (v & 0x00FF0000) >>  8 ) |  \
-      ( ((v >> 24) & 0xFF)) )
-
-#ifdef _MSC_VER
-#define SWAP_8(v)                               \
-    ( ( (v & 0x00000000000000FFL) << 56 ) |  \
-      ( (v & 0x000000000000FF00L) << 40 ) |  \
-      ( (v & 0x0000000000FF0000L) << 24 ) |  \
-      ( (v & 0x00000000FF000000L) <<  8 ) |  \
-      ( (v & 0x000000FF00000000L) >>  8 ) |  \
-      ( (v & 0x0000FF0000000000L) >> 24 ) |  \
-      ( (v & 0x00FF000000000000L) >> 40 ) |  \
-      ( ((v >> 56) & 0xFF)) )
+#if SIZEOF_SHORT == 2
+#  define SWAP_SHORT _Py_bswap16
 #else
-#define SWAP_8(v)                               \
-    ( ( (v & 0x00000000000000FFLL) << 56 ) |  \
-      ( (v & 0x000000000000FF00LL) << 40 ) |  \
-      ( (v & 0x0000000000FF0000LL) << 24 ) |  \
-      ( (v & 0x00000000FF000000LL) <<  8 ) |  \
-      ( (v & 0x000000FF00000000LL) >>  8 ) |  \
-      ( (v & 0x0000FF0000000000LL) >> 24 ) |  \
-      ( (v & 0x00FF000000000000LL) >> 40 ) |  \
-      ( ((v >> 56) & 0xFF)) )
+#  error "unsupported short size"
 #endif
 
-#define SWAP_INT SWAP_4
+#if SIZEOF_INT == 4
+#  define SWAP_INT _Py_bswap32
+#else
+#  error "unsupported int size"
+#endif
 
 #if SIZEOF_LONG == 4
-# define SWAP_LONG SWAP_4
+#  define SWAP_LONG _Py_bswap32
 #elif SIZEOF_LONG == 8
-# define SWAP_LONG SWAP_8
+#  define SWAP_LONG _Py_bswap64
+#else
+#  error "unsupported long size"
+#endif
+
+#if SIZEOF_LONG_LONG == 8
+#  define SWAP_LONG_LONG _Py_bswap64
+#else
+#  error "unsupported long long size"
 #endif
+
 /*****************************************************************
  * The setter methods return an object which must be kept alive, to keep the
  * data valid which has been stored in the memory block.  The ctypes object
@@ -569,12 +556,13 @@ h_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
 {
     long val;
     short field;
-    if (get_long(value, &val) < 0)
+    if (get_long(value, &val) < 0) {
         return NULL;
+    }
     memcpy(&field, ptr, sizeof(field));
-    field = SWAP_2(field);
+    field = SWAP_SHORT(field);
     field = SET(short, field, val, size);
-    field = SWAP_2(field);
+    field = SWAP_SHORT(field);
     memcpy(ptr, &field, sizeof(field));
     _RET(value);
 }
@@ -593,7 +581,7 @@ h_get_sw(void *ptr, Py_ssize_t size)
 {
     short val;
     memcpy(&val, ptr, sizeof(val));
-    val = SWAP_2(val);
+    val = SWAP_SHORT(val);
     GET_BITFIELD(val, size);
     return PyLong_FromLong(val);
 }
@@ -616,12 +604,13 @@ H_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
 {
     unsigned long val;
     unsigned short field;
-    if (get_ulong(value, &val) < 0)
+    if (get_ulong(value, &val) < 0) {
         return NULL;
+    }
     memcpy(&field, ptr, sizeof(field));
-    field = SWAP_2(field);
+    field = SWAP_SHORT(field);
     field = SET(unsigned short, field, val, size);
-    field = SWAP_2(field);
+    field = SWAP_SHORT(field);
     memcpy(ptr, &field, sizeof(field));
     _RET(value);
 }
@@ -641,7 +630,7 @@ H_get_sw(void *ptr, Py_ssize_t size)
 {
     unsigned short val;
     memcpy(&val, ptr, sizeof(val));
-    val = SWAP_2(val);
+    val = SWAP_SHORT(val);
     GET_BITFIELD(val, size);
     return PyLong_FromLong(val);
 }
@@ -664,8 +653,9 @@ i_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
 {
     long val;
     int field;
-    if (get_long(value, &val) < 0)
+    if (get_long(value, &val) < 0) {
         return NULL;
+    }
     memcpy(&field, ptr, sizeof(field));
     field = SWAP_INT(field);
     field = SET(int, field, val, size);
@@ -757,8 +747,9 @@ I_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
 {
     unsigned long val;
     unsigned int field;
-    if (get_ulong(value, &val) < 0)
+    if (get_ulong(value, &val) < 0) {
         return  NULL;
+    }
     memcpy(&field, ptr, sizeof(field));
     field = SWAP_INT(field);
     field = SET(unsigned int, field, (unsigned int)val, size);
@@ -805,8 +796,9 @@ l_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
 {
     long val;
     long field;
-    if (get_long(value, &val) < 0)
+    if (get_long(value, &val) < 0) {
         return NULL;
+    }
     memcpy(&field, ptr, sizeof(field));
     field = SWAP_LONG(field);
     field = SET(long, field, val, size);
@@ -853,8 +845,9 @@ L_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
 {
     unsigned long val;
     unsigned long field;
-    if (get_ulong(value, &val) < 0)
+    if (get_ulong(value, &val) < 0) {
         return  NULL;
+    }
     memcpy(&field, ptr, sizeof(field));
     field = SWAP_LONG(field);
     field = SET(unsigned long, field, val, size);
@@ -901,12 +894,13 @@ q_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
 {
     long long val;
     long long field;
-    if (get_longlong(value, &val) < 0)
+    if (get_longlong(value, &val) < 0) {
         return NULL;
+    }
     memcpy(&field, ptr, sizeof(field));
-    field = SWAP_8(field);
+    field = SWAP_LONG_LONG(field);
     field = SET(long long, field, val, size);
-    field = SWAP_8(field);
+    field = SWAP_LONG_LONG(field);
     memcpy(ptr, &field, sizeof(field));
     _RET(value);
 }
@@ -925,7 +919,7 @@ q_get_sw(void *ptr, Py_ssize_t size)
 {
     long long val;
     memcpy(&val, ptr, sizeof(val));
-    val = SWAP_8(val);
+    val = SWAP_LONG_LONG(val);
     GET_BITFIELD(val, size);
     return PyLong_FromLongLong(val);
 }
@@ -948,12 +942,13 @@ Q_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
 {
     unsigned long long val;
     unsigned long long field;
-    if (get_ulonglong(value, &val) < 0)
+    if (get_ulonglong(value, &val) < 0) {
         return NULL;
+    }
     memcpy(&field, ptr, sizeof(field));
-    field = SWAP_8(field);
+    field = SWAP_LONG_LONG(field);
     field = SET(unsigned long long, field, val, size);
-    field = SWAP_8(field);
+    field = SWAP_LONG_LONG(field);
     memcpy(ptr, &field, sizeof(field));
     _RET(value);
 }
@@ -972,7 +967,7 @@ Q_get_sw(void *ptr, Py_ssize_t size)
 {
     unsigned long long val;
     memcpy(&val, ptr, sizeof(val));
-    val = SWAP_8(val);
+    val = SWAP_LONG_LONG(val);
     GET_BITFIELD(val, size);
     return PyLong_FromUnsignedLongLong(val);
 }
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 8352f6e2590c5..9330e2625b3a0 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -9,6 +9,7 @@
 #define PY_SSIZE_T_CLEAN
 
 #include "Python.h"
+#include "pycore_byteswap.h"     // _Py_bswap32()
 #include "pycore_initconfig.h"   // _Py_GetConfigsAsDict()
 #include "pycore_gc.h"           // PyGC_Head
 
@@ -21,7 +22,7 @@ get_configs(PyObject *self, PyObject *Py_UNUSED(args))
 
 
 static PyObject*
-get_recursion_depth(PyObject *self, PyObject *args)
+get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args))
 {
     PyThreadState *tstate = PyThreadState_Get();
 
@@ -30,9 +31,38 @@ get_recursion_depth(PyObject *self, PyObject *args)
 }
 
 
+static PyObject*
+test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
+{
+    uint16_t u16 = _Py_bswap16(UINT16_C(0x3412));
+    if (u16 != UINT16_C(0x1234)) {
+        PyErr_Format(PyExc_AssertionError,
+                     "_Py_bswap16(0x3412) returns %u", u16);
+        return NULL;
+    }
+
+    uint32_t u32 = _Py_bswap32(UINT32_C(0x78563412));
+    if (u32 != UINT32_C(0x12345678)) {
+        PyErr_Format(PyExc_AssertionError,
+                     "_Py_bswap32(0x78563412) returns %lu", u32);
+        return NULL;
+    }
+
+    uint64_t u64 = _Py_bswap64(UINT64_C(0xEFCDAB9078563412));
+    if (u64 != UINT64_C(0x1234567890ABCDEF)) {
+        PyErr_Format(PyExc_AssertionError,
+                     "_Py_bswap64(0xEFCDAB9078563412) returns %llu", u64);
+        return NULL;
+    }
+
+    Py_RETURN_NONE;
+}
+
+
 static PyMethodDef TestMethods[] = {
     {"get_configs", get_configs, METH_NOARGS},
     {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
+    {"test_bswap", test_bswap, METH_NOARGS},
     {NULL, NULL} /* sentinel */
 };
 
diff --git a/Modules/sha256module.c b/Modules/sha256module.c
index 731082655c0ec..e0ff9b2b3a187 100644
--- a/Modules/sha256module.c
+++ b/Modules/sha256module.c
@@ -17,6 +17,7 @@
 /* SHA objects */
 
 #include "Python.h"
+#include "pycore_byteswap.h"      // _Py_bswap32()
 #include "structmember.h"         // PyMemberDef
 #include "hashlib.h"
 #include "pystrhex.h"
@@ -30,12 +31,7 @@ class SHA256Type "SHAobject *" "&PyType_Type"
 /* Some useful types */
 
 typedef unsigned char SHA_BYTE;
-
-#if SIZEOF_INT == 4
-typedef unsigned int SHA_INT32; /* 32-bit integer */
-#else
-/* not defined. compilation will die. */
-#endif
+typedef uint32_t SHA_INT32;  /* 32-bit integer */
 
 /* The SHA block size and message digest sizes, in bytes */
 
@@ -61,14 +57,9 @@ typedef struct {
 #if PY_LITTLE_ENDIAN
 static void longReverse(SHA_INT32 *buffer, int byteCount)
 {
-    SHA_INT32 value;
-
     byteCount /= sizeof(*buffer);
-    while (byteCount--) {
-        value = *buffer;
-        value = ( ( value & 0xFF00FF00L ) >> 8  ) | \
-                ( ( value & 0x00FF00FFL ) << 8 );
-        *buffer++ = ( value << 16 ) | ( value >> 16 );
+    for (; byteCount--; buffer++) {
+        *buffer = _Py_bswap32(*buffer);
     }
 }
 #endif
diff --git a/Modules/sha512module.c b/Modules/sha512module.c
index 38d303d369ec5..780f8e7f06c9e 100644
--- a/Modules/sha512module.c
+++ b/Modules/sha512module.c
@@ -17,6 +17,7 @@
 /* SHA objects */
 
 #include "Python.h"
+#include "pycore_byteswap.h"      // _Py_bswap32()
 #include "structmember.h"         // PyMemberDef
 #include "hashlib.h"
 #include "pystrhex.h"
@@ -30,13 +31,8 @@ class SHA512Type "SHAobject *" "&PyType_Type"
 /* Some useful types */
 
 typedef unsigned char SHA_BYTE;
-
-#if SIZEOF_INT == 4
-typedef unsigned int SHA_INT32; /* 32-bit integer */
-typedef unsigned long long SHA_INT64;        /* 64-bit integer */
-#else
-/* not defined. compilation will die. */
-#endif
+typedef uint32_t SHA_INT32;  /* 32-bit integer */
+typedef uint64_t SHA_INT64;  /* 64-bit integer */
 
 /* The SHA block size and message digest sizes, in bytes */
 
@@ -62,22 +58,9 @@ typedef struct {
 #if PY_LITTLE_ENDIAN
 static void longReverse(SHA_INT64 *buffer, int byteCount)
 {
-    SHA_INT64 value;
-
     byteCount /= sizeof(*buffer);
-    while (byteCount--) {
-        value = *buffer;
-
-                ((unsigned char*)buffer)[0] = (unsigned char)(value >> 56) & 0xff;
-                ((unsigned char*)buffer)[1] = (unsigned char)(value >> 48) & 0xff;
-                ((unsigned char*)buffer)[2] = (unsigned char)(value >> 40) & 0xff;
-                ((unsigned char*)buffer)[3] = (unsigned char)(value >> 32) & 0xff;
-                ((unsigned char*)buffer)[4] = (unsigned char)(value >> 24) & 0xff;
-                ((unsigned char*)buffer)[5] = (unsigned char)(value >> 16) & 0xff;
-                ((unsigned char*)buffer)[6] = (unsigned char)(value >>  8) & 0xff;
-                ((unsigned char*)buffer)[7] = (unsigned char)(value      ) & 0xff;
-
-                buffer++;
+    for (; byteCount--; buffer++) {
+        *buffer = _Py_bswap64(*buffer);
     }
 }
 #endif
diff --git a/Objects/stringlib/codecs.h b/Objects/stringlib/codecs.h
index cd7aa699b8f0f..208e8fe4a48bb 100644
--- a/Objects/stringlib/codecs.h
+++ b/Objects/stringlib/codecs.h
@@ -4,6 +4,8 @@
 # error "codecs.h is specific to Unicode"
 #endif
 
+#include "pycore_byteswap.h"      // _Py_bswap32()
+
 /* Mask to quickly check whether a C 'long' contains a
    non-ASCII, UTF8-encoded char. */
 #if (SIZEOF_LONG == 8)
@@ -732,24 +734,28 @@ STRINGLIB(utf16_encode)(const STRINGLIB_CHAR *in,
 #endif
 }
 
+static inline uint32_t
+STRINGLIB(SWAB4)(STRINGLIB_CHAR ch)
+{
+    uint32_t word = ch;
 #if STRINGLIB_SIZEOF_CHAR == 1
-# define SWAB4(CH, tmp)  ((CH) << 24) /* high bytes are zero */
+    /* high bytes are zero */
+    return (word << 24);
 #elif STRINGLIB_SIZEOF_CHAR == 2
-# define SWAB4(CH, tmp)  (tmp = (CH), \
-            ((tmp & 0x00FFu) << 24) + ((tmp & 0xFF00u) << 8))
-            /* high bytes are zero */
+    /* high bytes are zero */
+    return ((word & 0x00FFu) << 24) + ((word & 0xFF00u) << 8);
 #else
-# define SWAB4(CH, tmp)  (tmp = (CH), \
-            tmp = ((tmp & 0x00FF00FFu) << 8) + ((tmp >> 8) & 0x00FF00FFu), \
-            ((tmp & 0x0000FFFFu) << 16) + ((tmp >> 16) & 0x0000FFFFu))
+    return _Py_bswap32(word);
 #endif
+}
+
 Py_LOCAL_INLINE(Py_ssize_t)
 STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in,
                         Py_ssize_t len,
-                        PY_UINT32_T **outptr,
+                        uint32_t **outptr,
                         int native_ordering)
 {
-    PY_UINT32_T *out = *outptr;
+    uint32_t *out = *outptr;
     const STRINGLIB_CHAR *end = in + len;
     if (native_ordering) {
         const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
@@ -783,7 +789,6 @@ STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in,
         const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
         while (in < unrolled_end) {
 #if STRINGLIB_SIZEOF_CHAR > 1
-            Py_UCS4 ch1, ch2, ch3, ch4;
             /* check if any character is a surrogate character */
             if (((in[0] ^ 0xd800) &
                  (in[1] ^ 0xd800) &
@@ -791,10 +796,10 @@ STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in,
                  (in[3] ^ 0xd800) & 0xf800) == 0)
                 break;
 #endif
-            out[0] = SWAB4(in[0], ch1);
-            out[1] = SWAB4(in[1], ch2);
-            out[2] = SWAB4(in[2], ch3);
-            out[3] = SWAB4(in[3], ch4);
+            out[0] = STRINGLIB(SWAB4)(in[0]);
+            out[1] = STRINGLIB(SWAB4)(in[1]);
+            out[2] = STRINGLIB(SWAB4)(in[2]);
+            out[3] = STRINGLIB(SWAB4)(in[3]);
             in += 4; out += 4;
         }
         while (in < end) {
@@ -805,7 +810,7 @@ STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in,
                 goto fail;
             }
 #endif
-            *out++ = SWAB4(ch, ch);
+            *out++ = STRINGLIB(SWAB4)(ch);
         }
     }
     *outptr = out;
@@ -816,6 +821,5 @@ STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in,
     return len - (end - in + 1);
 #endif
 }
-#undef SWAB4
 
 #endif
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index c35499e0eb772..862c5a821b1f9 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -164,6 +164,7 @@
     <ClInclude Include="..\Include\internal\pycore_abstract.h" />
     <ClInclude Include="..\Include\internal\pycore_accu.h" />
     <ClInclude Include="..\Include\internal\pycore_atomic.h" />
+    <ClInclude Include="..\Include\internal\pycore_byteswap.h" />
     <ClInclude Include="..\Include\internal\pycore_bytes_methods.h" />
     <ClInclude Include="..\Include\internal\pycore_call.h" />
     <ClInclude Include="..\Include\internal\pycore_ceval.h" />
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index c04df27de5860..9d6d997b5267e 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -195,6 +195,9 @@
     <ClInclude Include="..\Include\internal\pycore_atomic.h">
       <Filter>Include</Filter>
     </ClInclude>
+    <ClInclude Include="..\Include\internal\pycore_byteswap.h">
+      <Filter>Include</Filter>
+    </ClInclude>
     <ClInclude Include="..\Include\internal\pycore_bytes_methods.h">
       <Filter>Include</Filter>
     </ClInclude>
diff --git a/setup.py b/setup.py
index 0357a0124f8b8..65a1cfab078c5 100644
--- a/setup.py
+++ b/setup.py
@@ -2044,7 +2044,7 @@ def detect_ctypes(self):
         # Thomas Heller's _ctypes module
         self.use_system_libffi = False
         include_dirs = []
-        extra_compile_args = []
+        extra_compile_args = ['-DPy_BUILD_CORE_MODULE']
         extra_link_args = []
         sources = ['_ctypes/_ctypes.c',
                    '_ctypes/callbacks.c',
@@ -2298,8 +2298,10 @@ def detect_hash_builtins(self):
         # It's harmless and the object code is tiny (40-50 KiB per module,
         # only loaded when actually used).
         self.add(Extension('_sha256', ['sha256module.c'],
+                           extra_compile_args=['-DPy_BUILD_CORE_MODULE'],
                            depends=['hashlib.h']))
         self.add(Extension('_sha512', ['sha512module.c'],
+                           extra_compile_args=['-DPy_BUILD_CORE_MODULE'],
                            depends=['hashlib.h']))
         self.add(Extension('_md5', ['md5module.c'],
                            depends=['hashlib.h']))



More information about the Python-checkins mailing list