Purge PassRefPtr in JavaScriptCore - 2
[WebKit-https.git] / Source / JavaScriptCore / jit / ExecutableAllocatorFixedVMPool.cpp
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
26 #include "config.h"
27 #include "ExecutableAllocator.h"
28
29 #include "JSCInlines.h"
30
31 #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
32
33 #include "CodeProfiling.h"
34 #include "ExecutableAllocationFuzz.h"
35 #include <errno.h>
36 #if !PLATFORM(WIN)
37 #include <unistd.h>
38 #endif
39 #include <wtf/MetaAllocator.h>
40 #include <wtf/PageReservation.h>
41 #include <wtf/VMTags.h>
42
43 #if OS(DARWIN)
44 #include <sys/mman.h>
45 #endif
46
47 #if OS(LINUX)
48 #include <stdio.h>
49 #endif
50
51 using namespace WTF;
52
53 namespace JSC {
54     
55 uintptr_t startOfFixedExecutableMemoryPool;
56
57 class FixedVMPoolExecutableAllocator : public MetaAllocator {
58     WTF_MAKE_FAST_ALLOCATED;
59 public:
60     FixedVMPoolExecutableAllocator()
61         : MetaAllocator(jitAllocationGranule) // round up all allocations to 32 bytes
62     {
63         m_reservation = PageReservation::reserveWithGuardPages(fixedExecutableMemoryPoolSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
64         if (m_reservation) {
65             ASSERT(m_reservation.size() == fixedExecutableMemoryPoolSize);
66             addFreshFreeSpace(m_reservation.base(), m_reservation.size());
67             
68             startOfFixedExecutableMemoryPool = reinterpret_cast<uintptr_t>(m_reservation.base());
69         }
70     }
71
72     virtual ~FixedVMPoolExecutableAllocator();
73     
74 protected:
75     virtual void* allocateNewSpace(size_t&) override
76     {
77         // We're operating in a fixed pool, so new allocation is always prohibited.
78         return 0;
79     }
80     
81     virtual void notifyNeedPage(void* page) override
82     {
83 #if USE(MADV_FREE_FOR_JIT_MEMORY)
84         UNUSED_PARAM(page);
85 #else
86         m_reservation.commit(page, pageSize());
87 #endif
88     }
89     
90     virtual void notifyPageIsFree(void* page) override
91     {
92 #if USE(MADV_FREE_FOR_JIT_MEMORY)
93         for (;;) {
94             int result = madvise(page, pageSize(), MADV_FREE);
95             if (!result)
96                 return;
97             ASSERT(result == -1);
98             if (errno != EAGAIN) {
99                 RELEASE_ASSERT_NOT_REACHED(); // In debug mode, this should be a hard failure.
100                 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.
101             }
102         }
103 #else
104         m_reservation.decommit(page, pageSize());
105 #endif
106     }
107
108 private:
109     PageReservation m_reservation;
110 };
111
112 static FixedVMPoolExecutableAllocator* allocator;
113
114 void ExecutableAllocator::initializeAllocator()
115 {
116     ASSERT(!allocator);
117     allocator = new FixedVMPoolExecutableAllocator();
118     CodeProfiling::notifyAllocator(allocator);
119 }
120
121 ExecutableAllocator::ExecutableAllocator(VM&)
122 {
123     ASSERT(allocator);
124 }
125
126 ExecutableAllocator::~ExecutableAllocator()
127 {
128 }
129
130 FixedVMPoolExecutableAllocator::~FixedVMPoolExecutableAllocator()
131 {
132     m_reservation.deallocate();
133 }
134
135 bool ExecutableAllocator::isValid() const
136 {
137     return !!allocator->bytesReserved();
138 }
139
140 bool ExecutableAllocator::underMemoryPressure()
141 {
142     MetaAllocator::Statistics statistics = allocator->currentStatistics();
143     return statistics.bytesAllocated > statistics.bytesReserved / 2;
144 }
145
146 double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage)
147 {
148     MetaAllocator::Statistics statistics = allocator->currentStatistics();
149     ASSERT(statistics.bytesAllocated <= statistics.bytesReserved);
150     size_t bytesAllocated = statistics.bytesAllocated + addedMemoryUsage;
151     if (bytesAllocated >= statistics.bytesReserved)
152         bytesAllocated = statistics.bytesReserved;
153     double result = 1.0;
154     size_t divisor = statistics.bytesReserved - bytesAllocated;
155     if (divisor)
156         result = static_cast<double>(statistics.bytesReserved) / divisor;
157     if (result < 1.0)
158         result = 1.0;
159     return result;
160 }
161
162 RefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(VM&, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort)
163 {
164     if (effort != JITCompilationCanFail && Options::reportMustSucceedExecutableAllocations()) {
165         dataLog("Allocating ", sizeInBytes, " bytes of executable memory with JITCompilationMustSucceed.\n");
166         WTFReportBacktrace();
167     }
168     
169     if (effort == JITCompilationCanFail
170         && doExecutableAllocationFuzzingIfEnabled() == PretendToFailExecutableAllocation)
171         return nullptr;
172     
173     RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID);
174     if (!result) {
175         if (effort != JITCompilationCanFail) {
176             dataLog("Ran out of executable memory while allocating ", sizeInBytes, " bytes.\n");
177             CRASH();
178         }
179         return nullptr;
180     }
181     return result;
182 }
183
184 size_t ExecutableAllocator::committedByteCount()
185 {
186     return allocator->bytesCommitted();
187 }
188
189 #if ENABLE(META_ALLOCATOR_PROFILE)
190 void ExecutableAllocator::dumpProfile()
191 {
192     allocator->dumpProfile();
193 }
194 #endif
195
196 }
197
198
199 #endif // ENABLE(EXECUTABLE_ALLOCATOR_FIXED)