[EME] Add basic implementation of HTMLMediaElement::setMediaKeys()
[WebKit-https.git] / Source / JavaScriptCore / assembler / ProbeStack.h
1 /*
2  * Copyright (C) 2017 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 <wtf/HashMap.h>
29 #include <wtf/StdLibExtras.h>
30 #include <wtf/Threading.h>
31
32 namespace JSC {
33
34 struct ProbeContext;
35
36 namespace Probe {
37
38 class Page {
39     WTF_MAKE_FAST_ALLOCATED;
40 public:
41     Page(void* baseAddress);
42
43     static void* baseAddressFor(void* p)
44     {
45         return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) & ~s_pageMask);
46     }
47     static void* chunkAddressFor(void* p)
48     {
49         return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) & ~s_chunkMask);
50     }
51
52     void* baseAddress() { return m_baseLogicalAddress; }
53
54     template<typename T>
55     T get(void* logicalAddress)
56     {
57         return *physicalAddressFor<T*>(logicalAddress);
58     }
59
60     template<typename T>
61     void set(void* logicalAddress, T value)
62     {
63         m_dirtyBits |= dirtyBitFor(logicalAddress);
64         *physicalAddressFor<T*>(logicalAddress) = value;
65     }
66
67     bool hasWritesToFlush() const { return !!m_dirtyBits; }
68     void flushWritesIfNeeded()
69     {
70         if (m_dirtyBits)
71             flushWrites();
72     }
73
74 private:
75     uintptr_t dirtyBitFor(void* logicalAddress)
76     {
77         uintptr_t offset = reinterpret_cast<uintptr_t>(logicalAddress) & s_pageMask;
78         return static_cast<uintptr_t>(1) << (offset >> s_chunkSizeShift);
79     }
80
81     template<typename T, typename = typename std::enable_if<std::is_pointer<T>::value>::type>
82     T physicalAddressFor(void* logicalAddress)
83     {
84         uintptr_t offset = reinterpret_cast<uintptr_t>(logicalAddress) & s_pageMask;
85         void* physicalAddress = reinterpret_cast<uint8_t*>(&m_buffer) + offset;
86         return reinterpret_cast<T>(physicalAddress);
87     }
88
89     void flushWrites();
90
91     void* m_baseLogicalAddress { nullptr };
92     uintptr_t m_dirtyBits { 0 };
93
94     static constexpr size_t s_pageSize = 1024;
95     static constexpr uintptr_t s_pageMask = s_pageSize - 1;
96     static constexpr size_t s_chunksPerPage = sizeof(uintptr_t) * 8; // sizeof(m_dirtyBits) in bits.
97     static constexpr size_t s_chunkSize = s_pageSize / s_chunksPerPage;
98     static constexpr uintptr_t s_chunkMask = s_chunkSize - 1;
99 #if USE(JSVALUE64)
100     static constexpr size_t s_chunkSizeShift = 4;
101 #else
102     static constexpr size_t s_chunkSizeShift = 5;
103 #endif
104     static_assert(s_pageSize > s_chunkSize, "bad pageSize or chunkSize");
105     static_assert(s_chunkSize == (1 << s_chunkSizeShift), "bad chunkSizeShift");
106
107
108     typedef typename std::aligned_storage<s_pageSize, std::alignment_of<uintptr_t>::value>::type Buffer;
109     Buffer m_buffer;
110 };
111
112 class Stack {
113     WTF_MAKE_FAST_ALLOCATED;
114 public:
115     Stack()
116         : m_lowWatermark(reinterpret_cast<void*>(-1))
117         , m_stackBounds(Thread::current().stack())
118     { }
119     Stack(Stack&& other);
120
121     void* lowWatermark() { return m_lowWatermark; }
122
123     template<typename T>
124     typename std::enable_if<!std::is_same<double, typename std::remove_cv<T>::type>::value, T>::type get(void* address)
125     {
126         Page* page = pageFor(address);
127         return page->get<T>(address);
128     }
129
130     template<typename T, typename = typename std::enable_if<!std::is_same<double, typename std::remove_cv<T>::type>::value>::type>
131     void set(void* address, T value)
132     {
133         Page* page = pageFor(address);
134         page->set<T>(address, value);
135
136         // We use the chunkAddress for the low watermark because we'll be doing write backs
137         // to the stack in increments of chunks. Hence, we'll treat the lowest address of
138         // the chunk as the low watermark of any given set address.
139         void* chunkAddress = Page::chunkAddressFor(address);
140         if (chunkAddress < m_lowWatermark)
141             m_lowWatermark = chunkAddress;
142     }
143
144     template<typename T>
145     typename std::enable_if<std::is_same<double, typename std::remove_cv<T>::type>::value, T>::type get(void* address)
146     {
147         Page* page = pageFor(address);
148         return bitwise_cast<double>(page->get<uint64_t>(address));
149     }
150
151     template<typename T, typename = typename std::enable_if<std::is_same<double, typename std::remove_cv<T>::type>::value>::type>
152     void set(void* address, double value)
153     {
154         set<uint64_t>(address, bitwise_cast<uint64_t>(value));
155     }
156
157     JS_EXPORT_PRIVATE Page* ensurePageFor(void* address);
158
159     void* newStackPointer() const { return m_newStackPointer; };
160     void setNewStackPointer(void* sp) { m_newStackPointer = sp; };
161
162     bool hasWritesToFlush();
163     void flushWrites();
164
165 #if !ASSERT_DISABLED
166     bool isValid() { return m_isValid; }
167 #endif
168
169 private:
170     Page* pageFor(void* address)
171     {
172         if (LIKELY(Page::baseAddressFor(address) == m_lastAccessedPageBaseAddress))
173             return m_lastAccessedPage;
174         return ensurePageFor(address);
175     }
176
177     void* m_newStackPointer { nullptr };
178     void* m_lowWatermark;
179
180     // A cache of the last accessed page details for quick access.
181     void* m_lastAccessedPageBaseAddress { nullptr };
182     Page* m_lastAccessedPage { nullptr };
183
184     StackBounds m_stackBounds;
185     HashMap<void*, std::unique_ptr<Page>> m_pages;
186
187 #if !ASSERT_DISABLED
188     bool m_isValid { true };
189 #endif
190 };
191
192 } // namespace Probe
193 } // namespace JSC