@@ -695,6 +695,43 @@ PHP_FUNCTION(natcasesort)
695695
696696typedef bucket_compare_func_t (* get_compare_function )(zend_long );
697697
698+ static int php_array_packed_long_compare (const void * a , const void * b )
699+ {
700+ const zval * lhs = a , * rhs = b ;
701+ if (Z_LVAL_P (lhs ) != Z_LVAL_P (rhs )) {
702+ return Z_LVAL_P (lhs ) > Z_LVAL_P (rhs ) ? 1 : -1 ;
703+ }
704+ return (Z_EXTRA_P (lhs ) > Z_EXTRA_P (rhs )) - (Z_EXTRA_P (lhs ) < Z_EXTRA_P (rhs ));
705+ }
706+
707+ static int php_array_packed_long_reverse_compare (const void * a , const void * b )
708+ {
709+ const zval * lhs = a , * rhs = b ;
710+ if (Z_LVAL_P (lhs ) != Z_LVAL_P (rhs )) {
711+ return Z_LVAL_P (lhs ) < Z_LVAL_P (rhs ) ? 1 : -1 ;
712+ }
713+ return (Z_EXTRA_P (lhs ) > Z_EXTRA_P (rhs )) - (Z_EXTRA_P (lhs ) < Z_EXTRA_P (rhs ));
714+ }
715+
716+ static bool php_array_try_packed_long_sort (HashTable * array , compare_func_t cmp )
717+ {
718+ if (!HT_IS_PACKED (array )
719+ || !HT_IS_WITHOUT_HOLES (array ) || HT_HAS_ITERATORS (array )) {
720+ return false;
721+ }
722+
723+ /* Reject references and other types before changing any element. Integer
724+ * comparisons cannot invoke user code, so the array stays exclusively owned. */
725+ for (uint32_t i = 0 ; i < array -> nNumUsed ; i ++ ) {
726+ if (Z_TYPE (array -> arPacked [i ]) != IS_LONG ) {
727+ return false;
728+ }
729+ }
730+
731+ zend_hash_sort_packed (array , cmp );
732+ return true;
733+ }
734+
698735static zend_always_inline void php_sort (INTERNAL_FUNCTION_PARAMETERS , get_compare_function get_cmp , bool renumber ) {
699736 HashTable * array ;
700737 zend_long sort_type = PHP_SORT_REGULAR ;
@@ -708,6 +745,14 @@ static zend_always_inline void php_sort(INTERNAL_FUNCTION_PARAMETERS, get_compar
708745
709746 cmp = get_cmp (sort_type );
710747
748+ /* Keep small sorts out of the speculative type scan and helper call. */
749+ if (renumber && sort_type == PHP_SORT_REGULAR && array -> nNumOfElements >= 64
750+ && php_array_try_packed_long_sort (array ,
751+ get_cmp == php_get_data_compare_func
752+ ? php_array_packed_long_compare : php_array_packed_long_reverse_compare )) {
753+ RETURN_TRUE ;
754+ }
755+
711756 zend_array_sort (array , cmp , renumber );
712757
713758 RETURN_TRUE ;
0 commit comments