diff --git a/runtime/platform/utils_macos.cc b/runtime/platform/utils_macos.cc index eaab3191d52..0c4762c8045 100644 --- a/runtime/platform/utils_macos.cc +++ b/runtime/platform/utils_macos.cc @@ -7,6 +7,9 @@ #include "platform/utils.h" +#include // NOLINT +#include // NOLINT + namespace dart { char* Utils::StrNDup(const char* s, intptr_t n) { @@ -64,6 +67,76 @@ int Utils::VSNPrint(char* str, size_t size, const char* format, va_list args) { return retval; } +namespace internal { + +// Returns the running system's Darwin major version. Don't call this, it's +// an implementation detail and its result is meant to be cached by +// MacOSXMinorVersion. +int32_t DarwinMajorVersionInternal() { + // uname is implemented as a simple series of sysctl system calls to + // obtain the relevant data from the kernel. The data is + // compiled right into the kernel, so no threads or blocking or other + // funny business is necessary. + + struct utsname uname_info; + if (uname(&uname_info) != 0) { + FATAL("Fatal error in DarwinMajorVersionInternal : invalid return uname"); + return 0; + } + + if (strcmp(uname_info.sysname, "Darwin") != 0) { + FATAL1( + "Fatal error in DarwinMajorVersionInternal : unexpected uname" + " sysname '%s'", + uname_info.sysname); + return 0; + } + + int32_t darwin_major_version = 0; + char* dot = strchr(uname_info.release, '.'); + if (dot) { + errno = 0; + char* end_ptr = NULL; + darwin_major_version = strtol(uname_info.release, &end_ptr, 10); + if (errno != 0 || (end_ptr == uname_info.release)) { + dot = NULL; + } + } + + if (!dot) { + FATAL1( + "Fatal error in DarwinMajorVersionInternal :" + " could not parse uname release '%s'", + uname_info.release); + return 0; + } + + return darwin_major_version; +} + +// Returns the running system's Mac OS X minor version. This is the |y| value +// in 10.y or 10.y.z. Don't call this, it's an implementation detail and the +// result is meant to be cached by MacOSXMinorVersion. +int32_t MacOSXMinorVersionInternal() { + int darwin_major_version = DarwinMajorVersionInternal(); + + // The Darwin major version is always 4 greater than the Mac OS X minor + // version for Darwin versions beginning with 6, corresponding to Mac OS X + // 10.2. Since this correspondence may change in the future, warn when + // encountering a version higher than anything seen before. Older Darwin + // versions, or versions that can't be determined, result in + // immediate death. + ASSERT(darwin_major_version >= 6); + return (darwin_major_version - 4); +} + +int32_t MacOSXMinorVersion() { + static int mac_os_x_minor_version = MacOSXMinorVersionInternal(); + return mac_os_x_minor_version; +} + +} // namespace internal + } // namespace dart #endif // defined(HOST_OS_MACOS) diff --git a/runtime/platform/utils_macos.h b/runtime/platform/utils_macos.h index 052352d81a4..bc34193119e 100644 --- a/runtime/platform/utils_macos.h +++ b/runtime/platform/utils_macos.h @@ -5,10 +5,71 @@ #ifndef RUNTIME_PLATFORM_UTILS_MACOS_H_ #define RUNTIME_PLATFORM_UTILS_MACOS_H_ +#include #include // NOLINT namespace dart { +namespace internal { + +// Returns the system's Mac OS X minor version. This is the |y| value +// in 10.y or 10.y.z. +int32_t MacOSXMinorVersion(); + +} // namespace internal + +// Run-time OS version checks. +#define DEFINE_IS_OS_FUNCS(V, TEST_DEPLOYMENT_TARGET) \ + inline bool IsOS10_##V() { \ + TEST_DEPLOYMENT_TARGET(>, V, false) \ + return internal::MacOSXMinorVersion() == V; \ + } \ + inline bool IsAtLeastOS10_##V() { \ + TEST_DEPLOYMENT_TARGET(>=, V, true) \ + return internal::MacOSXMinorVersion() >= V; \ + } \ + inline bool IsAtMostOS10_##V() { \ + TEST_DEPLOYMENT_TARGET(>, V, false) \ + return internal::MacOSXMinorVersion() <= V; \ + } + +#define TEST_DEPLOYMENT_TARGET(OP, V, RET) \ + if (MAC_OS_X_VERSION_MIN_REQUIRED OP MAC_OS_X_VERSION_10_##V) return RET; +#define IGNORE_DEPLOYMENT_TARGET(OP, V, RET) + +DEFINE_IS_OS_FUNCS(9, TEST_DEPLOYMENT_TARGET) +DEFINE_IS_OS_FUNCS(10, TEST_DEPLOYMENT_TARGET) + +#ifdef MAC_OS_X_VERSION_10_11 +DEFINE_IS_OS_FUNCS(11, TEST_DEPLOYMENT_TARGET) +#else +DEFINE_IS_OS_FUNCS(11, IGNORE_DEPLOYMENT_TARGET) +#endif + +#ifdef MAC_OS_X_VERSION_10_12 +DEFINE_IS_OS_FUNCS(12, TEST_DEPLOYMENT_TARGET) +#else +DEFINE_IS_OS_FUNCS(12, IGNORE_DEPLOYMENT_TARGET) +#endif + +#ifdef MAC_OS_X_VERSION_10_13 +DEFINE_IS_OS_FUNCS(13, TEST_DEPLOYMENT_TARGET) +#else +DEFINE_IS_OS_FUNCS(13, IGNORE_DEPLOYMENT_TARGET) +#endif + +#ifdef MAC_OS_X_VERSION_10_14 +DEFINE_IS_OS_FUNCS(14, TEST_DEPLOYMENT_TARGET) +#else +DEFINE_IS_OS_FUNCS(14, IGNORE_DEPLOYMENT_TARGET) +#endif + +#ifdef MAC_OS_X_VERSION_10_15 +DEFINE_IS_OS_FUNCS(15, TEST_DEPLOYMENT_TARGET) +#else +DEFINE_IS_OS_FUNCS(15, IGNORE_DEPLOYMENT_TARGET) +#endif + inline int Utils::CountLeadingZeros(uword x) { #if defined(ARCH_IS_32_BIT) return __builtin_clzl(x); diff --git a/runtime/vm/virtual_memory_posix.cc b/runtime/vm/virtual_memory_posix.cc index 2bcced12c7a..cf3e94a3fd4 100644 --- a/runtime/vm/virtual_memory_posix.cc +++ b/runtime/vm/virtual_memory_posix.cc @@ -194,6 +194,8 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size, // The mapping will be RX and stays that way until it will eventually be // unmapped. MemoryRegion region(region_ptr, size); + // DUAL_MAPPING_SUPPORTED is false in TARGET_OS_MACOS and hence support + // for MAP_JIT is not required here. const int alias_prot = PROT_READ | PROT_EXEC; void* alias_ptr = MapAligned(fd, alias_prot, size, alignment, allocated_size); @@ -211,8 +213,13 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size, const int prot = PROT_READ | PROT_WRITE | ((is_executable && !FLAG_write_protect_code) ? PROT_EXEC : 0); - void* address = - mmap(NULL, allocated_size, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + int map_flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(HOST_OS_MACOS) + if (IsAtLeastOS10_14()) { + map_flags |= MAP_JIT; + } +#endif // defined(HOST_OS_MACOS) + void* address = mmap(NULL, allocated_size, prot, map_flags, -1, 0); LOG_INFO("mmap(NULL, 0x%" Px ", %u, ...): %p\n", allocated_size, prot, address); if (address == MAP_FAILED) {