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