1/*
2 * Copyright (C) 2009-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 "ExecutableAllocator.h"
29#include "JSCPtrTag.h"
30#include <wtf/DataLog.h>
31#include <wtf/PrintStream.h>
32#include <wtf/RefPtr.h>
33#include <wtf/text/CString.h>
34
35// ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid
36// instruction address on the platform (for example, check any alignment requirements).
37#if CPU(ARM_THUMB2) && ENABLE(JIT)
38// ARM instructions must be 16-bit aligned. Thumb2 code pointers to be loaded into
39// into the processor are decorated with the bottom bit set, while traditional ARM has
40// the lower bit clear. Since we don't know what kind of pointer, we check for both
41// decorated and undecorated null.
42#define ASSERT_NULL_OR_VALID_CODE_POINTER(ptr) \
43 ASSERT(!ptr || reinterpret_cast<intptr_t>(ptr) & ~1)
44#define ASSERT_VALID_CODE_POINTER(ptr) \
45 ASSERT(reinterpret_cast<intptr_t>(ptr) & ~1)
46#define ASSERT_VALID_CODE_OFFSET(offset) \
47 ASSERT(!(offset & 1)) // Must be multiple of 2.
48#else
49#define ASSERT_NULL_OR_VALID_CODE_POINTER(ptr) // Anything goes!
50#define ASSERT_VALID_CODE_POINTER(ptr) \
51 ASSERT(ptr)
52#define ASSERT_VALID_CODE_OFFSET(offset) // Anything goes!
53#endif
54
55namespace JSC {
56
57template<PtrTag> class MacroAssemblerCodePtr;
58
59enum OpcodeID : unsigned;
60
61// FunctionPtr:
62//
63// FunctionPtr should be used to wrap pointers to C/C++ functions in JSC
64// (particularly, the stub functions).
65template<PtrTag tag = CFunctionPtrTag>
66class FunctionPtr {
67public:
68 FunctionPtr() { }
69 FunctionPtr(std::nullptr_t) { }
70
71 template<typename ReturnType, typename... Arguments>
72 FunctionPtr(ReturnType(*value)(Arguments...))
73 : m_value(tagCFunctionPtr<void*, tag>(value))
74 {
75 assertIsNullOrCFunctionPtr(value);
76 ASSERT_NULL_OR_VALID_CODE_POINTER(m_value);
77 }
78
79// MSVC doesn't seem to treat functions with different calling conventions as
80// different types; these methods already defined for fastcall, below.
81#if CALLING_CONVENTION_IS_STDCALL && !OS(WINDOWS)
82
83 template<typename ReturnType, typename... Arguments>
84 FunctionPtr(ReturnType(CDECL *value)(Arguments...))
85 : m_value(tagCFunctionPtr<void*, tag>(value))
86 {
87 assertIsNullOrCFunctionPtr(value);
88 ASSERT_NULL_OR_VALID_CODE_POINTER(m_value);
89 }
90
91#endif // CALLING_CONVENTION_IS_STDCALL && !OS(WINDOWS)
92
93#if COMPILER_SUPPORTS(FASTCALL_CALLING_CONVENTION)
94
95 template<typename ReturnType, typename... Arguments>
96 FunctionPtr(ReturnType(FASTCALL *value)(Arguments...))
97 : m_value(tagCFunctionPtr<void*, tag>(value))
98 {
99 assertIsNullOrCFunctionPtr(value);
100 ASSERT_NULL_OR_VALID_CODE_POINTER(m_value);
101 }
102
103#endif // COMPILER_SUPPORTS(FASTCALL_CALLING_CONVENTION)
104
105 template<typename PtrType, typename = std::enable_if_t<std::is_pointer<PtrType>::value && !std::is_function<typename std::remove_pointer<PtrType>::type>::value>>
106 explicit FunctionPtr(PtrType value)
107 // Using a C-ctyle cast here to avoid compiler error on RVTC:
108 // Error: #694: reinterpret_cast cannot cast away const or other type qualifiers
109 // (I guess on RVTC function pointers have a different constness to GCC/MSVC?)
110 : m_value(tagCFunctionPtr<void*, tag>(value))
111 {
112 assertIsNullOrCFunctionPtr(value);
113 ASSERT_NULL_OR_VALID_CODE_POINTER(m_value);
114 }
115
116 explicit FunctionPtr(MacroAssemblerCodePtr<tag>);
117
118 template<PtrTag otherTag>
119 FunctionPtr<otherTag> retagged() const
120 {
121 if (!m_value)
122 return FunctionPtr<otherTag>();
123 return FunctionPtr<otherTag>(*this);
124 }
125
126 void* executableAddress() const
127 {
128 return m_value;
129 }
130
131 template<PtrTag newTag>
132 void* retaggedExecutableAddress() const
133 {
134 return retagCodePtr<tag, newTag>(m_value);
135 }
136
137 explicit operator bool() const { return !!m_value; }
138 bool operator!() const { return !m_value; }
139
140 bool operator==(const FunctionPtr& other) const { return m_value == other.m_value; }
141 bool operator!=(const FunctionPtr& other) const { return m_value != other.m_value; }
142
143private:
144 template<PtrTag otherTag>
145 explicit FunctionPtr(const FunctionPtr<otherTag>& other)
146 : m_value(retagCodePtr<otherTag, tag>(other.executableAddress()))
147 {
148 ASSERT_NULL_OR_VALID_CODE_POINTER(m_value);
149 }
150
151 void* m_value { nullptr };
152
153 template<PtrTag> friend class FunctionPtr;
154};
155
156static_assert(sizeof(FunctionPtr<CFunctionPtrTag>) == sizeof(void*), "");
157#if COMPILER_SUPPORTS(BUILTIN_IS_TRIVIALLY_COPYABLE)
158static_assert(__is_trivially_copyable(FunctionPtr<CFunctionPtrTag>), "");
159#endif
160
161// ReturnAddressPtr:
162//
163// ReturnAddressPtr should be used to wrap return addresses generated by processor
164// 'call' instructions exectued in JIT code. We use return addresses to look up
165// exception and optimization information, and to repatch the call instruction
166// that is the source of the return address.
167class ReturnAddressPtr {
168public:
169 ReturnAddressPtr() { }
170
171 explicit ReturnAddressPtr(const void* value)
172 : m_value(value)
173 {
174 ASSERT_VALID_CODE_POINTER(m_value);
175 }
176
177 template<PtrTag tag>
178 explicit ReturnAddressPtr(FunctionPtr<tag> function)
179 : m_value(untagCodePtr<tag>(function.executableAddress()))
180 {
181 ASSERT_VALID_CODE_POINTER(m_value);
182 }
183
184 const void* value() const
185 {
186 return m_value;
187 }
188
189 void dump(PrintStream& out) const
190 {
191 out.print(RawPointer(m_value));
192 }
193
194private:
195 const void* m_value { nullptr };
196};
197
198// MacroAssemblerCodePtr:
199//
200// MacroAssemblerCodePtr should be used to wrap pointers to JIT generated code.
201class MacroAssemblerCodePtrBase {
202protected:
203 static void dumpWithName(void* executableAddress, void* dataLocation, const char* name, PrintStream& out);
204};
205
206// FIXME: Make JSC MacroAssemblerCodePtr injerit from MetaAllocatorPtr.
207// https://bugs.webkit.org/show_bug.cgi?id=185145
208template<PtrTag tag>
209class MacroAssemblerCodePtr : private MacroAssemblerCodePtrBase {
210public:
211 MacroAssemblerCodePtr() = default;
212 MacroAssemblerCodePtr(std::nullptr_t) : m_value(nullptr) { }
213
214 explicit MacroAssemblerCodePtr(const void* value)
215#if CPU(ARM_THUMB2)
216 // Decorate the pointer as a thumb code pointer.
217 : m_value(reinterpret_cast<const char*>(value) + 1)
218#else
219 : m_value(value)
220#endif
221 {
222 assertIsTaggedWith(value, tag);
223 ASSERT(value);
224#if CPU(ARM_THUMB2)
225 ASSERT(!(reinterpret_cast<uintptr_t>(value) & 1));
226#endif
227 ASSERT_VALID_CODE_POINTER(m_value);
228 }
229
230 static MacroAssemblerCodePtr createFromExecutableAddress(const void* value)
231 {
232 ASSERT(value);
233 ASSERT_VALID_CODE_POINTER(value);
234 assertIsTaggedWith(value, tag);
235 MacroAssemblerCodePtr result;
236 result.m_value = value;
237 return result;
238 }
239
240 explicit MacroAssemblerCodePtr(ReturnAddressPtr ra)
241 : m_value(tagCodePtr<tag>(ra.value()))
242 {
243 assertIsNotTagged(ra.value());
244 ASSERT(ra.value());
245 ASSERT_VALID_CODE_POINTER(m_value);
246 }
247
248 template<PtrTag newTag>
249 MacroAssemblerCodePtr<newTag> retagged() const
250 {
251 if (!m_value)
252 return MacroAssemblerCodePtr<newTag>();
253 return MacroAssemblerCodePtr<newTag>::createFromExecutableAddress(retaggedExecutableAddress<newTag>());
254 }
255
256 template<typename T = void*>
257 T executableAddress() const
258 {
259 return bitwise_cast<T>(m_value);
260 }
261
262 template<typename T = void*>
263 T untaggedExecutableAddress() const
264 {
265 return untagCodePtr<T, tag>(m_value);
266 }
267
268 template<PtrTag newTag, typename T = void*>
269 T retaggedExecutableAddress() const
270 {
271 return retagCodePtr<T, tag, newTag>(m_value);
272 }
273
274#if CPU(ARM_THUMB2)
275 // To use this pointer as a data address remove the decoration.
276 template<typename T = void*>
277 T dataLocation() const
278 {
279 ASSERT_VALID_CODE_POINTER(m_value);
280 return bitwise_cast<T>(m_value ? bitwise_cast<char*>(m_value) - 1 : nullptr);
281 }
282#else
283 template<typename T = void*>
284 T dataLocation() const
285 {
286 ASSERT_VALID_CODE_POINTER(m_value);
287 return untagCodePtr<T, tag>(m_value);
288 }
289#endif
290
291 bool operator!() const
292 {
293 return !m_value;
294 }
295 explicit operator bool() const { return !(!*this); }
296
297 bool operator==(const MacroAssemblerCodePtr& other) const
298 {
299 return m_value == other.m_value;
300 }
301
302 // Disallow any casting operations (except for booleans). Instead, the client
303 // should be asking executableAddress() explicitly.
304 template<typename T, typename = std::enable_if_t<!std::is_same<T, bool>::value>>
305 operator T() = delete;
306
307 void dumpWithName(const char* name, PrintStream& out) const
308 {
309 MacroAssemblerCodePtrBase::dumpWithName(executableAddress(), dataLocation(), name, out);
310 }
311
312 void dump(PrintStream& out) const { dumpWithName("CodePtr", out); }
313
314 enum EmptyValueTag { EmptyValue };
315 enum DeletedValueTag { DeletedValue };
316
317 MacroAssemblerCodePtr(EmptyValueTag)
318 : m_value(emptyValue())
319 { }
320
321 MacroAssemblerCodePtr(DeletedValueTag)
322 : m_value(deletedValue())
323 { }
324
325 bool isEmptyValue() const { return m_value == emptyValue(); }
326 bool isDeletedValue() const { return m_value == deletedValue(); }
327
328 unsigned hash() const { return PtrHash<const void*>::hash(m_value); }
329
330 static void initialize();
331
332private:
333 static const void* emptyValue() { return bitwise_cast<void*>(static_cast<intptr_t>(1)); }
334 static const void* deletedValue() { return bitwise_cast<void*>(static_cast<intptr_t>(2)); }
335
336 const void* m_value { nullptr };
337};
338
339template<PtrTag tag>
340struct MacroAssemblerCodePtrHash {
341 static unsigned hash(const MacroAssemblerCodePtr<tag>& ptr) { return ptr.hash(); }
342 static bool equal(const MacroAssemblerCodePtr<tag>& a, const MacroAssemblerCodePtr<tag>& b)
343 {
344 return a == b;
345 }
346 static const bool safeToCompareToEmptyOrDeleted = true;
347};
348
349// MacroAssemblerCodeRef:
350//
351// A reference to a section of JIT generated code. A CodeRef consists of a
352// pointer to the code, and a ref pointer to the pool from within which it
353// was allocated.
354class MacroAssemblerCodeRefBase {
355protected:
356 static bool tryToDisassemble(MacroAssemblerCodePtr<DisassemblyPtrTag>, size_t, const char* prefix, PrintStream& out);
357 static bool tryToDisassemble(MacroAssemblerCodePtr<DisassemblyPtrTag>, size_t, const char* prefix);
358 JS_EXPORT_PRIVATE static CString disassembly(MacroAssemblerCodePtr<DisassemblyPtrTag>, size_t);
359};
360
361template<PtrTag tag>
362class MacroAssemblerCodeRef : private MacroAssemblerCodeRefBase {
363private:
364 // This is private because it's dangerous enough that we want uses of it
365 // to be easy to find - hence the static create method below.
366 explicit MacroAssemblerCodeRef(MacroAssemblerCodePtr<tag> codePtr)
367 : m_codePtr(codePtr)
368 {
369 ASSERT(m_codePtr);
370 }
371
372public:
373 MacroAssemblerCodeRef() = default;
374
375 MacroAssemblerCodeRef(Ref<ExecutableMemoryHandle>&& executableMemory)
376 : m_codePtr(executableMemory->start().retaggedPtr<tag>())
377 , m_executableMemory(WTFMove(executableMemory))
378 {
379 ASSERT(m_executableMemory->isManaged());
380 ASSERT(m_executableMemory->start());
381 ASSERT(m_codePtr);
382 }
383
384 template<PtrTag otherTag>
385 MacroAssemblerCodeRef& operator=(const MacroAssemblerCodeRef<otherTag>& otherCodeRef)
386 {
387 m_codePtr = MacroAssemblerCodePtr<tag>::createFromExecutableAddress(otherCodeRef.code().template retaggedExecutableAddress<tag>());
388 m_executableMemory = otherCodeRef.m_executableMemory;
389 return *this;
390 }
391
392 // Use this only when you know that the codePtr refers to code that is
393 // already being kept alive through some other means. Typically this means
394 // that codePtr is immortal.
395 static MacroAssemblerCodeRef createSelfManagedCodeRef(MacroAssemblerCodePtr<tag> codePtr)
396 {
397 return MacroAssemblerCodeRef(codePtr);
398 }
399
400 ExecutableMemoryHandle* executableMemory() const
401 {
402 return m_executableMemory.get();
403 }
404
405 MacroAssemblerCodePtr<tag> code() const
406 {
407 return m_codePtr;
408 }
409
410 template<PtrTag newTag>
411 MacroAssemblerCodePtr<newTag> retaggedCode() const
412 {
413 return m_codePtr.template retagged<newTag>();
414 }
415
416 template<PtrTag newTag>
417 MacroAssemblerCodeRef<newTag> retagged() const
418 {
419 return MacroAssemblerCodeRef<newTag>(*this);
420 }
421
422 size_t size() const
423 {
424 if (!m_executableMemory)
425 return 0;
426 return m_executableMemory->sizeInBytes();
427 }
428
429 bool tryToDisassemble(PrintStream& out, const char* prefix = "") const
430 {
431 return tryToDisassemble(retaggedCode<DisassemblyPtrTag>(), size(), prefix, out);
432 }
433
434 bool tryToDisassemble(const char* prefix = "") const
435 {
436 return tryToDisassemble(retaggedCode<DisassemblyPtrTag>(), size(), prefix);
437 }
438
439 CString disassembly() const
440 {
441 return MacroAssemblerCodeRefBase::disassembly(retaggedCode<DisassemblyPtrTag>(), size());
442 }
443
444 explicit operator bool() const { return !!m_codePtr; }
445
446 void dump(PrintStream& out) const
447 {
448 m_codePtr.dumpWithName("CodeRef", out);
449 }
450
451private:
452 template<PtrTag otherTag>
453 MacroAssemblerCodeRef(const MacroAssemblerCodeRef<otherTag>& otherCodeRef)
454 {
455 *this = otherCodeRef;
456 }
457
458 MacroAssemblerCodePtr<tag> m_codePtr;
459 RefPtr<ExecutableMemoryHandle> m_executableMemory;
460
461 template<PtrTag> friend class MacroAssemblerCodeRef;
462};
463
464template<PtrTag tag>
465inline FunctionPtr<tag>::FunctionPtr(MacroAssemblerCodePtr<tag> ptr)
466 : m_value(ptr.executableAddress())
467{
468}
469
470} // namespace JSC
471
472namespace WTF {
473
474template<typename T> struct DefaultHash;
475template<JSC::PtrTag tag> struct DefaultHash<JSC::MacroAssemblerCodePtr<tag>> {
476 typedef JSC::MacroAssemblerCodePtrHash<tag> Hash;
477};
478
479template<typename T> struct HashTraits;
480template<JSC::PtrTag tag> struct HashTraits<JSC::MacroAssemblerCodePtr<tag>> : public CustomHashTraits<JSC::MacroAssemblerCodePtr<tag>> { };
481
482} // namespace WTF
483