Index: include/llvm/Support/Memory.h =================================================================== --- include/llvm/Support/Memory.h +++ include/llvm/Support/Memory.h @@ -35,6 +35,7 @@ private: void *Address; ///< Address of first byte of memory area size_t Size; ///< Size, in bytes of the memory area + unsigned Flags = 0; friend class Memory; }; @@ -45,9 +46,11 @@ class Memory { public: enum ProtectionFlags { - MF_READ = 0x1000000, + MF_READ = 0x1000000, MF_WRITE = 0x2000000, - MF_EXEC = 0x4000000 + MF_EXEC = 0x4000000, + MF_RWE_MASK = 0x7000000, + MF_HUGE_HINT = 0x0000001 }; /// This method allocates a block of memory that is suitable for loading Index: lib/Support/Unix/Memory.inc =================================================================== --- lib/Support/Unix/Memory.inc +++ lib/Support/Unix/Memory.inc @@ -45,7 +45,7 @@ namespace { int getPosixProtectionFlags(unsigned Flags) { - switch (Flags) { + switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { case llvm::sys::Memory::MF_READ: return PROT_READ; case llvm::sys::Memory::MF_WRITE: Index: lib/Support/Windows/Memory.inc =================================================================== --- lib/Support/Windows/Memory.inc +++ lib/Support/Windows/Memory.inc @@ -22,7 +22,7 @@ namespace { DWORD getWindowsProtectionFlags(unsigned Flags) { - switch (Flags) { + switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { // Contrary to what you might expect, the Windows page protection flags // are not a bitwise combination of RWX values case llvm::sys::Memory::MF_READ: @@ -56,6 +56,31 @@ return Info.dwAllocationGranularity; } +size_t getLargePageSize() { + HANDLE Token = 0; + size_t LargePageMin = GetLargePageMinimum(); + if (LargePageMin) + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &Token); + if (Token) { + LUID Luid; + if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { + TOKEN_PRIVILEGES TP{}; + TP.PrivilegeCount = 1; + TP.Privileges[0].Luid = Luid; + TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { + DWORD E = GetLastError(); + if (E == ERROR_SUCCESS) { + return LargePageMin; + } + } + } + CloseHandle(Token); + } + return 0; +} + } // namespace namespace llvm { @@ -86,7 +111,14 @@ GranularityCached = Granularity; } - const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity; + static size_t LargePageSize = getLargePageSize(); + unsigned HugePages = + ((Flags & MF_HUGE_HINT) && LargePageSize) ? MEM_LARGE_PAGES : 0; + if (HugePages) { + Granularity = LargePageSize; + } + + size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; uintptr_t Start = NearBlock ? reinterpret_cast(NearBlock->base()) + NearBlock->size() @@ -101,11 +133,11 @@ void *PA = ::VirtualAlloc(reinterpret_cast(Start), NumBlocks*Granularity, - MEM_RESERVE | MEM_COMMIT, Protect); + MEM_RESERVE | MEM_COMMIT | HugePages, Protect); if (PA == NULL) { - if (NearBlock) { - // Try again without the NearBlock hint - return allocateMappedMemory(NumBytes, NULL, Flags, EC); + if (NearBlock || HugePages) { + // Try again without the NearBlock hint and without large memory pages + return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); } EC = mapWindowsError(::GetLastError()); return MemoryBlock(); @@ -114,6 +146,7 @@ MemoryBlock Result; Result.Address = PA; Result.Size = NumBlocks*Granularity; + Result.Flags = Flags; if (Flags & MF_EXEC) Memory::InvalidateInstructionCache(Result.Address, Result.Size); Index: unittests/Support/MemoryTest.cpp =================================================================== --- unittests/Support/MemoryTest.cpp +++ unittests/Support/MemoryTest.cpp @@ -105,6 +105,22 @@ EXPECT_FALSE(Memory::releaseMappedMemory(M1)); } +TEST_P(MappedMemoryTest, AllocAndReleaseHuge) { + CHECK_UNSUPPORTED(); + std::error_code EC; + MemoryBlock M1 = Memory::allocateMappedMemory( + sizeof(int), nullptr, Flags | Memory::MF_HUGE_HINT, EC); + EXPECT_EQ(std::error_code(), EC); + + // Test large/huge memory pages. In the worst case, 4kb pages should be + // returned, if large pages aren't available. + + EXPECT_NE((void *)nullptr, M1.base()); + EXPECT_LE(sizeof(int), M1.size()); + + EXPECT_FALSE(Memory::releaseMappedMemory(M1)); +} + TEST_P(MappedMemoryTest, MultipleAllocAndRelease) { CHECK_UNSUPPORTED(); std::error_code EC;