1/*
2 * Copyright (C) 2017-2018 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#include "config.h"
27#include "IsoCellSet.h"
28
29#include "BlockDirectoryInlines.h"
30#include "MarkedBlockInlines.h"
31
32namespace JSC {
33
34IsoCellSet::IsoCellSet(IsoSubspace& subspace)
35 : m_subspace(subspace)
36{
37 size_t size = subspace.m_directory.m_blocks.size();
38 m_blocksWithBits.resize(size);
39 m_bits.grow(size);
40 subspace.m_cellSets.append(this);
41}
42
43IsoCellSet::~IsoCellSet()
44{
45 if (isOnList())
46 BasicRawSentinelNode<IsoCellSet>::remove();
47}
48
49Ref<SharedTask<MarkedBlock::Handle*()>> IsoCellSet::parallelNotEmptyMarkedBlockSource()
50{
51 class Task : public SharedTask<MarkedBlock::Handle*()> {
52 public:
53 Task(IsoCellSet& set)
54 : m_set(set)
55 , m_directory(set.m_subspace.m_directory)
56 {
57 }
58
59 MarkedBlock::Handle* run() override
60 {
61 if (m_done)
62 return nullptr;
63 auto locker = holdLock(m_lock);
64 auto bits = m_directory.m_markingNotEmpty & m_set.m_blocksWithBits;
65 m_index = bits.findBit(m_index, true);
66 if (m_index >= m_directory.m_blocks.size()) {
67 m_done = true;
68 return nullptr;
69 }
70 return m_directory.m_blocks[m_index++];
71 }
72
73 private:
74 IsoCellSet& m_set;
75 BlockDirectory& m_directory;
76 size_t m_index { 0 };
77 Lock m_lock;
78 bool m_done { false };
79 };
80
81 return adoptRef(*new Task(*this));
82}
83
84NEVER_INLINE Bitmap<MarkedBlock::atomsPerBlock>* IsoCellSet::addSlow(size_t blockIndex)
85{
86 auto locker = holdLock(m_subspace.m_directory.m_bitvectorLock);
87 auto& bitsPtrRef = m_bits[blockIndex];
88 auto* bits = bitsPtrRef.get();
89 if (!bits) {
90 bitsPtrRef = std::make_unique<Bitmap<MarkedBlock::atomsPerBlock>>();
91 bits = bitsPtrRef.get();
92 WTF::storeStoreFence();
93 m_blocksWithBits[blockIndex] = true;
94 }
95 return bits;
96}
97
98void IsoCellSet::didResizeBits(size_t newSize)
99{
100 m_blocksWithBits.resize(newSize);
101 m_bits.grow(newSize);
102}
103
104void IsoCellSet::didRemoveBlock(size_t blockIndex)
105{
106 {
107 auto locker = holdLock(m_subspace.m_directory.m_bitvectorLock);
108 m_blocksWithBits[blockIndex] = false;
109 }
110 m_bits[blockIndex] = nullptr;
111}
112
113void IsoCellSet::sweepToFreeList(MarkedBlock::Handle* block)
114{
115 RELEASE_ASSERT(!block->isAllocated());
116
117 if (!m_blocksWithBits[block->index()])
118 return;
119
120 WTF::loadLoadFence();
121
122 if (!m_bits[block->index()]) {
123 dataLog("FATAL: for block index ", block->index(), ":\n");
124 dataLog("Blocks with bits says: ", !!m_blocksWithBits[block->index()], "\n");
125 dataLog("Bits says: ", RawPointer(m_bits[block->index()].get()), "\n");
126 RELEASE_ASSERT_NOT_REACHED();
127 }
128
129 if (block->block().hasAnyNewlyAllocated()) {
130 // The newlyAllocated() bits are a superset of the marks() bits.
131 m_bits[block->index()]->concurrentFilter(block->block().newlyAllocated());
132 return;
133 }
134
135 if (block->isEmpty() || block->areMarksStaleForSweep()) {
136 {
137 // Holding the bitvector lock happens to be enough because that's what we also hold in
138 // other places where we manipulate this bitvector.
139 auto locker = holdLock(m_subspace.m_directory.m_bitvectorLock);
140 m_blocksWithBits[block->index()] = false;
141 }
142 m_bits[block->index()] = nullptr;
143 return;
144 }
145
146 m_bits[block->index()]->concurrentFilter(block->block().marks());
147}
148
149} // namespace JSC
150
151