ExecutableAllocatorFixedVMPool.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Copyright (C) 2009 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #include "ExecutableAllocator.h"
  27. #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
  28. #include "CodeProfiling.h"
  29. #include <errno.h>
  30. #include <unistd.h>
  31. #include <wtf/MetaAllocator.h>
  32. #include <wtf/PageReservation.h>
  33. #include <wtf/VMTags.h>
  34. #if OS(PSP2)
  35. #include <manx/JitSecurity.h>
  36. #include <manx/Memblock.h>
  37. #endif
  38. #if OS(DARWIN)
  39. #include <sys/mman.h>
  40. #endif
  41. #if OS(LINUX)
  42. #include <stdio.h>
  43. #endif
  44. #if !PLATFORM(IOS) && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
  45. // MADV_FREE_REUSABLE does not work for JIT memory on older OSes so use MADV_FREE in that case.
  46. #define WTF_USE_MADV_FREE_FOR_JIT_MEMORY 1
  47. #endif
  48. using namespace WTF;
  49. namespace JSC {
  50. uintptr_t startOfFixedExecutableMemoryPool;
  51. class FixedVMPoolExecutableAllocator : public MetaAllocator {
  52. WTF_MAKE_FAST_ALLOCATED;
  53. public:
  54. FixedVMPoolExecutableAllocator()
  55. : MetaAllocator(jitAllocationGranule) // round up all allocations to 32 bytes
  56. {
  57. #if OS(PSP2)
  58. m_reservation = PageReservation::reserve(fixedExecutableMemoryPoolSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
  59. #else
  60. m_reservation = PageReservation::reserveWithGuardPages(fixedExecutableMemoryPoolSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
  61. #endif
  62. #if !ENABLE(LLINT)
  63. RELEASE_ASSERT(m_reservation);
  64. #endif
  65. if (m_reservation) {
  66. #if OS(PSP2)
  67. size_t hltSledSize = Manx::JitSecurity::execRegionPrologueHltSledSize();
  68. #if CPU(ARM_THUMB2)
  69. uint16_t * ip = reinterpret_cast<uint16_t*>(m_reservation.base());
  70. uint16_t hltInstruction = 0xb7b7;
  71. #else
  72. uint32_t * ip = reinterpret_cast<uint32_t*>(m_reservation.base());
  73. uint32_t hltInstruction = 0xb7b7b7b7;
  74. #endif
  75. Manx::Memblock::setWritable(true);
  76. for (size_t i = 0; i < hltSledSize; ++i) {
  77. *ip++ = hltInstruction;
  78. }
  79. Manx::Memblock::setWritable(false);
  80. RELEASE_ASSERT(fixedExecutableMemoryPoolSize > hltSledSize * sizeof(*ip));
  81. fixedExecutableMemoryPoolSize -= (hltSledSize * sizeof(*ip));
  82. startOfFixedExecutableMemoryPool = reinterpret_cast<uintptr_t>(ip);
  83. addFreshFreeSpace(reinterpret_cast<void*>(startOfFixedExecutableMemoryPool), fixedExecutableMemoryPoolSize);
  84. #else
  85. ASSERT(m_reservation.size() == fixedExecutableMemoryPoolSize);
  86. addFreshFreeSpace(m_reservation.base(), m_reservation.size());
  87. startOfFixedExecutableMemoryPool = reinterpret_cast<uintptr_t>(m_reservation.base());
  88. #endif
  89. }
  90. }
  91. DETACHED_JIT_VIRTUAL_DTOR ~FixedVMPoolExecutableAllocator();
  92. protected:
  93. virtual void* allocateNewSpace(size_t&)
  94. {
  95. // We're operating in a fixed pool, so new allocation is always prohibited.
  96. return 0;
  97. }
  98. virtual void notifyNeedPage(void* page)
  99. {
  100. #if USE(MADV_FREE_FOR_JIT_MEMORY)
  101. UNUSED_PARAM(page);
  102. #else
  103. m_reservation.commit(page, pageSize());
  104. #endif
  105. }
  106. virtual void notifyPageIsFree(void* page)
  107. {
  108. #if USE(MADV_FREE_FOR_JIT_MEMORY)
  109. for (;;) {
  110. int result = madvise(page, pageSize(), MADV_FREE);
  111. if (!result)
  112. return;
  113. ASSERT(result == -1);
  114. if (errno != EAGAIN) {
  115. RELEASE_ASSERT_NOT_REACHED(); // In debug mode, this should be a hard failure.
  116. break; // In release mode, we should just ignore the error - not returning memory to the OS is better than crashing, especially since we _will_ be able to reuse the memory internally anyway.
  117. }
  118. }
  119. #else
  120. m_reservation.decommit(page, pageSize());
  121. #endif
  122. }
  123. private:
  124. PageReservation m_reservation;
  125. };
  126. static FixedVMPoolExecutableAllocator* allocator;
  127. void ExecutableAllocator::initializeAllocator()
  128. {
  129. ASSERT(!allocator);
  130. allocator = new FixedVMPoolExecutableAllocator();
  131. CodeProfiling::notifyAllocator(allocator);
  132. }
  133. ExecutableAllocator::ExecutableAllocator(VM&)
  134. {
  135. ASSERT(allocator);
  136. }
  137. ExecutableAllocator::~ExecutableAllocator()
  138. {
  139. }
  140. FixedVMPoolExecutableAllocator::~FixedVMPoolExecutableAllocator()
  141. {
  142. m_reservation.deallocate();
  143. }
  144. bool ExecutableAllocator::isValid() const
  145. {
  146. return !!allocator->bytesReserved();
  147. }
  148. bool ExecutableAllocator::underMemoryPressure()
  149. {
  150. MetaAllocator::Statistics statistics = allocator->currentStatistics();
  151. return statistics.bytesAllocated > statistics.bytesReserved / 2;
  152. }
  153. double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage)
  154. {
  155. MetaAllocator::Statistics statistics = allocator->currentStatistics();
  156. ASSERT(statistics.bytesAllocated <= statistics.bytesReserved);
  157. size_t bytesAllocated = statistics.bytesAllocated + addedMemoryUsage;
  158. if (bytesAllocated >= statistics.bytesReserved)
  159. bytesAllocated = statistics.bytesReserved;
  160. double result = 1.0;
  161. size_t divisor = statistics.bytesReserved - bytesAllocated;
  162. if (divisor)
  163. result = static_cast<double>(statistics.bytesReserved) / divisor;
  164. if (result < 1.0)
  165. result = 1.0;
  166. return result;
  167. }
  168. PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(VM& vm, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort)
  169. {
  170. RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID);
  171. if (!result) {
  172. if (effort == JITCompilationCanFail)
  173. return result;
  174. releaseExecutableMemory(vm);
  175. result = allocator->allocate(sizeInBytes, ownerUID);
  176. RELEASE_ASSERT(result);
  177. }
  178. return result.release();
  179. }
  180. size_t ExecutableAllocator::committedByteCount()
  181. {
  182. return allocator->bytesCommitted();
  183. }
  184. #if ENABLE(META_ALLOCATOR_PROFILE)
  185. void ExecutableAllocator::dumpProfile()
  186. {
  187. allocator->dumpProfile();
  188. }
  189. #endif
  190. }
  191. #endif // ENABLE(EXECUTABLE_ALLOCATOR_FIXED)