testapi test crashes on Windows in WTF::Vector<wchar_t,64,WTF::UnsafeVectorOverflow...
[WebKit-https.git] / Source / JavaScriptCore / interpreter / JSStack.cpp
1 /*
2  * Copyright (C) 2008, 2013 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 Computer, 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 "JSStackInlines.h"
31
32 #include "ConservativeRoots.h"
33 #include "Interpreter.h"
34
35 namespace JSC {
36
37 static size_t committedBytesCount = 0;
38
39 static Mutex& stackStatisticsMutex()
40 {
41     DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
42     return staticMutex;
43 }    
44
45 JSStack::JSStack(VM& vm, size_t capacity)
46     : m_vm(vm)
47     , m_end(0)
48     , m_topCallFrame(vm.topCallFrame)
49 {
50     ASSERT(capacity && isPageAligned(capacity));
51
52     m_reservation = PageReservation::reserve(roundUpAllocationSize(capacity * sizeof(Register), commitSize), OSAllocator::JSVMStackPages);
53     updateStackLimit(highAddress());
54     m_commitEnd = highAddress();
55     
56     m_lastStackTop = getBaseOfStack();
57
58     disableErrorStackReserve();
59
60     m_topCallFrame = 0;
61 }
62
63 JSStack::~JSStack()
64 {
65     void* highAddress = reinterpret_cast<void*>(static_cast<char*>(m_reservation.base()) + m_reservation.size());
66     if (highAddress > m_commitEnd) {
67         m_reservation.decommit(reinterpret_cast<void*>(m_commitEnd), reinterpret_cast<intptr_t>(highAddress) - reinterpret_cast<intptr_t>(m_commitEnd));
68         addToCommittedByteCount(-(reinterpret_cast<intptr_t>(highAddress) - reinterpret_cast<intptr_t>(m_commitEnd)));
69     }
70     m_reservation.deallocate();
71 }
72
73 bool JSStack::growSlowCase(Register* newEnd)
74 {
75     // If we have already committed enough memory to satisfy this request,
76     // just update the end pointer and return.
77     if (newEnd >= m_commitEnd) {
78         updateStackLimit(newEnd);
79         return true;
80     }
81
82     // Compute the chunk size of additional memory to commit, and see if we
83     // have it is still within our budget. If not, we'll fail to grow and
84     // return false.
85     long delta = roundUpAllocationSize(reinterpret_cast<char*>(m_commitEnd) - reinterpret_cast<char*>(newEnd), commitSize);
86     if (reinterpret_cast<char*>(m_commitEnd) - delta <= reinterpret_cast<char*>(m_useableEnd))
87         return false;
88
89     // Otherwise, the growth is still within our budget. Go ahead and commit
90     // it and return true.
91     m_reservation.commit(reinterpret_cast<char*>(m_commitEnd) - delta, delta);
92     addToCommittedByteCount(delta);
93     m_commitEnd = reinterpret_cast_ptr<Register*>(reinterpret_cast<char*>(m_commitEnd) - delta);
94     updateStackLimit(newEnd);
95     return true;
96 }
97
98 void JSStack::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
99 {
100     conservativeRoots.add(getBaseOfStack(), getTopOfStack());
101 }
102
103 void JSStack::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks)
104 {
105     conservativeRoots.add(getBaseOfStack(), getTopOfStack(), jitStubRoutines, codeBlocks);
106 }
107
108 void JSStack::sanitizeStack()
109 {
110     ASSERT(getTopOfStack() <= getBaseOfStack());
111     
112     if (m_lastStackTop < getTopOfStack()) {
113         char* begin = reinterpret_cast<char*>(m_lastStackTop);
114         char* end = reinterpret_cast<char*>(getTopOfStack());
115         memset(begin, 0, end - begin);
116     }
117     
118     m_lastStackTop = getTopOfStack();
119 }
120
121 void JSStack::releaseExcessCapacity()
122 {
123     ptrdiff_t delta = reinterpret_cast<uintptr_t>(highAddress()) - reinterpret_cast<uintptr_t>(m_commitEnd);
124     m_reservation.decommit(m_commitEnd, delta);
125     addToCommittedByteCount(-delta);
126     m_commitEnd = highAddress();
127 }
128
129 void JSStack::initializeThreading()
130 {
131     stackStatisticsMutex();
132 }
133
134 size_t JSStack::committedByteCount()
135 {
136     MutexLocker locker(stackStatisticsMutex());
137     return committedBytesCount;
138 }
139
140 void JSStack::addToCommittedByteCount(long byteCount)
141 {
142     MutexLocker locker(stackStatisticsMutex());
143     ASSERT(static_cast<long>(committedBytesCount) + byteCount > -1);
144     committedBytesCount += byteCount;
145 }
146
147 void JSStack::enableErrorStackReserve()
148 {
149     m_useableEnd = reservationEnd();
150 }
151
152 void JSStack::disableErrorStackReserve()
153 {
154     char* useableEnd = reinterpret_cast<char*>(reservationEnd()) + commitSize;
155     m_useableEnd = reinterpret_cast_ptr<Register*>(useableEnd);
156
157     // By the time we get here, we are guaranteed to be destructing the last
158     // Interpreter::ErrorHandlingMode that enabled this reserve in the first
159     // place. That means the stack space beyond m_useableEnd before we
160     // enabled the reserve was not previously in use. Hence, it is safe to
161     // shrink back to that m_useableEnd.
162     if (m_end < m_useableEnd) {
163         ASSERT(m_topCallFrame->frameExtent() >= m_useableEnd);
164         shrink(m_useableEnd);
165     }
166 }
167
168 } // namespace JSC