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