/ interpreter / CLoopStack.cpp
CLoopStack.cpp
1 /* 2 * Copyright (C) 2008-2017 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 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "CLoopStack.h" 31 32 #if ENABLE(C_LOOP) 33 34 #include "CLoopStackInlines.h" 35 #include "ConservativeRoots.h" 36 #include "Interpreter.h" 37 #include "JSCInlines.h" 38 #include "Options.h" 39 #include <wtf/Lock.h> 40 41 namespace JSC { 42 43 static size_t committedBytesCount = 0; 44 45 static size_t commitSize() 46 { 47 static size_t size = std::max<size_t>(16 * 1024, pageSize()); 48 return size; 49 } 50 51 static Lock stackStatisticsMutex; 52 53 CLoopStack::CLoopStack(VM& vm) 54 : m_vm(vm) 55 , m_topCallFrame(vm.topCallFrame) 56 , m_softReservedZoneSizeInRegisters(0) 57 { 58 size_t capacity = Options::maxPerThreadStackUsage(); 59 capacity = WTF::roundUpToMultipleOf(pageSize(), capacity); 60 ASSERT(capacity && isPageAligned(capacity)); 61 62 m_reservation = PageReservation::reserve(WTF::roundUpToMultipleOf(commitSize(), capacity), OSAllocator::UnknownUsage); 63 64 auto* bottomOfStack = highAddress(); 65 setCLoopStackLimit(bottomOfStack); 66 ASSERT(m_end == bottomOfStack); 67 m_commitTop = bottomOfStack; 68 m_lastStackPointer = bottomOfStack; 69 m_currentStackPointer = bottomOfStack; 70 71 m_topCallFrame = 0; 72 } 73 74 CLoopStack::~CLoopStack() 75 { 76 ptrdiff_t sizeToDecommit = reinterpret_cast<char*>(highAddress()) - reinterpret_cast<char*>(m_commitTop); 77 m_reservation.decommit(reinterpret_cast<void*>(m_commitTop), sizeToDecommit); 78 addToCommittedByteCount(-sizeToDecommit); 79 m_reservation.deallocate(); 80 } 81 82 bool CLoopStack::grow(Register* newTopOfStack) 83 { 84 Register* newTopOfStackWithReservedZone = newTopOfStack - m_softReservedZoneSizeInRegisters; 85 86 // If we have already committed enough memory to satisfy this request, 87 // just update the end pointer and return. 88 if (newTopOfStackWithReservedZone >= m_commitTop) { 89 setCLoopStackLimit(newTopOfStack); 90 return true; 91 } 92 93 // Compute the chunk size of additional memory to commit, and see if we 94 // have it still within our budget. If not, we'll fail to grow and 95 // return false. 96 ptrdiff_t delta = reinterpret_cast<char*>(m_commitTop) - reinterpret_cast<char*>(newTopOfStackWithReservedZone); 97 delta = WTF::roundUpToMultipleOf(commitSize(), delta); 98 Register* newCommitTop = m_commitTop - (delta / sizeof(Register)); 99 if (newCommitTop < reservationTop()) 100 return false; 101 102 // Otherwise, the growth is still within our budget. Commit it and return true. 103 m_reservation.commit(newCommitTop, delta); 104 addToCommittedByteCount(delta); 105 m_commitTop = newCommitTop; 106 newTopOfStack = m_commitTop + m_softReservedZoneSizeInRegisters; 107 setCLoopStackLimit(newTopOfStack); 108 return true; 109 } 110 111 void CLoopStack::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks) 112 { 113 conservativeRoots.add(currentStackPointer(), highAddress(), jitStubRoutines, codeBlocks); 114 } 115 116 void CLoopStack::sanitizeStack() 117 { 118 #if !ASAN_ENABLED 119 void* stackTop = currentStackPointer(); 120 ASSERT(stackTop <= highAddress()); 121 if (m_lastStackPointer < stackTop) { 122 char* begin = reinterpret_cast<char*>(m_lastStackPointer); 123 char* end = reinterpret_cast<char*>(stackTop); 124 memset(begin, 0, end - begin); 125 } 126 127 m_lastStackPointer = stackTop; 128 #endif 129 } 130 131 void CLoopStack::releaseExcessCapacity() 132 { 133 Register* highAddressWithReservedZone = highAddress() - m_softReservedZoneSizeInRegisters; 134 ptrdiff_t delta = reinterpret_cast<char*>(highAddressWithReservedZone) - reinterpret_cast<char*>(m_commitTop); 135 m_reservation.decommit(m_commitTop, delta); 136 addToCommittedByteCount(-delta); 137 m_commitTop = highAddressWithReservedZone; 138 } 139 140 void CLoopStack::addToCommittedByteCount(long byteCount) 141 { 142 LockHolder locker(stackStatisticsMutex); 143 ASSERT(static_cast<long>(committedBytesCount) + byteCount > -1); 144 committedBytesCount += byteCount; 145 } 146 147 void CLoopStack::setSoftReservedZoneSize(size_t reservedZoneSize) 148 { 149 m_softReservedZoneSizeInRegisters = reservedZoneSize / sizeof(Register); 150 if (m_commitTop > m_end - m_softReservedZoneSizeInRegisters) 151 grow(m_end); 152 } 153 154 bool CLoopStack::isSafeToRecurse() const 155 { 156 void* reservationLimit = reinterpret_cast<int8_t*>(reservationTop() + m_softReservedZoneSizeInRegisters); 157 return !m_topCallFrame || (m_topCallFrame->topOfFrame() > reservationLimit); 158 } 159 160 size_t CLoopStack::committedByteCount() 161 { 162 LockHolder locker(stackStatisticsMutex); 163 return committedBytesCount; 164 } 165 166 } // namespace JSC 167 168 #endif // ENABLE(C_LOOP)