3333#include <mach/vm_statistics.h>
3434#endif
3535
36+ #include "zend_execute.h"
37+
3638#if defined(MAP_ANON ) && !defined(MAP_ANONYMOUS )
3739# define MAP_ANONYMOUS MAP_ANON
3840#endif
3941#if defined(MAP_ALIGNED_SUPER )
4042# define MAP_HUGETLB MAP_ALIGNED_SUPER
4143#endif
4244
45+ #if defined(__linux__ ) && (defined(__x86_64__ ) || defined (__aarch64__ ))
46+ static void * find_prefered_mmap_base (size_t requested_size )
47+ {
48+ FILE * f ;
49+ size_t huge_page_size = 2 * 1024 * 1024 ;
50+ uintptr_t last_free_addr = 0 ;
51+ uintptr_t last_candidate = (uintptr_t )MAP_FAILED ;
52+ uintptr_t start , end , text_start = 0 ;
53+ char buffer [MAXPATHLEN ];
54+
55+ f = fopen ("/proc/self/maps" , "r" );
56+ if (!f ) {
57+ return MAP_FAILED ;
58+ }
59+
60+ while (fgets (buffer , MAXPATHLEN , f ) && sscanf (buffer , "%lx-%lx" , & start , & end ) == 2 ) {
61+ if ((uintptr_t )execute_ex >= start ) {
62+ /* the current segment lays before PHP .text segment or PHP .text segment itself */
63+ if (last_free_addr + requested_size <= start ) {
64+ last_candidate = last_free_addr ;
65+ }
66+ if ((uintptr_t )execute_ex < end ) {
67+ /* the current segment is PHP .text segment itself */
68+ if (last_candidate != (uintptr_t )MAP_FAILED ) {
69+ if (end - last_candidate < UINT32_MAX ) {
70+ /* we have found a big anough hole before the text segment */
71+ break ;
72+ }
73+ last_candidate = (uintptr_t )MAP_FAILED ;
74+ }
75+ text_start = start ;
76+ }
77+ } else {
78+ /* the current segment lays after PHP .text segment */
79+ if (last_free_addr + requested_size - text_start > UINT32_MAX ) {
80+ /* the current segment and the following segments lay too far from PHP .text segment */
81+ break ;
82+ }
83+ if (last_free_addr + requested_size <= start ) {
84+ last_candidate = last_free_addr ;
85+ break ;
86+ }
87+ }
88+ last_free_addr = ZEND_MM_ALIGNED_SIZE_EX (end , huge_page_size );
89+
90+ }
91+ fclose (f );
92+
93+ return (void * )last_candidate ;
94+ }
95+ #endif
96+
4397static int create_segments (size_t requested_size , zend_shared_segment * * * shared_segments_p , int * shared_segments_count , char * * error_in )
4498{
4599 zend_shared_segment * shared_segment ;
@@ -55,6 +109,24 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
55109#ifdef PROT_MAX
56110 flags |= PROT_MAX (PROT_READ | PROT_WRITE | PROT_EXEC );
57111#endif
112+ #if defined(__linux__ ) && (defined(__x86_64__ ) || defined (__aarch64__ ))
113+ void * hint = find_prefered_mmap_base (requested_size );
114+ if (hint != MAP_FAILED ) {
115+ # ifdef MAP_HUGETLB
116+ size_t huge_page_size = 2 * 1024 * 1024 ;
117+ if (requested_size >= huge_page_size && requested_size % huge_page_size == 0 ) {
118+ p = mmap (hint , requested_size , flags , MAP_SHARED |MAP_ANONYMOUS |MAP_HUGETLB |MAP_FIXED , -1 , 0 );
119+ if (p != MAP_FAILED ) {
120+ goto success ;
121+ }
122+ }
123+ #endif
124+ p = mmap (hint , requested_size , flags , MAP_SHARED |MAP_ANONYMOUS |MAP_FIXED , -1 , 0 );
125+ if (p != MAP_FAILED ) {
126+ goto success ;
127+ }
128+ }
129+ #endif
58130#ifdef MAP_HUGETLB
59131 size_t huge_page_size = 2 * 1024 * 1024 ;
60132
0 commit comments