Unreviewed, speculative fix for CLoop build on CPU(UNKNOWN)
[WebKit-https.git] / Source / JavaScriptCore / jit / ExecutableAllocator.h
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
56 namespace JSC {
57
58 static const unsigned jitAllocationGranule = 32;
59
60 typedef WTF::MetaAllocatorHandle ExecutableMemoryHandle;
61
62 class ExecutableAllocatorBase {
63     WTF_MAKE_FAST_ALLOCATED;
64     WTF_MAKE_NONCOPYABLE(ExecutableAllocatorBase);
65 public:
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
87 protected:
88     ExecutableAllocatorBase() = default;
89     ~ExecutableAllocatorBase() = default;
90
91 private:
92     mutable Lock m_lock;
93 };
94
95 #if ENABLE(JIT)
96
97 JS_EXPORT_PRIVATE void* startOfFixedExecutableMemoryPoolImpl();
98 JS_EXPORT_PRIVATE void* endOfFixedExecutableMemoryPoolImpl();
99
100 template<typename T = void*>
101 T startOfFixedExecutableMemoryPool()
102 {
103     return bitwise_cast<T>(startOfFixedExecutableMemoryPoolImpl());
104 }
105
106 template<typename T = void*>
107 T endOfFixedExecutableMemoryPool()
108 {
109     return bitwise_cast<T>(endOfFixedExecutableMemoryPoolImpl());
110 }
111
112 JS_EXPORT_PRIVATE bool isJITPC(void* pc);
113
114 #if ENABLE(SEPARATED_WX_HEAP)
115
116 typedef void (*JITWriteSeparateHeapsFunction)(off_t, const void*, size_t);
117 extern JS_EXPORT_PRIVATE JITWriteSeparateHeapsFunction jitWriteSeparateHeapsFunction;
118 extern JS_EXPORT_PRIVATE bool useFastPermisionsJITCopy;
119
120 #endif // ENABLE(SEPARATED_WX_HEAP)
121
122 static 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
158 class ExecutableAllocator : private ExecutableAllocatorBase {
159 public:
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
188 private:
189     ExecutableAllocator() = default;
190     ~ExecutableAllocator() = default;
191 };
192
193 #else
194
195 class ExecutableAllocator : public ExecutableAllocatorBase {
196 public:
197     static ExecutableAllocator& singleton();
198     static void initialize();
199     static void initializeUnderlyingAllocator() { }
200
201 private:
202     ExecutableAllocator() = default;
203     ~ExecutableAllocator() = default;
204 };
205
206 static inline void* performJITMemcpy(void *dst, const void *src, size_t n)
207 {
208     return memcpy(dst, src, n);
209 }
210
211 inline bool isJITPC(void*) { return false; }
212 #endif // ENABLE(JIT)
213
214
215 } // namespace JSC