1/*
2 * Copyright (C) 2011 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef Strong_h
27#define Strong_h
28
29#include <wtf/Assertions.h>
30#include "Handle.h"
31#include "HandleSet.h"
32
33namespace JSC {
34
35class VM;
36
37// A strongly referenced handle that prevents the object it points to from being garbage collected.
38template <typename T> class Strong : public Handle<T> {
39    using Handle<T>::slot;
40    using Handle<T>::setSlot;
41    template <typename U> friend class Strong;
42
43public:
44    typedef typename Handle<T>::ExternalType ExternalType;
45
46    Strong()
47        : Handle<T>()
48    {
49    }
50
51    Strong(VM&, ExternalType = ExternalType());
52
53    Strong(VM&, Handle<T>);
54
55    Strong(const Strong& other)
56        : Handle<T>()
57    {
58        if (!other.slot())
59            return;
60        setSlot(HandleSet::heapFor(other.slot())->allocate());
61        set(other.get());
62    }
63
64    template <typename U> Strong(const Strong<U>& other)
65        : Handle<T>()
66    {
67        if (!other.slot())
68            return;
69        setSlot(HandleSet::heapFor(other.slot())->allocate());
70        set(other.get());
71    }
72
73    enum HashTableDeletedValueTag { HashTableDeletedValue };
74    bool isHashTableDeletedValue() const { return slot() == hashTableDeletedValue(); }
75    Strong(HashTableDeletedValueTag)
76        : Handle<T>(hashTableDeletedValue())
77    {
78    }
79
80    ~Strong()
81    {
82        clear();
83    }
84
85    bool operator!() const { return !slot() || !*slot(); }
86
87    // This conversion operator allows implicit conversion to bool but not to other integer types.
88    typedef JSValue (HandleBase::*UnspecifiedBoolType);
89    operator UnspecifiedBoolType*() const { return !!*this ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
90
91    void swap(Strong& other)
92    {
93        Handle<T>::swap(other);
94    }
95
96    ExternalType get() const { return HandleTypes<T>::getFromSlot(this->slot()); }
97
98    void set(VM&, ExternalType);
99
100    template <typename U> Strong& operator=(const Strong<U>& other)
101    {
102        if (!other.slot()) {
103            clear();
104            return *this;
105        }
106
107        set(*HandleSet::heapFor(other.slot())->vm(), other.get());
108        return *this;
109    }
110
111    Strong& operator=(const Strong& other)
112    {
113        if (!other.slot()) {
114            clear();
115            return *this;
116        }
117
118        set(*HandleSet::heapFor(other.slot())->vm(), other.get());
119        return *this;
120    }
121
122    void clear()
123    {
124        if (!slot())
125            return;
126        HandleSet::heapFor(slot())->deallocate(slot());
127        setSlot(0);
128    }
129
130private:
131    static HandleSlot hashTableDeletedValue() { return reinterpret_cast<HandleSlot>(-1); }
132
133    void set(ExternalType externalType)
134    {
135        ASSERT(slot());
136        JSValue value = HandleTypes<T>::toJSValue(externalType);
137        HandleSet::heapFor(slot())->writeBarrier(slot(), value);
138        *slot() = value;
139    }
140};
141
142template<class T> inline void swap(Strong<T>& a, Strong<T>& b)
143{
144    a.swap(b);
145}
146
147} // namespace JSC
148
149namespace WTF {
150
151template<typename T> struct VectorTraits<JSC::Strong<T>> : SimpleClassVectorTraits {
152    static const bool canCompareWithMemcmp = false;
153};
154
155template<typename P> struct HashTraits<JSC::Strong<P>> : SimpleClassHashTraits<JSC::Strong<P>> { };
156
157}
158
159#endif // Strong_h
160