1/*
2 * Copyright (C) 2013 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/DeferrableRefCounted.h>
29#include <wtf/Forward.h>
30
31namespace JSC {
32
33class JSCell;
34
35// A C-heap-allocated object that may have additional reference counts
36// due to incoming references from the heap, which are tracked in
37// reverse: the object knows its incoming references. Such objects also
38// have the invariant that they don't have references back into the GC
39// heap.
40
41template<typename T>
42class GCIncomingRefCounted : public DeferrableRefCounted<T> {
43public:
44 GCIncomingRefCounted()
45 : m_encodedPointer(0)
46 {
47 }
48
49 ~GCIncomingRefCounted()
50 {
51 if (hasVectorOfCells())
52 delete vectorOfCells();
53 }
54
55 size_t numberOfIncomingReferences() const
56 {
57 if (!hasAnyIncoming())
58 return 0;
59 if (hasSingleton())
60 return 1;
61 return vectorOfCells()->size();
62 }
63
64 JSCell* incomingReferenceAt(size_t index) const
65 {
66 ASSERT(hasAnyIncoming());
67 if (hasSingleton()) {
68 ASSERT(!index);
69 return singleton();
70 }
71 return vectorOfCells()->at(index);
72 }
73
74 // It's generally not a good idea to call this directly, since if this
75 // returns true, you're supposed to add this object to the GC's list.
76 // Call GCIncomingRefCountedSet::addReference() instead.
77 bool addIncomingReference(JSCell*);
78
79 // A filter function returns true if we wish to keep the incoming
80 // reference, and false if we don't. This may delete the object,
81 // and if it does so, this returns true. In general, you don't want
82 // to use this with a filter function that can return false unless
83 // you're also walking the GC's list.
84 template<typename FilterFunctionType>
85 bool filterIncomingReferences(FilterFunctionType&&);
86
87private:
88 static uintptr_t singletonFlag() { return 1; }
89
90 bool hasVectorOfCells() const { return !(m_encodedPointer & singletonFlag()); }
91 bool hasAnyIncoming() const { return !!m_encodedPointer; }
92 bool hasSingleton() const { return hasAnyIncoming() && !hasVectorOfCells(); }
93
94 JSCell* singleton() const
95 {
96 ASSERT(hasSingleton());
97 return bitwise_cast<JSCell*>(m_encodedPointer & ~singletonFlag());
98 }
99
100 Vector<JSCell*>* vectorOfCells() const
101 {
102 ASSERT(hasVectorOfCells());
103 return bitwise_cast<Vector<JSCell*>*>(m_encodedPointer);
104 }
105
106 // Singleton flag is set: this is a JSCell*.
107 // Singleton flag not set: this is a pointer to a vector of cells.
108 uintptr_t m_encodedPointer;
109};
110
111} // namespace JSC
112