diff options
author | Derek Schuff <dschuff@chromium.org> | 2012-09-25 17:30:25 -0700 |
---|---|---|
committer | Derek Schuff <dschuff@chromium.org> | 2012-09-25 18:01:23 -0700 |
commit | a27c28b1427dc2082ab2b31efdbb25f9fde31b61 (patch) | |
tree | 6f3ff025f542ca3f66a1a01cbf239aeef7784511 /lib/Support | |
parent | 0e15ffd8cb1ec642eddb96380660914ff2b007e1 (diff) | |
parent | bc4021f31eaa97ee52655828da3e3de14a39e4a6 (diff) |
Merge commit 'bc4021f31eaa97ee52655828da3e3de14a39e4a6'
Conflicts:
lib/MC/MCAssembler.cpp
lib/Target/ARM/ARMISelDAGToDAG.cpp
lib/Target/Mips/MipsInstrFPU.td
lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
lib/Target/X86/X86ISelLowering.h
Diffstat (limited to 'lib/Support')
-rw-r--r-- | lib/Support/DAGDeltaAlgorithm.cpp | 10 | ||||
-rw-r--r-- | lib/Support/DataStream.cpp | 2 | ||||
-rw-r--r-- | lib/Support/Host.cpp | 1 | ||||
-rw-r--r-- | lib/Support/Memory.cpp | 52 | ||||
-rw-r--r-- | lib/Support/MemoryBuffer.cpp | 10 | ||||
-rw-r--r-- | lib/Support/StreamableMemoryObject.cpp | 24 | ||||
-rw-r--r-- | lib/Support/Unix/Memory.inc | 202 | ||||
-rw-r--r-- | lib/Support/Unix/Signals.inc | 2 | ||||
-rw-r--r-- | lib/Support/Windows/Memory.inc | 165 | ||||
-rw-r--r-- | lib/Support/system_error.cpp | 10 |
10 files changed, 362 insertions, 116 deletions
diff --git a/lib/Support/DAGDeltaAlgorithm.cpp b/lib/Support/DAGDeltaAlgorithm.cpp index 1e89c6ad2f..34e82cf441 100644 --- a/lib/Support/DAGDeltaAlgorithm.cpp +++ b/lib/Support/DAGDeltaAlgorithm.cpp @@ -122,7 +122,7 @@ private: DDA.UpdatedSearchState(Changes, Sets, Required); } - /// ExecuteOneTest - Execute a single test predicate on the change set \arg S. + /// ExecuteOneTest - Execute a single test predicate on the change set \p S. bool ExecuteOneTest(const changeset_ty &S) { // Check dependencies invariant. DEBUG({ @@ -143,8 +143,8 @@ public: changeset_ty Run(); - /// GetTestResult - Get the test result for the active set \arg Changes with - /// \arg Required changes from the cache, executing the test if necessary. + /// GetTestResult - Get the test result for the active set \p Changes with + /// \p Required changes from the cache, executing the test if necessary. /// /// \param Changes - The set of active changes being minimized, which should /// have their pred closure included in the test. @@ -163,11 +163,11 @@ class DeltaActiveSetHelper : public DeltaAlgorithm { protected: /// UpdatedSearchState - Callback used when the search state changes. virtual void UpdatedSearchState(const changeset_ty &Changes, - const changesetlist_ty &Sets) { + const changesetlist_ty &Sets) LLVM_OVERRIDE { DDAI.UpdatedSearchState(Changes, Sets, Required); } - virtual bool ExecuteOneTest(const changeset_ty &S) { + virtual bool ExecuteOneTest(const changeset_ty &S) LLVM_OVERRIDE { return DDAI.GetTestResult(S, Required); } diff --git a/lib/Support/DataStream.cpp b/lib/Support/DataStream.cpp index 94d14a5e36..3a38e2a66b 100644 --- a/lib/Support/DataStream.cpp +++ b/lib/Support/DataStream.cpp @@ -58,7 +58,7 @@ public: virtual ~DataFileStreamer() { close(Fd); } - virtual size_t GetBytes(unsigned char *buf, size_t len) { + virtual size_t GetBytes(unsigned char *buf, size_t len) LLVM_OVERRIDE { NumStreamFetches++; return read(Fd, buf, len); } diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index 9a2c39d72e..a13b9e2f87 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -303,6 +303,7 @@ std::string sys::getHostCPUName() { case 8: return "k6-2"; case 9: case 13: return "k6-3"; + case 10: return "geode"; default: return "pentium"; } case 6: diff --git a/lib/Support/Memory.cpp b/lib/Support/Memory.cpp index 3cc8f5ee7b..12f083822f 100644 --- a/lib/Support/Memory.cpp +++ b/lib/Support/Memory.cpp @@ -16,10 +16,6 @@ #include "llvm/Support/Valgrind.h" #include "llvm/Config/config.h" -namespace llvm { -using namespace sys; -} - // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Memory.inc" @@ -27,51 +23,3 @@ using namespace sys; #ifdef LLVM_ON_WIN32 #include "Windows/Memory.inc" #endif - -extern "C" void sys_icache_invalidate(const void *Addr, size_t len); - -/// InvalidateInstructionCache - Before the JIT can run a block of code -/// that has been emitted it must invalidate the instruction cache on some -/// platforms. -void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, - size_t Len) { - -// icache invalidation for PPC and ARM. -#if defined(__APPLE__) - -# if (defined(__POWERPC__) || defined (__ppc__) || \ - defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) - sys_icache_invalidate(const_cast<void *>(Addr), Len); -# endif - -#else - -# if (defined(__POWERPC__) || defined (__ppc__) || \ - defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) - const size_t LineSize = 32; - - const intptr_t Mask = ~(LineSize - 1); - const intptr_t StartLine = ((intptr_t) Addr) & Mask; - const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; - - for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) - asm volatile("dcbf 0, %0" : : "r"(Line)); - asm volatile("sync"); - - for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) - asm volatile("icbi 0, %0" : : "r"(Line)); - asm volatile("isync"); -# elif defined(__arm__) && defined(__GNUC__) - // FIXME: Can we safely always call this for __GNUC__ everywhere? - const char *Start = static_cast<const char *>(Addr); - const char *End = Start + Len; - __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); -# elif defined(__mips__) - const char *Start = static_cast<const char *>(Addr); - cacheflush(const_cast<char *>(Start), Len, BCACHE); -# endif - -#endif // end apple - - ValgrindDiscardTranslations(Addr, Len); -} diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index 61d51b6b48..8b009b84a5 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -81,12 +81,12 @@ public: init(InputData.begin(), InputData.end(), RequiresNullTerminator); } - virtual const char *getBufferIdentifier() const { + virtual const char *getBufferIdentifier() const LLVM_OVERRIDE { // The name is stored after the class itself. return reinterpret_cast<const char*>(this + 1); } - - virtual BufferKind getBufferKind() const { + + virtual BufferKind getBufferKind() const LLVM_OVERRIDE { return MemoryBuffer_Malloc; } }; @@ -194,8 +194,8 @@ public: sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart), RealSize); } - - virtual BufferKind getBufferKind() const { + + virtual BufferKind getBufferKind() const LLVM_OVERRIDE { return MemoryBuffer_MMap; } }; diff --git a/lib/Support/StreamableMemoryObject.cpp b/lib/Support/StreamableMemoryObject.cpp index fe3752a77a..59e27a263e 100644 --- a/lib/Support/StreamableMemoryObject.cpp +++ b/lib/Support/StreamableMemoryObject.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/StreamableMemoryObject.h" +#include "llvm/Support/Compiler.h" #include <cassert> #include <cstring> @@ -23,18 +24,23 @@ public: assert(LastChar >= FirstChar && "Invalid start/end range"); } - virtual uint64_t getBase() const { return 0; } - virtual uint64_t getExtent() const { return LastChar - FirstChar; } - virtual int readByte(uint64_t address, uint8_t* ptr) const; + virtual uint64_t getBase() const LLVM_OVERRIDE { return 0; } + virtual uint64_t getExtent() const LLVM_OVERRIDE { + return LastChar - FirstChar; + } + virtual int readByte(uint64_t address, uint8_t* ptr) const LLVM_OVERRIDE; virtual int readBytes(uint64_t address, uint64_t size, uint8_t* buf, - uint64_t* copied) const; - virtual const uint8_t *getPointer(uint64_t address, uint64_t size) const; - virtual bool isValidAddress(uint64_t address) const { + uint64_t* copied) const LLVM_OVERRIDE; + virtual const uint8_t *getPointer(uint64_t address, + uint64_t size) const LLVM_OVERRIDE; + virtual bool isValidAddress(uint64_t address) const LLVM_OVERRIDE { return validAddress(address); } - virtual bool isObjectEnd(uint64_t address) const {return objectEnd(address);} + virtual bool isObjectEnd(uint64_t address) const LLVM_OVERRIDE { + return objectEnd(address); + } private: const uint8_t* const FirstChar; @@ -49,8 +55,8 @@ private: return static_cast<ptrdiff_t>(address) == LastChar - FirstChar; } - RawMemoryObject(const RawMemoryObject&); // DO NOT IMPLEMENT - void operator=(const RawMemoryObject&); // DO NOT IMPLEMENT + RawMemoryObject(const RawMemoryObject&) LLVM_DELETED_FUNCTION; + void operator=(const RawMemoryObject&) LLVM_DELETED_FUNCTION; }; int RawMemoryObject::readByte(uint64_t address, uint8_t* ptr) const { diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc index 7136acf6cf..f4cfbc65cf 100644 --- a/lib/Support/Unix/Memory.inc +++ b/lib/Support/Unix/Memory.inc @@ -14,6 +14,7 @@ #include "Unix.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Process.h" #include "llvm/Support/Debug.h" @@ -33,14 +34,142 @@ # endif #endif +extern "C" void sys_icache_invalidate(const void *Addr, size_t len); + +namespace { + +int getPosixProtectionFlags(unsigned Flags) { + switch (Flags) { + case llvm::sys::Memory::MF_READ: + return PROT_READ; + case llvm::sys::Memory::MF_WRITE: + return PROT_WRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: + return PROT_READ | PROT_WRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: + return PROT_READ | PROT_EXEC; + case llvm::sys::Memory::MF_READ | + llvm::sys::Memory::MF_WRITE | + llvm::sys::Memory::MF_EXEC: + return PROT_READ | PROT_WRITE | PROT_EXEC; + case llvm::sys::Memory::MF_EXEC: + return PROT_EXEC; + default: + llvm_unreachable("Illegal memory protection flag specified!"); + } + // Provide a default return value as required by some compilers. + return PROT_NONE; +} + +} // namespace + +namespace llvm { +namespace sys { + +MemoryBlock +Memory::allocateMappedMemory(size_t NumBytes, + const MemoryBlock *const NearBlock, + unsigned PFlags, + error_code &EC) { + EC = error_code::success(); + if (NumBytes == 0) + return MemoryBlock(); + + static const size_t PageSize = Process::GetPageSize(); + const size_t NumPages = (NumBytes+PageSize-1)/PageSize; + + int fd = -1; +#ifdef NEED_DEV_ZERO_FOR_MMAP + static int zero_fd = open("/dev/zero", O_RDWR); + if (zero_fd == -1) { + EC = error_code(errno, system_category()); + return MemoryBlock(); + } + fd = zero_fd; +#endif + + int MMFlags = MAP_PRIVATE | +#ifdef HAVE_MMAP_ANONYMOUS + MAP_ANONYMOUS +#else + MAP_ANON +#endif + ; // Ends statement above + + int Protect = getPosixProtectionFlags(PFlags); + + // Use any near hint and the page size to set a page-aligned starting address + uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + + NearBlock->size() : 0; + if (Start && Start % PageSize) + Start += PageSize - Start % PageSize; + + void *Addr = ::mmap(reinterpret_cast<void*>(Start), PageSize*NumPages, + Protect, MMFlags, fd, 0); + if (Addr == MAP_FAILED) { + if (NearBlock) //Try again without a near hint + return allocateMappedMemory(NumBytes, 0, PFlags, EC); + + EC = error_code(errno, system_category()); + return MemoryBlock(); + } + + MemoryBlock Result; + Result.Address = Addr; + Result.Size = NumPages*PageSize; + + if (PFlags & MF_EXEC) + Memory::InvalidateInstructionCache(Result.Address, Result.Size); + + return Result; +} + +error_code +Memory::releaseMappedMemory(MemoryBlock &M) { + if (M.Address == 0 || M.Size == 0) + return error_code::success(); + + if (0 != ::munmap(M.Address, M.Size)) + return error_code(errno, system_category()); + + M.Address = 0; + M.Size = 0; + + return error_code::success(); +} + +error_code +Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { + if (M.Address == 0 || M.Size == 0) + return error_code::success(); + + if (!Flags) + return error_code(EINVAL, generic_category()); + + int Protect = getPosixProtectionFlags(Flags); +#ifndef __native_client__ + int Result = ::mprotect(M.Address, M.Size, Protect); +#else + int Result = -1; + llvm_unreachable("Native client does not support mprotect"); +#endif + if (Result != 0) + return error_code(errno, system_category()); + + if (Flags & MF_EXEC) + Memory::InvalidateInstructionCache(M.Address, M.Size); + + return error_code::success(); +} + /// AllocateRWX - Allocate a slab of memory with read/write/execute /// permissions. This is typically used for JIT applications where we want /// to emit code to the memory then jump to it. Getting this type of memory /// is very OS specific. /// -llvm::sys::MemoryBlock -llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, - std::string *ErrMsg) { +MemoryBlock +Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, + std::string *ErrMsg) { if (NumBytes == 0) return MemoryBlock(); size_t pageSize = Process::GetPageSize(); @@ -90,7 +219,7 @@ dbgs() << "calling mmap, start " << start << "\n"; VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); if (KERN_SUCCESS != kr) { MakeErrMsg(ErrMsg, "vm_protect max RX failed"); - return sys::MemoryBlock(); + return MemoryBlock(); } kr = vm_protect(mach_task_self(), (vm_address_t)pa, @@ -98,7 +227,7 @@ dbgs() << "calling mmap, start " << start << "\n"; VM_PROT_READ | VM_PROT_WRITE); if (KERN_SUCCESS != kr) { MakeErrMsg(ErrMsg, "vm_protect RW failed"); - return sys::MemoryBlock(); + return MemoryBlock(); } #endif @@ -109,17 +238,17 @@ dbgs() << "calling mmap, start " << start << "\n"; return result; } -bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { +bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { if (M.Address == 0 || M.Size == 0) return false; if (0 != ::munmap(M.Address, M.Size)) return MakeErrMsg(ErrMsg, "Can't release RWX Memory"); return false; } -bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { +bool Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { #if defined(__APPLE__) && defined(__arm__) if (M.Address == 0 || M.Size == 0) return false; - sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + Memory::InvalidateInstructionCache(M.Address, M.Size); kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE); return KERN_SUCCESS == kr; @@ -128,10 +257,10 @@ bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { #endif } -bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { +bool Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { #if defined(__APPLE__) && defined(__arm__) if (M.Address == 0 || M.Size == 0) return false; - sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + Memory::InvalidateInstructionCache(M.Address, M.Size); kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); return KERN_SUCCESS == kr; @@ -140,7 +269,7 @@ bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { #endif } -bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { +bool Memory::setRangeWritable(const void *Addr, size_t Size) { #if defined(__APPLE__) && defined(__arm__) kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, (vm_size_t)Size, 0, @@ -151,7 +280,7 @@ bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { #endif } -bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { +bool Memory::setRangeExecutable(const void *Addr, size_t Size) { #if defined(__APPLE__) && defined(__arm__) kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, (vm_size_t)Size, 0, @@ -161,3 +290,52 @@ bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { return true; #endif } + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void Memory::InvalidateInstructionCache(const void *Addr, + size_t Len) { + +// icache invalidation for PPC and ARM. +#if defined(__APPLE__) + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) + sys_icache_invalidate(const_cast<void *>(Addr), Len); +# endif + +#else + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) + const size_t LineSize = 32; + + const intptr_t Mask = ~(LineSize - 1); + const intptr_t StartLine = ((intptr_t) Addr) & Mask; + const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("dcbf 0, %0" : : "r"(Line)); + asm volatile("sync"); + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("icbi 0, %0" : : "r"(Line)); + asm volatile("isync"); +# elif defined(__arm__) && defined(__GNUC__) + // FIXME: Can we safely always call this for __GNUC__ everywhere? + const char *Start = static_cast<const char *>(Addr); + const char *End = Start + Len; + __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); +# elif defined(__mips__) + const char *Start = static_cast<const char *>(Addr); + cacheflush(const_cast<char *>(Start), Len, BCACHE); +# endif + +#endif // end apple + + ValgrindDiscardTranslations(Addr, Len); +} + +} // namespace sys +} // namespace llvm diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc index 704f4681bc..e05e81acaf 100644 --- a/lib/Support/Unix/Signals.inc +++ b/lib/Support/Unix/Signals.inc @@ -249,7 +249,7 @@ void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { // On glibc systems we have the 'backtrace' function, which works nicely, but // doesn't demangle symbols. static void PrintStackTrace(void *) { -#ifdef HAVE_BACKTRACE +#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACE) static void* StackTrace[256]; // Use backtrace() to output a backtrace on Linux systems with glibc. int depth = backtrace(StackTrace, diff --git a/lib/Support/Windows/Memory.inc b/lib/Support/Windows/Memory.inc index fcc72837c4..cb80f2817c 100644 --- a/lib/Support/Windows/Memory.inc +++ b/lib/Support/Windows/Memory.inc @@ -12,51 +12,163 @@ // //===----------------------------------------------------------------------===// -#include "Windows.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Process.h" +#include "Windows.h" + +namespace { + +DWORD getWindowsProtectionFlags(unsigned Flags) { + switch (Flags) { + // 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: + return PAGE_READONLY; + case llvm::sys::Memory::MF_WRITE: + // Note: PAGE_WRITE is not supported by VirtualProtect + return PAGE_READWRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: + return PAGE_READWRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE_READ; + case llvm::sys::Memory::MF_READ | + llvm::sys::Memory::MF_WRITE | + llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE_READWRITE; + case llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE; + default: + llvm_unreachable("Illegal memory protection flag specified!"); + } + // Provide a default return value as required by some compilers. + return PAGE_NOACCESS; +} + +size_t getAllocationGranularity() { + SYSTEM_INFO Info; + ::GetSystemInfo(&Info); + if (Info.dwPageSize > Info.dwAllocationGranularity) + return Info.dwPageSize; + else + return Info.dwAllocationGranularity; +} + +} // namespace namespace llvm { -using namespace sys; +namespace sys { //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code //===----------------------------------------------------------------------===// -MemoryBlock Memory::AllocateRWX(size_t NumBytes, - const MemoryBlock *NearBlock, - std::string *ErrMsg) { - if (NumBytes == 0) return MemoryBlock(); +MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, + const MemoryBlock *const NearBlock, + unsigned Flags, + error_code &EC) { + EC = error_code::success(); + if (NumBytes == 0) + return MemoryBlock(); + + // While we'd be happy to allocate single pages, the Windows allocation + // granularity may be larger than a single page (in practice, it is 64K) + // so mapping less than that will create an unreachable fragment of memory. + static const size_t Granularity = getAllocationGranularity(); + const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity; - static const size_t pageSize = Process::GetPageSize(); - size_t NumPages = (NumBytes+pageSize-1)/pageSize; + uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + + NearBlock->size() + : NULL; - PVOID start = NearBlock ? static_cast<unsigned char *>(NearBlock->base()) + - NearBlock->size() : NULL; + // If the requested address is not aligned to the allocation granularity, + // round up to get beyond NearBlock. VirtualAlloc would have rounded down. + if (Start && Start % Granularity != 0) + Start += Granularity - Start % Granularity; - void *pa = VirtualAlloc(start, NumPages*pageSize, MEM_RESERVE | MEM_COMMIT, - PAGE_EXECUTE_READWRITE); - if (pa == NULL) { + DWORD Protect = getWindowsProtectionFlags(Flags); + + void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start), + NumBlocks*Granularity, + MEM_RESERVE | MEM_COMMIT, Protect); + if (PA == NULL) { if (NearBlock) { // Try again without the NearBlock hint - return AllocateRWX(NumBytes, NULL, ErrMsg); + return allocateMappedMemory(NumBytes, NULL, Flags, EC); } - MakeErrMsg(ErrMsg, "Can't allocate RWX Memory: "); + EC = error_code(::GetLastError(), system_category()); return MemoryBlock(); } - MemoryBlock result; - result.Address = pa; - result.Size = NumPages*pageSize; - return result; + MemoryBlock Result; + Result.Address = PA; + Result.Size = NumBlocks*Granularity; + ; + if (Flags & MF_EXEC) + Memory::InvalidateInstructionCache(Result.Address, Result.Size); + + return Result; } -bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { - if (M.Address == 0 || M.Size == 0) return false; +error_code Memory::releaseMappedMemory(MemoryBlock &M) { + if (M.Address == 0 || M.Size == 0) + return error_code::success(); + if (!VirtualFree(M.Address, 0, MEM_RELEASE)) - return MakeErrMsg(ErrMsg, "Can't release RWX Memory: "); - return false; + return error_code(::GetLastError(), system_category()); + + M.Address = 0; + M.Size = 0; + + return error_code::success(); +} + +error_code Memory::protectMappedMemory(const MemoryBlock &M, + unsigned Flags) { + if (M.Address == 0 || M.Size == 0) + return error_code::success(); + + DWORD Protect = getWindowsProtectionFlags(Flags); + + DWORD OldFlags; + if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags)) + return error_code(::GetLastError(), system_category()); + + if (Flags & MF_EXEC) + Memory::InvalidateInstructionCache(M.Address, M.Size); + + return error_code::success(); +} + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void Memory::InvalidateInstructionCache( + const void *Addr, size_t Len) { + FlushInstructionCache(GetCurrentProcess(), Addr, Len); +} + + +MemoryBlock Memory::AllocateRWX(size_t NumBytes, + const MemoryBlock *NearBlock, + std::string *ErrMsg) { + MemoryBlock MB; + error_code EC; + MB = allocateMappedMemory(NumBytes, NearBlock, + MF_READ|MF_WRITE|MF_EXEC, EC); + if (EC != error_code::success() && ErrMsg) { + MakeErrMsg(ErrMsg, EC.message()); + } + return MB; +} + +bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { + error_code EC = releaseMappedMemory(M); + if (EC == error_code::success()) + return false; + MakeErrMsg(ErrMsg, EC.message()); + return true; } static DWORD getProtection(const void *addr) { @@ -93,7 +205,7 @@ bool Memory::setRangeWritable(const void *Addr, size_t Size) { } DWORD oldProt; - sys::Memory::InvalidateInstructionCache(Addr, Size); + Memory::InvalidateInstructionCache(Addr, Size); return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) == TRUE; } @@ -112,9 +224,10 @@ bool Memory::setRangeExecutable(const void *Addr, size_t Size) { } DWORD oldProt; - sys::Memory::InvalidateInstructionCache(Addr, Size); + Memory::InvalidateInstructionCache(Addr, Size); return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) == TRUE; } -} +} // namespace sys +} // namespace llvm diff --git a/lib/Support/system_error.cpp b/lib/Support/system_error.cpp index 56898de315..2df223ca71 100644 --- a/lib/Support/system_error.cpp +++ b/lib/Support/system_error.cpp @@ -48,8 +48,8 @@ _do_message::message(int ev) const { class _generic_error_category : public _do_message { public: - virtual const char* name() const; - virtual std::string message(int ev) const; + virtual const char* name() const LLVM_OVERRIDE; + virtual std::string message(int ev) const LLVM_OVERRIDE; }; const char* @@ -74,9 +74,9 @@ generic_category() { class _system_error_category : public _do_message { public: - virtual const char* name() const; - virtual std::string message(int ev) const; - virtual error_condition default_error_condition(int ev) const; + virtual const char* name() const LLVM_OVERRIDE; + virtual std::string message(int ev) const LLVM_OVERRIDE; + virtual error_condition default_error_condition(int ev) const LLVM_OVERRIDE; }; const char* |