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