Introducing VMEntryScope to update the VM stack limit.
[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     disableErrorStackReserve();
57
58     m_topCallFrame = 0;
59 }
60
61 JSStack::~JSStack()
62 {
63     void* highAddress = reinterpret_cast<void*>(static_cast<char*>(m_reservation.base()) + m_reservation.size());
64     m_reservation.decommit(reinterpret_cast<void*>(m_commitEnd), reinterpret_cast<intptr_t>(highAddress) - reinterpret_cast<intptr_t>(m_commitEnd));
65     addToCommittedByteCount(-(reinterpret_cast<intptr_t>(highAddress) - reinterpret_cast<intptr_t>(m_commitEnd)));
66     m_reservation.deallocate();
67 }
68
69 bool JSStack::growSlowCase(Register* newEnd)
70 {
71     // If we have already committed enough memory to satisfy this request,
72     // just update the end pointer and return.
73     if (newEnd >= m_commitEnd) {
74         updateStackLimit(newEnd);
75         return true;
76     }
77
78     // Compute the chunk size of additional memory to commit, and see if we
79     // have it is still within our budget. If not, we'll fail to grow and
80     // return false.
81     long delta = roundUpAllocationSize(reinterpret_cast<char*>(m_commitEnd) - reinterpret_cast<char*>(newEnd), commitSize);
82     if (reinterpret_cast<char*>(m_commitEnd) - delta <= reinterpret_cast<char*>(m_useableEnd))
83         return false;
84
85     // Otherwise, the growth is still within our budget. Go ahead and commit
86     // it and return true.
87     m_reservation.commit(reinterpret_cast<char*>(m_commitEnd) - delta, delta);
88     addToCommittedByteCount(delta);
89     m_commitEnd = reinterpret_cast_ptr<Register*>(reinterpret_cast<char*>(m_commitEnd) - delta);
90     updateStackLimit(newEnd);
91     return true;
92 }
93
94 void JSStack::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
95 {
96     conservativeRoots.add(getBaseOfStack(), getTopOfStack());
97 }
98
99 void JSStack::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks)
100 {
101     conservativeRoots.add(getBaseOfStack(), getTopOfStack(), jitStubRoutines, codeBlocks);
102 }
103
104 void JSStack::releaseExcessCapacity()
105 {
106     ptrdiff_t delta = reinterpret_cast<uintptr_t>(highAddress()) - reinterpret_cast<uintptr_t>(m_commitEnd);
107     m_reservation.decommit(m_commitEnd, delta);
108     addToCommittedByteCount(-delta);
109     m_commitEnd = highAddress();
110 }
111
112 void JSStack::initializeThreading()
113 {
114     stackStatisticsMutex();
115 }
116
117 size_t JSStack::committedByteCount()
118 {
119     MutexLocker locker(stackStatisticsMutex());
120     return committedBytesCount;
121 }
122
123 void JSStack::addToCommittedByteCount(long byteCount)
124 {
125     MutexLocker locker(stackStatisticsMutex());
126     ASSERT(static_cast<long>(committedBytesCount) + byteCount > -1);
127     committedBytesCount += byteCount;
128 }
129
130 void JSStack::enableErrorStackReserve()
131 {
132     m_useableEnd = reservationEnd();
133 }
134
135 void JSStack::disableErrorStackReserve()
136 {
137     char* useableEnd = reinterpret_cast<char*>(reservationEnd()) + commitSize;
138     m_useableEnd = reinterpret_cast_ptr<Register*>(useableEnd);
139
140     // By the time we get here, we are guaranteed to be destructing the last
141     // Interpreter::ErrorHandlingMode that enabled this reserve in the first
142     // place. That means the stack space beyond m_useableEnd before we
143     // enabled the reserve was not previously in use. Hence, it is safe to
144     // shrink back to that m_useableEnd.
145     if (m_end < m_useableEnd) {
146         ASSERT(m_topCallFrame->frameExtent() >= m_useableEnd);
147         shrink(m_useableEnd);
148     }
149 }
150
151 } // namespace JSC