@@ -653,29 +653,43 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
653653 stgdict -> align = total_align ;
654654 stgdict -> length = len ; /* ADD ffi_ofs? */
655655
656- #define MAX_STRUCT_SIZE 16
656+ /*
657+ * On Arm platforms, structs with at most 4 elements of any floating point
658+ * type values can be passed through registers. If the type is double the
659+ * maximum size of the struct is 32 bytes.
660+ * By Arm platforms it is meant both 32 and 64-bit.
661+ */
662+ #if defined(__aarch64__ ) || defined(__arm__ )
663+ # define MAX_STRUCT_SIZE 32
664+ #else
665+ # define MAX_STRUCT_SIZE 16
666+ #endif
657667
658668 if (arrays_seen && (size <= MAX_STRUCT_SIZE )) {
659669 /*
660- * See bpo-22273. Arrays are normally treated as pointers, which is
661- * fine when an array name is being passed as parameter, but not when
662- * passing structures by value that contain arrays. On 64-bit Linux,
663- * small structures passed by value are passed in registers, and in
664- * order to do this, libffi needs to know the true type of the array
665- * members of structs. Treating them as pointers breaks things.
670+ * See bpo-22273 and gh-110190. Arrays are normally treated as
671+ * pointers, which is fine when an array name is being passed as
672+ * parameter, but not when passing structures by value that contain
673+ * arrays.
674+ * On x86_64 Linux and Arm platforms, small structures passed by
675+ * value are passed in registers, and in order to do this, libffi needs
676+ * to know the true type of the array members of structs. Treating them
677+ * as pointers breaks things.
666678 *
667- * By small structures, we mean ones that are 16 bytes or less. In that
668- * case, there can't be more than 16 elements after unrolling arrays,
669- * as we (will) disallow bitfields. So we can collect the true ffi_type
670- * values in a fixed-size local array on the stack and, if any arrays
671- * were seen, replace the ffi_type_pointer.elements with a more
672- * accurate set, to allow libffi to marshal them into registers
673- * correctly. It means one more loop over the fields, but if we got
674- * here, the structure is small, so there aren't too many of those.
679+ * By small structures, we mean ones that are 16 bytes or less on
680+ * x86-64 and 32 bytes or less on Arm. In that case, there can't be
681+ * more than 16 or 32 elements after unrolling arrays, as we (will)
682+ * disallow bitfields. So we can collect the true ffi_type values in
683+ * a fixed-size local array on the stack and, if any arrays were seen,
684+ * replace the ffi_type_pointer.elements with a more accurate set,
685+ * to allow libffi to marshal them into registers correctly.
686+ * It means one more loop over the fields, but if we got here,
687+ * the structure is small, so there aren't too many of those.
675688 *
676- * Although the passing in registers is specific to 64-bit Linux, the
677- * array-in-struct vs. pointer problem is general. But we restrict the
678- * type transformation to small structs nonetheless.
689+ * Although the passing in registers is specific to x86_64 Linux
690+ * and Arm platforms, the array-in-struct vs. pointer problem is
691+ * general. But we restrict the type transformation to small structs
692+ * nonetheless.
679693 *
680694 * Note that although a union may be small in terms of memory usage, it
681695 * could contain many overlapping declarations of arrays, e.g.
@@ -701,6 +715,9 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
701715 * struct { uint_32 e1; uint_32 e2; ... uint_32 e_4; } f6;
702716 * }
703717 *
718+ * The same principle applies for a struct 32 bytes in size like in
719+ * the case of Arm platforms.
720+ *
704721 * So the struct/union needs setting up as follows: all non-array
705722 * elements copied across as is, and all array elements replaced with
706723 * an equivalent struct which has as many fields as the array has
0 commit comments