1/*
2 * Copyright (C) 2008, 2009 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 COMPUTER, 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 COMPUTER, 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#ifndef StructureTransitionTable_h
27#define StructureTransitionTable_h
28
29#include "UString.h"
30#include "WeakGCMap.h"
31#include <wtf/HashFunctions.h>
32#include <wtf/HashTraits.h>
33#include <wtf/OwnPtr.h>
34#include <wtf/RefPtr.h>
35
36namespace JSC {
37
38class Structure;
39
40class StructureTransitionTable {
41    static const intptr_t UsingSingleSlotFlag = 1;
42
43    struct Hash {
44        typedef std::pair<RefPtr<StringImpl>, unsigned> Key;
45        static unsigned hash(const Key& p)
46        {
47            return p.first->existingHash();
48        }
49
50        static bool equal(const Key& a, const Key& b)
51        {
52            return a == b;
53        }
54
55        static const bool safeToCompareToEmptyOrDeleted = true;
56    };
57
58    struct HashTraits {
59        typedef WTF::HashTraits<RefPtr<StringImpl> > FirstTraits;
60        typedef WTF::GenericHashTraits<unsigned> SecondTraits;
61        typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType;
62
63        static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero;
64        static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); }
65
66        static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction;
67
68        static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); }
69        static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
70    };
71
72    struct WeakGCMapFinalizerCallback {
73        static void* finalizerContextFor(Hash::Key)
74        {
75            return 0;
76        }
77
78        static inline Hash::Key keyForFinalizer(void* context, Structure* structure)
79        {
80            return keyForWeakGCMapFinalizer(context, structure);
81        }
82    };
83
84    typedef WeakGCMap<Hash::Key, Structure, WeakGCMapFinalizerCallback, Hash, HashTraits> TransitionMap;
85
86    static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*);
87
88public:
89    StructureTransitionTable()
90        : m_data(UsingSingleSlotFlag)
91    {
92    }
93
94    ~StructureTransitionTable()
95    {
96        if (!isUsingSingleSlot())
97            delete map();
98        else
99            clearSingleTransition();
100    }
101
102    inline void add(JSGlobalData&, Structure*);
103    inline void remove(Structure*);
104    inline bool contains(StringImpl* rep, unsigned attributes) const;
105    inline Structure* get(StringImpl* rep, unsigned attributes) const;
106
107private:
108    bool isUsingSingleSlot() const
109    {
110        return m_data & UsingSingleSlotFlag;
111    }
112
113    TransitionMap* map() const
114    {
115        ASSERT(!isUsingSingleSlot());
116        return reinterpret_cast<TransitionMap*>(m_data);
117    }
118
119    HandleSlot slot() const
120    {
121        ASSERT(isUsingSingleSlot());
122        return reinterpret_cast<HandleSlot>(m_data & ~UsingSingleSlotFlag);
123    }
124
125    void setMap(TransitionMap* map)
126    {
127        ASSERT(isUsingSingleSlot());
128
129        if (HandleSlot slot = this->slot())
130            HandleHeap::heapFor(slot)->deallocate(slot);
131
132        // This implicitly clears the flag that indicates we're using a single transition
133        m_data = reinterpret_cast<intptr_t>(map);
134
135        ASSERT(!isUsingSingleSlot());
136    }
137
138    Structure* singleTransition() const
139    {
140        ASSERT(isUsingSingleSlot());
141        if (HandleSlot slot = this->slot()) {
142            if (*slot)
143                return reinterpret_cast<Structure*>(slot->asCell());
144        }
145        return 0;
146    }
147
148    void clearSingleTransition()
149    {
150        ASSERT(isUsingSingleSlot());
151        if (HandleSlot slot = this->slot())
152            HandleHeap::heapFor(slot)->deallocate(slot);
153    }
154
155    void setSingleTransition(JSGlobalData& globalData, Structure* structure)
156    {
157        ASSERT(isUsingSingleSlot());
158        HandleSlot slot = this->slot();
159        if (!slot) {
160            slot = globalData.allocateGlobalHandle();
161            HandleHeap::heapFor(slot)->makeWeak(slot, 0, 0);
162            m_data = reinterpret_cast<intptr_t>(slot) | UsingSingleSlotFlag;
163        }
164        HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast<JSCell*>(structure));
165        *slot = reinterpret_cast<JSCell*>(structure);
166    }
167
168    intptr_t m_data;
169};
170
171} // namespace JSC
172
173#endif // StructureTransitionTable_h
174