3030#if defined(__FreeBSD__)
3131#include < sys/sysctl.h>
3232#include < sys/user.h>
33+ #elif defined(__APPLE__)
34+ #include < mach/vm_map.h>
3335#endif
3436#include < unistd.h> // readlink
3537
@@ -212,6 +214,42 @@ static struct text_region FindNodeTextRegion() {
212214 }
213215 start += cursz;
214216 }
217+ #elif defined(__APPLE__)
218+ struct text_region nregion;
219+ nregion.found_text_region = false ;
220+ struct vm_region_submap_info_64 map;
221+ mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
222+ vm_address_t addr = 0UL ;
223+ vm_size_t size = 0 ;
224+ natural_t depth = 1 ;
225+
226+ while (true ) {
227+ if (vm_region_recurse_64 (mach_task_self (), &addr, &size, &depth,
228+ reinterpret_cast <vm_region_info_64_t >(&map),
229+ &count) != KERN_SUCCESS) {
230+ break ;
231+ }
232+
233+ if (map.is_submap ) {
234+ depth++;
235+ } else {
236+ char * start = reinterpret_cast <char *>(hugepage_align_up (addr));
237+ char * end = reinterpret_cast <char *>(hugepage_align_down (addr+size));
238+ size_t esize = end - start;
239+
240+ if (end > start && (map.protection & VM_PROT_READ) != 0 &&
241+ (map.protection & VM_PROT_EXECUTE) != 0 ) {
242+ nregion.found_text_region = true ;
243+ nregion.from = start;
244+ nregion.to = end;
245+ nregion.total_hugepages = esize / hps;
246+ break ;
247+ }
248+
249+ addr += size;
250+ size = 0 ;
251+ }
252+ }
215253#endif
216254 return nregion;
217255}
@@ -267,11 +305,15 @@ static bool IsSuperPagesEnabled() {
267305// 2: This function should not call any function(s) that might be moved.
268306// a. map a new area and copy the original code there
269307// b. mmap using the start address with MAP_FIXED so we get exactly
270- // the same virtual address
308+ // the same virtual address (except on macOS).
271309// c. madvise with MADV_HUGE_PAGE
272310// d. If successful copy the code there and unmap the original region
273311int
312+ #if !defined(__APPLE__)
274313__attribute__ ((__section__(" .lpstub" )))
314+ #else
315+ __attribute__ ((__section__(" __TEXT,__lpstub" )))
316+ #endif
275317__attribute__ ((__aligned__(hps)))
276318__attribute__ ((__noinline__))
277319MoveTextRegionToLargePages (const text_region& r) {
@@ -289,6 +331,9 @@ MoveTextRegionToLargePages(const text_region& r) {
289331 PrintSystemError (errno);
290332 return -1 ;
291333 }
334+ OnScopeLeave munmap_on_return ([nmem, size]() {
335+ if (-1 == munmap (nmem, size)) PrintSystemError (errno);
336+ });
292337
293338 memcpy (nmem, r.from , size);
294339
@@ -302,7 +347,6 @@ MoveTextRegionToLargePages(const text_region& r) {
302347 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1 , 0 );
303348 if (tmem == MAP_FAILED) {
304349 PrintSystemError (errno);
305- munmap (nmem, size);
306350 return -1 ;
307351 }
308352
@@ -313,11 +357,6 @@ MoveTextRegionToLargePages(const text_region& r) {
313357 if (ret == -1 ) {
314358 PrintSystemError (errno);
315359 }
316- ret = munmap (nmem, size);
317- if (ret == -1 ) {
318- PrintSystemError (errno);
319- }
320-
321360 return -1 ;
322361 }
323362#elif defined(__FreeBSD__)
@@ -327,32 +366,46 @@ MoveTextRegionToLargePages(const text_region& r) {
327366 MAP_ALIGNED_SUPER, -1 , 0 );
328367 if (tmem == MAP_FAILED) {
329368 PrintSystemError (errno);
330- munmap (nmem, size);
331369 return -1 ;
332370 }
333- #endif
334-
335- memcpy (start, nmem, size);
336- ret = mprotect (start, size, PROT_READ | PROT_EXEC);
371+ #elif defined(__APPLE__)
372+ // There is not enough room to reserve the mapping close
373+ // to the region address so we content to give a hint
374+ // without forcing the new address being closed to.
375+ // We explicitally gives all permission since we plan
376+ // to write into it.
377+ tmem = mmap (start, size,
378+ PROT_READ | PROT_WRITE | PROT_EXEC,
379+ MAP_PRIVATE | MAP_ANONYMOUS,
380+ VM_FLAGS_SUPERPAGE_SIZE_2MB, 0 );
381+ if (tmem == MAP_FAILED) {
382+ PrintSystemError (errno);
383+ return -1 ;
384+ }
385+ memcpy (tmem, nmem, size);
386+ ret = mprotect (start, size, PROT_READ | PROT_WRITE | PROT_EXEC);
337387 if (ret == -1 ) {
338388 PrintSystemError (errno);
339389 ret = munmap (tmem, size);
340390 if (ret == -1 ) {
341391 PrintSystemError (errno);
342392 }
343- ret = munmap (nmem, size);
344- if (ret == -1 ) {
345- PrintSystemError (errno);
346- }
347393 return -1 ;
348394 }
395+ memcpy (start, tmem, size);
396+ #else
397+ memcpy (start, nmem, size);
398+ #endif
349399
350- // Release the old/temporary mapped region
351- ret = munmap (nmem, size);
400+ ret = mprotect (start, size, PROT_READ | PROT_EXEC);
352401 if (ret == -1 ) {
353402 PrintSystemError (errno);
403+ ret = munmap (tmem, size);
404+ if (ret == -1 ) {
405+ PrintSystemError (errno);
406+ }
407+ return -1 ;
354408 }
355-
356409 return ret;
357410}
358411
@@ -369,16 +422,19 @@ int MapStaticCodeToLargePages() {
369422 return MoveTextRegionToLargePages (r);
370423
371424 return -1 ;
372- #elif defined(__FreeBSD__)
425+ #elif defined(__FreeBSD__) || defined(__APPLE__)
373426 return MoveTextRegionToLargePages (r);
374427#endif
375428}
376429
377430bool IsLargePagesEnabled () {
378431#if defined(__linux__)
379432 return IsTransparentHugePagesEnabled ();
380- #else
433+ #elif defined(__FreeBSD__)
381434 return IsSuperPagesEnabled ();
435+ #elif defined(__APPLE__)
436+ // pse-36 flag is present in recent mac x64 products.
437+ return true ;
382438#endif
383439}
384440
0 commit comments