brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.5 KiB · 93a3211 Raw
194 lines · plain
1//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides the Win32 specific implementation of various Memory10// management utilities11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Support/DataTypes.h"15#include "llvm/Support/ErrorHandling.h"16#include "llvm/Support/Process.h"17#include "llvm/Support/WindowsError.h"18 19// The Windows.h header must be the last one included.20#include "llvm/Support/Windows/WindowsSupport.h"21 22static DWORD getWindowsProtectionFlags(unsigned Flags) {23  switch (Flags & llvm::sys::Memory::MF_RWE_MASK) {24  // Contrary to what you might expect, the Windows page protection flags25  // are not a bitwise combination of RWX values26  case llvm::sys::Memory::MF_READ:27    return PAGE_READONLY;28  case llvm::sys::Memory::MF_WRITE:29    // Note: PAGE_WRITE is not supported by VirtualProtect30    return PAGE_READWRITE;31  case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE:32    return PAGE_READWRITE;33  case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_EXEC:34    return PAGE_EXECUTE_READ;35  case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE |36      llvm::sys::Memory::MF_EXEC:37    return PAGE_EXECUTE_READWRITE;38  case llvm::sys::Memory::MF_EXEC:39    return PAGE_EXECUTE;40  default:41    llvm_unreachable("Illegal memory protection flag specified!");42  }43  // Provide a default return value as required by some compilers.44  return PAGE_NOACCESS;45}46 47// While we'd be happy to allocate single pages, the Windows allocation48// granularity may be larger than a single page (in practice, it is 64K)49// so mapping less than that will create an unreachable fragment of memory.50static size_t getAllocationGranularity() {51  SYSTEM_INFO Info;52  ::GetSystemInfo(&Info);53  if (Info.dwPageSize > Info.dwAllocationGranularity)54    return Info.dwPageSize;55  else56    return Info.dwAllocationGranularity;57}58 59// Large/huge memory pages need explicit process permissions in order to be60// used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=1164361// Also large pages need to be manually enabled on your OS. If all this is62// sucessfull, we return the minimal large memory page size.63static size_t enableProcessLargePages() {64  HANDLE Token = 0;65  size_t LargePageMin = GetLargePageMinimum();66  if (LargePageMin)67    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,68                     &Token);69  if (!Token)70    return 0;71  LUID Luid;72  if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) {73    CloseHandle(Token);74    return 0;75  }76  TOKEN_PRIVILEGES TP{};77  TP.PrivilegeCount = 1;78  TP.Privileges[0].Luid = Luid;79  TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;80  if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) {81    CloseHandle(Token);82    return 0;83  }84  DWORD E = GetLastError();85  CloseHandle(Token);86  if (E == ERROR_SUCCESS)87    return LargePageMin;88  return 0;89}90 91namespace llvm {92namespace sys {93 94//===----------------------------------------------------------------------===//95//=== WARNING: Implementation here must contain only Win32 specific code96//===          and must not be UNIX code97//===----------------------------------------------------------------------===//98 99MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,100                                         const MemoryBlock *const NearBlock,101                                         unsigned Flags, std::error_code &EC) {102  EC = std::error_code();103  if (NumBytes == 0)104    return MemoryBlock();105 106  static size_t DefaultGranularity = getAllocationGranularity();107  static size_t LargePageGranularity = enableProcessLargePages();108 109  DWORD AllocType = MEM_RESERVE | MEM_COMMIT;110  bool HugePages = false;111  size_t Granularity = DefaultGranularity;112 113  if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) {114    AllocType |= MEM_LARGE_PAGES;115    HugePages = true;116    Granularity = LargePageGranularity;117  }118 119  size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity;120 121  uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +122                                    NearBlock->allocatedSize()123                              : 0;124 125  // If the requested address is not aligned to the allocation granularity,126  // round up to get beyond NearBlock. VirtualAlloc would have rounded down.127  if (Start && Start % Granularity != 0)128    Start += Granularity - Start % Granularity;129 130  DWORD Protect = getWindowsProtectionFlags(Flags);131 132  size_t AllocSize = NumBlocks * Granularity;133  void *PA = ::VirtualAlloc(reinterpret_cast<void *>(Start), AllocSize,134                            AllocType, Protect);135  if (PA == NULL) {136    if (NearBlock || HugePages) {137      // Try again without the NearBlock hint and without large memory pages138      return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC);139    }140    EC = mapWindowsError(::GetLastError());141    return MemoryBlock();142  }143 144  MemoryBlock Result;145  Result.Address = PA;146  Result.AllocatedSize = AllocSize;147  Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0);148 149  if (Flags & MF_EXEC)150    Memory::InvalidateInstructionCache(Result.Address, AllocSize);151 152  return Result;153}154 155std::error_code Memory::releaseMappedMemory(MemoryBlock &M) {156  if (M.Address == 0 || M.AllocatedSize == 0)157    return std::error_code();158 159  if (!VirtualFree(M.Address, 0, MEM_RELEASE))160    return mapWindowsError(::GetLastError());161 162  M.Address = 0;163  M.AllocatedSize = 0;164 165  return std::error_code();166}167 168std::error_code Memory::protectMappedMemory(const MemoryBlock &M,169                                            unsigned Flags) {170  if (M.Address == 0 || M.AllocatedSize == 0)171    return std::error_code();172 173  DWORD Protect = getWindowsProtectionFlags(Flags);174 175  DWORD OldFlags;176  if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags))177    return mapWindowsError(::GetLastError());178 179  if (Flags & MF_EXEC)180    Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize);181 182  return std::error_code();183}184 185/// InvalidateInstructionCache - Before the JIT can run a block of code186/// that has been emitted it must invalidate the instruction cache on some187/// platforms.188void Memory::InvalidateInstructionCache(const void *Addr, size_t Len) {189  FlushInstructionCache(GetCurrentProcess(), Addr, Len);190}191 192} // namespace sys193} // namespace llvm194