Butterflies should be allocated in Auxiliary MarkedSpace instead of CopiedSpace and...
[WebKit-https.git] / Source / JavaScriptCore / heap / LargeAllocation.h
1 /*
2  * Copyright (C) 2016 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 "MarkedBlock.h"
29 #include "WeakSet.h"
30
31 namespace JSC {
32
33 // WebKit has a good malloc that already knows what to do for large allocations. The GC shouldn't
34 // have to think about such things. That's where LargeAllocation comes in. We will allocate large
35 // objects directly using malloc, and put the LargeAllocation header just before them. We can detect
36 // when a HeapCell* is a LargeAllocation because it will have the MarkedBlock::atomSize / 2 bit set.
37
38 class LargeAllocation {
39 public:
40     static LargeAllocation* tryCreate(Heap&, size_t, const AllocatorAttributes&);
41     
42     static LargeAllocation* fromCell(const void* cell)
43     {
44         return bitwise_cast<LargeAllocation*>(bitwise_cast<char*>(cell) - headerSize());
45     }
46     
47     HeapCell* cell() const
48     {
49         return bitwise_cast<HeapCell*>(bitwise_cast<char*>(this) + headerSize());
50     }
51     
52     static bool isLargeAllocation(HeapCell* cell)
53     {
54         return bitwise_cast<uintptr_t>(cell) & halfAlignment;
55     }
56     
57     void lastChanceToFinalize();
58     
59     Heap* heap() const { return m_weakSet.heap(); }
60     VM* vm() const { return m_weakSet.vm(); }
61     WeakSet& weakSet() { return m_weakSet; }
62     
63     void shrink();
64     
65     void visitWeakSet(HeapRootVisitor&);
66     void reapWeakSet();
67     
68     void clearNewlyAllocated() { m_isNewlyAllocated = false; }
69     void clearMarks();
70     template<HeapOperation collectionType>
71     void clearMarksWithCollectionType();
72     
73     bool isNewlyAllocated() const { return m_isNewlyAllocated; }
74     ALWAYS_INLINE bool isMarked() { return m_isMarked.load(std::memory_order_relaxed); }
75     bool isMarkedOrNewlyAllocated() { return isMarked() || isNewlyAllocated(); }
76     bool isLive() { return isMarkedOrNewlyAllocated(); }
77     
78     bool hasValidCell() const { return m_hasValidCell; }
79     
80     bool isEmpty();
81     
82     size_t cellSize() const { return m_cellSize; }
83     
84     bool aboveLowerBound(const void* rawPtr)
85     {
86         char* ptr = bitwise_cast<char*>(rawPtr);
87         char* begin = bitwise_cast<char*>(cell());
88         return ptr >= begin;
89     }
90     
91     bool belowUpperBound(const void* rawPtr)
92     {
93         char* ptr = bitwise_cast<char*>(rawPtr);
94         char* begin = bitwise_cast<char*>(cell());
95         char* end = begin + cellSize();
96         // We cannot #include IndexingHeader.h because reasons. The fact that IndexingHeader is 8
97         // bytes is wired deep into our engine, so this isn't so bad.
98         size_t sizeOfIndexingHeader = 8;
99         return ptr <= end + sizeOfIndexingHeader;
100     }
101     
102     bool contains(const void* rawPtr)
103     {
104         return aboveLowerBound(rawPtr) && belowUpperBound(rawPtr);
105     }
106     
107     const AllocatorAttributes& attributes() const { return m_attributes; }
108     
109     ALWAYS_INLINE bool testAndSetMarked()
110     {
111         // This method is usually called when the object is already marked. This avoids us
112         // having to CAS in that case. It's profitable to reduce the total amount of CAS
113         // traffic.
114         if (isMarked())
115             return true;
116         return !m_isMarked.compareExchangeStrong(false, true);
117     }
118     ALWAYS_INLINE bool testAndSetMarked(HeapCell*) { return testAndSetMarked(); }
119     void setMarked() { m_isMarked.store(true); }
120     void clearMarked() { m_isMarked.store(false); }
121     
122     void setHasAnyMarked() { }
123     
124     void sweep();
125     
126     void destroy();
127     
128     void dump(PrintStream&) const;
129     
130 private:
131     LargeAllocation(Heap&, size_t, const AllocatorAttributes&);
132     
133     static const unsigned alignment = MarkedBlock::atomSize;
134     static const unsigned halfAlignment = alignment / 2;
135
136     static unsigned headerSize();
137     
138     size_t m_cellSize;
139     bool m_isNewlyAllocated;
140     bool m_hasValidCell;
141     Atomic<bool> m_isMarked;
142     AllocatorAttributes m_attributes;
143     WeakSet m_weakSet;
144 };
145
146 inline unsigned LargeAllocation::headerSize()
147 {
148     return ((sizeof(LargeAllocation) + halfAlignment - 1) & ~(halfAlignment - 1)) | halfAlignment;
149 }
150
151 } // namespace JSC
152