1/*
2 * Copyright (C) 2016-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 "MarkedBlock.h"
29#include "WeakSet.h"
30
31namespace JSC {
32
33class SlotVisitor;
34
35// WebKit has a good malloc that already knows what to do for large allocations. The GC shouldn't
36// have to think about such things. That's where LargeAllocation comes in. We will allocate large
37// objects directly using malloc, and put the LargeAllocation header just before them. We can detect
38// when a HeapCell* is a LargeAllocation because it will have the MarkedBlock::atomSize / 2 bit set.
39
40class LargeAllocation : public BasicRawSentinelNode<LargeAllocation> {
41public:
42 static LargeAllocation* tryCreate(Heap&, size_t, Subspace*, unsigned indexInSpace);
43
44 LargeAllocation* tryReallocate(size_t, Subspace*);
45
46 ~LargeAllocation();
47
48 static LargeAllocation* fromCell(const void* cell)
49 {
50 return bitwise_cast<LargeAllocation*>(bitwise_cast<char*>(cell) - headerSize());
51 }
52
53 HeapCell* cell() const
54 {
55 return bitwise_cast<HeapCell*>(bitwise_cast<char*>(this) + headerSize());
56 }
57
58 static bool isLargeAllocation(HeapCell* cell)
59 {
60 return bitwise_cast<uintptr_t>(cell) & halfAlignment;
61 }
62
63 Subspace* subspace() const { return m_subspace; }
64
65 void lastChanceToFinalize();
66
67 Heap* heap() const { return m_weakSet.heap(); }
68 VM* vm() const { return m_weakSet.vm(); }
69 WeakSet& weakSet() { return m_weakSet; }
70
71 unsigned indexInSpace() { return m_indexInSpace; }
72 void setIndexInSpace(unsigned indexInSpace) { m_indexInSpace = indexInSpace; }
73
74 void shrink();
75
76 void visitWeakSet(SlotVisitor&);
77 void reapWeakSet();
78
79 void clearNewlyAllocated() { m_isNewlyAllocated = false; }
80 void flip();
81
82 bool isNewlyAllocated() const { return m_isNewlyAllocated; }
83 ALWAYS_INLINE bool isMarked() { return m_isMarked.load(std::memory_order_relaxed); }
84 ALWAYS_INLINE bool isMarked(HeapCell*) { return isMarked(); }
85 ALWAYS_INLINE bool isMarked(HeapCell*, Dependency) { return isMarked(); }
86 ALWAYS_INLINE bool isMarked(HeapVersion, HeapCell*) { return isMarked(); }
87 bool isLive() { return isMarked() || isNewlyAllocated(); }
88
89 bool hasValidCell() const { return m_hasValidCell; }
90
91 bool isEmpty();
92
93 size_t cellSize() const { return m_cellSize; }
94
95 bool aboveLowerBound(const void* rawPtr)
96 {
97 char* ptr = bitwise_cast<char*>(rawPtr);
98 char* begin = bitwise_cast<char*>(cell());
99 return ptr >= begin;
100 }
101
102 bool belowUpperBound(const void* rawPtr)
103 {
104 char* ptr = bitwise_cast<char*>(rawPtr);
105 char* begin = bitwise_cast<char*>(cell());
106 char* end = begin + cellSize();
107 // We cannot #include IndexingHeader.h because reasons. The fact that IndexingHeader is 8
108 // bytes is wired deep into our engine, so this isn't so bad.
109 size_t sizeOfIndexingHeader = 8;
110 return ptr <= end + sizeOfIndexingHeader;
111 }
112
113 bool contains(const void* rawPtr)
114 {
115 return aboveLowerBound(rawPtr) && belowUpperBound(rawPtr);
116 }
117
118 const CellAttributes& attributes() const { return m_attributes; }
119
120 Dependency aboutToMark(HeapVersion) { return Dependency(); }
121
122 ALWAYS_INLINE bool testAndSetMarked()
123 {
124 // This method is usually called when the object is already marked. This avoids us
125 // having to CAS in that case. It's profitable to reduce the total amount of CAS
126 // traffic.
127 if (isMarked())
128 return true;
129 return m_isMarked.compareExchangeStrong(false, true);
130 }
131 ALWAYS_INLINE bool testAndSetMarked(HeapCell*, Dependency) { return testAndSetMarked(); }
132 void clearMarked() { m_isMarked.store(false); }
133
134 void noteMarked() { }
135
136#if ASSERT_DISABLED
137 void assertValidCell(VM&, HeapCell*) const { }
138#else
139 void assertValidCell(VM&, HeapCell*) const;
140#endif
141
142 void sweep();
143
144 void destroy();
145
146 void dump(PrintStream&) const;
147
148 static const unsigned alignment = MarkedBlock::atomSize;
149 static const unsigned halfAlignment = alignment / 2;
150
151private:
152 LargeAllocation(Heap&, size_t, Subspace*, unsigned indexInSpace, bool adjustedAlignment);
153
154 static unsigned headerSize();
155
156 void* basePointer() const;
157
158 size_t m_cellSize;
159 unsigned m_indexInSpace { 0 };
160 bool m_isNewlyAllocated : 1;
161 bool m_hasValidCell : 1;
162 bool m_adjustedAlignment : 1;
163 Atomic<bool> m_isMarked;
164 CellAttributes m_attributes;
165 Subspace* m_subspace;
166 WeakSet m_weakSet;
167};
168
169inline unsigned LargeAllocation::headerSize()
170{
171 return ((sizeof(LargeAllocation) + halfAlignment - 1) & ~(halfAlignment - 1)) | halfAlignment;
172}
173
174inline void* LargeAllocation::basePointer() const
175{
176 if (m_adjustedAlignment)
177 return bitwise_cast<char*>(this) - halfAlignment;
178 return bitwise_cast<void*>(this);
179}
180
181} // namespace JSC
182
183