30
30
#if defined(__FreeBSD__)
31
31
#include < sys/sysctl.h>
32
32
#include < sys/user.h>
33
+ #elif defined(__APPLE__)
34
+ #include < mach/vm_map.h>
33
35
#endif
34
36
#include < unistd.h> // readlink
35
37
47
49
#include < sstream>
48
50
#include < vector>
49
51
52
+ // Define MAP_ANONYMOUS as an alias for MAP_ANON to support OSX 10.10.
53
+ #if defined(__APPLE__)
54
+ #ifndef MAP_ANONYMOUS
55
+ #define MAP_ANONYMOUS MAP_ANON
56
+ #endif
57
+ #endif
58
+
50
59
// The functions in this file map the text segment of node into 2M pages.
51
60
// The algorithm is simple
52
61
// Find the text region of node binary in memory
@@ -212,6 +221,42 @@ static struct text_region FindNodeTextRegion() {
212
221
}
213
222
start += cursz;
214
223
}
224
+ #elif defined(__APPLE__)
225
+ struct text_region nregion;
226
+ nregion.found_text_region = false ;
227
+ struct vm_region_submap_info_64 map;
228
+ mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
229
+ vm_address_t addr = 0UL ;
230
+ vm_size_t size = 0 ;
231
+ natural_t depth = 1 ;
232
+
233
+ while (true ) {
234
+ if (vm_region_recurse_64 (mach_task_self (), &addr, &size, &depth,
235
+ reinterpret_cast <vm_region_info_64_t >(&map),
236
+ &count) != KERN_SUCCESS) {
237
+ break ;
238
+ }
239
+
240
+ if (map.is_submap ) {
241
+ depth++;
242
+ } else {
243
+ char * start = reinterpret_cast <char *>(hugepage_align_up (addr));
244
+ char * end = reinterpret_cast <char *>(hugepage_align_down (addr+size));
245
+ size_t esize = end - start;
246
+
247
+ if (end > start && (map.protection & VM_PROT_READ) != 0 &&
248
+ (map.protection & VM_PROT_EXECUTE) != 0 ) {
249
+ nregion.found_text_region = true ;
250
+ nregion.from = start;
251
+ nregion.to = end;
252
+ nregion.total_hugepages = esize / hps;
253
+ break ;
254
+ }
255
+
256
+ addr += size;
257
+ size = 0 ;
258
+ }
259
+ }
215
260
#endif
216
261
return nregion;
217
262
}
@@ -267,11 +312,15 @@ static bool IsSuperPagesEnabled() {
267
312
// 2: This function should not call any function(s) that might be moved.
268
313
// a. map a new area and copy the original code there
269
314
// b. mmap using the start address with MAP_FIXED so we get exactly
270
- // the same virtual address
315
+ // the same virtual address (except on macOS).
271
316
// c. madvise with MADV_HUGE_PAGE
272
317
// d. If successful copy the code there and unmap the original region
273
318
int
319
+ #if !defined(__APPLE__)
274
320
__attribute__ ((__section__(" .lpstub" )))
321
+ #else
322
+ __attribute__ ((__section__(" __TEXT,__lpstub" )))
323
+ #endif
275
324
__attribute__ ((__aligned__(hps)))
276
325
__attribute__ ((__noinline__))
277
326
MoveTextRegionToLargePages (const text_region& r) {
@@ -289,6 +338,9 @@ MoveTextRegionToLargePages(const text_region& r) {
289
338
PrintSystemError (errno);
290
339
return -1 ;
291
340
}
341
+ OnScopeLeave munmap_on_return ([nmem, size]() {
342
+ if (-1 == munmap (nmem, size)) PrintSystemError (errno);
343
+ });
292
344
293
345
memcpy (nmem, r.from , size);
294
346
@@ -302,7 +354,6 @@ MoveTextRegionToLargePages(const text_region& r) {
302
354
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1 , 0 );
303
355
if (tmem == MAP_FAILED) {
304
356
PrintSystemError (errno);
305
- munmap (nmem, size);
306
357
return -1 ;
307
358
}
308
359
@@ -313,11 +364,6 @@ MoveTextRegionToLargePages(const text_region& r) {
313
364
if (ret == -1 ) {
314
365
PrintSystemError (errno);
315
366
}
316
- ret = munmap (nmem, size);
317
- if (ret == -1 ) {
318
- PrintSystemError (errno);
319
- }
320
-
321
367
return -1 ;
322
368
}
323
369
#elif defined(__FreeBSD__)
@@ -327,32 +373,46 @@ MoveTextRegionToLargePages(const text_region& r) {
327
373
MAP_ALIGNED_SUPER, -1 , 0 );
328
374
if (tmem == MAP_FAILED) {
329
375
PrintSystemError (errno);
330
- munmap (nmem, size);
331
376
return -1 ;
332
377
}
333
- #endif
334
-
335
- memcpy (start, nmem, size);
336
- ret = mprotect (start, size, PROT_READ | PROT_EXEC);
378
+ #elif defined(__APPLE__)
379
+ // There is not enough room to reserve the mapping close
380
+ // to the region address so we content to give a hint
381
+ // without forcing the new address being closed to.
382
+ // We explicitally gives all permission since we plan
383
+ // to write into it.
384
+ tmem = mmap (start, size,
385
+ PROT_READ | PROT_WRITE | PROT_EXEC,
386
+ MAP_PRIVATE | MAP_ANONYMOUS,
387
+ VM_FLAGS_SUPERPAGE_SIZE_2MB, 0 );
388
+ if (tmem == MAP_FAILED) {
389
+ PrintSystemError (errno);
390
+ return -1 ;
391
+ }
392
+ memcpy (tmem, nmem, size);
393
+ ret = mprotect (start, size, PROT_READ | PROT_WRITE | PROT_EXEC);
337
394
if (ret == -1 ) {
338
395
PrintSystemError (errno);
339
396
ret = munmap (tmem, size);
340
397
if (ret == -1 ) {
341
398
PrintSystemError (errno);
342
399
}
343
- ret = munmap (nmem, size);
344
- if (ret == -1 ) {
345
- PrintSystemError (errno);
346
- }
347
400
return -1 ;
348
401
}
402
+ memcpy (start, tmem, size);
403
+ #else
404
+ memcpy (start, nmem, size);
405
+ #endif
349
406
350
- // Release the old/temporary mapped region
351
- ret = munmap (nmem, size);
407
+ ret = mprotect (start, size, PROT_READ | PROT_EXEC);
352
408
if (ret == -1 ) {
353
409
PrintSystemError (errno);
410
+ ret = munmap (tmem, size);
411
+ if (ret == -1 ) {
412
+ PrintSystemError (errno);
413
+ }
414
+ return -1 ;
354
415
}
355
-
356
416
return ret;
357
417
}
358
418
@@ -369,16 +429,19 @@ int MapStaticCodeToLargePages() {
369
429
return MoveTextRegionToLargePages (r);
370
430
371
431
return -1 ;
372
- #elif defined(__FreeBSD__)
432
+ #elif defined(__FreeBSD__) || defined(__APPLE__)
373
433
return MoveTextRegionToLargePages (r);
374
434
#endif
375
435
}
376
436
377
437
bool IsLargePagesEnabled () {
378
438
#if defined(__linux__)
379
439
return IsTransparentHugePagesEnabled ();
380
- #else
440
+ #elif defined(__FreeBSD__)
381
441
return IsSuperPagesEnabled ();
442
+ #elif defined(__APPLE__)
443
+ // pse-36 flag is present in recent mac x64 products.
444
+ return true ;
382
445
#endif
383
446
}
384
447
0 commit comments