1/*
2 * Copyright (C) 2008-2019 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#pragma once
27
28#include "JITCompilationEffort.h"
29#include "JSCConfig.h"
30#include "JSCPtrTag.h"
31#include "Options.h"
32#include <stddef.h> // for ptrdiff_t
33#include <limits>
34#include <wtf/Assertions.h>
35#include <wtf/Gigacage.h>
36#include <wtf/Lock.h>
37#include <wtf/MetaAllocatorHandle.h>
38#include <wtf/MetaAllocator.h>
39
40#if OS(IOS_FAMILY)
41#include <libkern/OSCacheControl.h>
42#endif
43
44#if OS(IOS_FAMILY)
45#include <sys/mman.h>
46#endif
47
48#if CPU(MIPS) && OS(LINUX)
49#include <sys/cachectl.h>
50#endif
51
52#if ENABLE(FAST_JIT_PERMISSIONS)
53#include <os/thread_self_restrict.h>
54#endif
55#define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (pageSize() * 4)
56
57#define EXECUTABLE_POOL_WRITABLE true
58
59namespace JSC {
60
61static constexpr unsigned jitAllocationGranule = 32;
62
63typedef WTF::MetaAllocatorHandle ExecutableMemoryHandle;
64
65class ExecutableAllocatorBase {
66 WTF_MAKE_FAST_ALLOCATED;
67 WTF_MAKE_NONCOPYABLE(ExecutableAllocatorBase);
68public:
69 bool isValid() const { return false; }
70
71 static bool underMemoryPressure() { return false; }
72
73 static double memoryPressureMultiplier(size_t) { return 1.0; }
74
75 static void dumpProfile() { }
76
77 RefPtr<ExecutableMemoryHandle> allocate(size_t, void*, JITCompilationEffort) { return nullptr; }
78
79 static void setJITEnabled(bool) { };
80
81 bool isValidExecutableMemory(const AbstractLocker&, void*) { return false; }
82
83 static size_t committedByteCount() { return 0; }
84
85 Lock& getLock() const
86 {
87 return m_lock;
88 }
89
90protected:
91 ExecutableAllocatorBase() = default;
92 ~ExecutableAllocatorBase() = default;
93
94private:
95 mutable Lock m_lock;
96};
97
98#if ENABLE(JIT)
99
100JS_EXPORT_PRIVATE void* startOfFixedExecutableMemoryPoolImpl();
101JS_EXPORT_PRIVATE void* endOfFixedExecutableMemoryPoolImpl();
102
103template<typename T = void*>
104T startOfFixedExecutableMemoryPool()
105{
106 return bitwise_cast<T>(startOfFixedExecutableMemoryPoolImpl());
107}
108
109template<typename T = void*>
110T endOfFixedExecutableMemoryPool()
111{
112 return bitwise_cast<T>(endOfFixedExecutableMemoryPoolImpl());
113}
114
115JS_EXPORT_PRIVATE bool isJITPC(void* pc);
116
117JS_EXPORT_PRIVATE void dumpJITMemory(const void*, const void*, size_t);
118
119static ALWAYS_INLINE void* performJITMemcpy(void *dst, const void *src, size_t n)
120{
121#if CPU(ARM64)
122 static constexpr size_t instructionSize = sizeof(unsigned);
123 RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(dst) == dst);
124 RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(src) == src);
125#endif
126 if (isJITPC(dst)) {
127 RELEASE_ASSERT(reinterpret_cast<uint8_t*>(dst) + n <= endOfFixedExecutableMemoryPool());
128
129 if (UNLIKELY(Options::dumpJITMemoryPath()))
130 dumpJITMemory(dst, src, n);
131#if ENABLE(FAST_JIT_PERMISSIONS)
132#if ENABLE(SEPARATED_WX_HEAP)
133 if (g_jscConfig.useFastPermisionsJITCopy)
134#endif
135 {
136 os_thread_self_restrict_rwx_to_rw();
137 memcpy(dst, src, n);
138 RELEASE_ASSERT(!Gigacage::contains(src));
139 os_thread_self_restrict_rwx_to_rx();
140 return dst;
141 }
142#endif // ENABLE(FAST_JIT_PERMISSIONS)
143
144#if ENABLE(SEPARATED_WX_HEAP)
145 if (g_jscConfig.jitWriteSeparateHeaps) {
146 // Use execute-only write thunk for writes inside the JIT region. This is a variant of
147 // memcpy that takes an offset into the JIT region as its destination (first) parameter.
148 off_t offset = (off_t)((uintptr_t)dst - startOfFixedExecutableMemoryPool<uintptr_t>());
149 retagCodePtr<JITThunkPtrTag, CFunctionPtrTag>(g_jscConfig.jitWriteSeparateHeaps)(offset, src, n);
150 RELEASE_ASSERT(!Gigacage::contains(src));
151 return dst;
152 }
153#endif
154 }
155
156 // Use regular memcpy for writes outside the JIT region.
157 return memcpy(dst, src, n);
158}
159
160class ExecutableAllocator : private ExecutableAllocatorBase {
161public:
162 using Base = ExecutableAllocatorBase;
163
164 static ExecutableAllocator& singleton();
165 static void initialize();
166 static void initializeUnderlyingAllocator();
167
168 bool isValid() const;
169
170 static bool underMemoryPressure();
171
172 static double memoryPressureMultiplier(size_t addedMemoryUsage);
173
174#if ENABLE(META_ALLOCATOR_PROFILE)
175 static void dumpProfile();
176#else
177 static void dumpProfile() { }
178#endif
179
180 JS_EXPORT_PRIVATE static void setJITEnabled(bool);
181
182 RefPtr<ExecutableMemoryHandle> allocate(size_t sizeInBytes, void* ownerUID, JITCompilationEffort);
183
184 bool isValidExecutableMemory(const AbstractLocker&, void* address);
185
186 static size_t committedByteCount();
187
188 Lock& getLock() const;
189
190private:
191 ExecutableAllocator() = default;
192 ~ExecutableAllocator() = default;
193};
194
195#else
196
197class ExecutableAllocator : public ExecutableAllocatorBase {
198public:
199 static ExecutableAllocator& singleton();
200 static void initialize();
201 static void initializeUnderlyingAllocator() { }
202
203private:
204 ExecutableAllocator() = default;
205 ~ExecutableAllocator() = default;
206};
207
208static inline void* performJITMemcpy(void *dst, const void *src, size_t n)
209{
210 return memcpy(dst, src, n);
211}
212
213inline bool isJITPC(void*) { return false; }
214#endif // ENABLE(JIT)
215
216
217} // namespace JSC
218