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