Fix build break after r154861
[WebKit-https.git] / Source / JavaScriptCore / runtime / MapData.h
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. 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 MapData_h
27 #define MapData_h
28
29 #include "CallFrame.h"
30 #include "JSCJSValue.h"
31 #include "JSDestructibleObject.h"
32
33 #include <wtf/HashFunctions.h>
34 #include <wtf/HashMap.h>
35 #include <wtf/MathExtras.h>
36
37 namespace JSC {
38
39 class MapData : public JSDestructibleObject {
40 public:
41     typedef JSDestructibleObject Base;
42
43     struct const_iterator {
44         const_iterator(const MapData*);
45         ~const_iterator();
46         const WTF::KeyValuePair<JSValue, JSValue> operator*() const;
47         JSValue key() const { ASSERT(!atEnd()); return m_mapData->m_entries[m_index].key.get(); }
48         JSValue value() const { ASSERT(!atEnd()); return m_mapData->m_entries[m_index].value.get(); }
49         void operator++();
50         static const_iterator end(const MapData*);
51         bool operator!=(const const_iterator& other);
52         bool operator==(const const_iterator& other);
53
54     private:
55         // This is a bit gnarly. We use an index of -1 to indicate the
56         // "end()" iterator. By casting to unsigned we can immediately
57         // test if both iterators are at the end of their iteration.
58         // We need this in order to keep the common case (eg. iter != end())
59         // fast.
60         bool atEnd() const { return static_cast<size_t>(m_index) >= static_cast<size_t>(m_mapData->m_size); }
61         const MapData* m_mapData;
62         int32_t m_index;
63     };
64
65     struct KeyType {
66         ALWAYS_INLINE KeyType() { }
67         KeyType(JSValue);
68         JSValue value;
69     };
70
71     static MapData* create(VM& vm, JSGlobalObject* globalObject)
72     {
73         MapData* mapData = new (NotNull, allocateCell<MapData>(vm.heap)) MapData(vm, globalObject);
74         mapData->finishCreation(vm);
75         return mapData;
76     }
77
78     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
79     {
80         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
81     }
82
83     void set(CallFrame*, KeyType, JSValue);
84     JSValue get(CallFrame*, KeyType);
85     bool remove(CallFrame*, KeyType);
86     bool contains(CallFrame*, KeyType);
87     size_t size(CallFrame*) const { return m_size - m_deletedCount; }
88
89     const_iterator begin() const { return const_iterator(this); }
90     const_iterator end() const { return const_iterator::end(this); }
91
92     void clear();
93
94     DECLARE_INFO;
95     static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
96
97 private:
98     typedef WTF::UnsignedWithZeroKeyHashTraits<int32_t> IndexTraits;
99
100     // Our marking functions expect Entry to maintain this layout, and have all
101     // fields be WriteBarrier<Unknown>
102     struct Entry {
103         WriteBarrier<Unknown> key;
104         WriteBarrier<Unknown> value;
105     };
106
107     typedef HashMap<EncodedJSValue, int32_t, EncodedJSValueHash, EncodedJSValueHashTraits, IndexTraits> ValueKeyedMap;
108     typedef HashMap<StringImpl*, int32_t, typename WTF::DefaultHash<StringImpl*>::Hash, WTF::HashTraits<StringImpl*>, IndexTraits> StringKeyedMap;
109
110     MapData(VM&, JSGlobalObject*);
111     static void destroy(JSCell*);
112     static void visitChildren(JSCell*, SlotVisitor&);
113     static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
114
115
116     ALWAYS_INLINE Entry* find(CallFrame*, KeyType);
117     ALWAYS_INLINE Entry* add(CallFrame*, KeyType);
118     template <typename Map, typename Key> ALWAYS_INLINE Entry* add(CallFrame*, Map&, Key, KeyType);
119
120     ALWAYS_INLINE bool shouldPack() const { return m_deletedCount && !m_iteratorCount; }
121     CheckedBoolean ensureSpaceForAppend(CallFrame*);
122
123     ALWAYS_INLINE void replaceAndPackBackingStore(Entry* destination, int32_t newSize);
124     ALWAYS_INLINE void replaceBackingStore(Entry* destination, int32_t newSize);
125
126     ValueKeyedMap m_valueKeyedTable;
127     StringKeyedMap m_stringKeyedTable;
128     int32_t m_capacity;
129     int32_t m_size;
130     int32_t m_deletedCount;
131     mutable int32_t m_iteratorCount;
132     Entry* m_entries;
133 };
134
135 ALWAYS_INLINE void MapData::clear()
136 {
137     m_valueKeyedTable.clear();
138     m_stringKeyedTable.clear();
139     m_capacity = 0;
140     m_size = 0;
141     m_deletedCount = 0;
142     m_entries = 0;
143 }
144
145 ALWAYS_INLINE MapData::KeyType::KeyType(JSValue v)
146 {
147     if (!v.isDouble()) {
148         value = v;
149         return;
150     }
151     double d = v.asDouble();
152     if (std::isnan(d) || (std::signbit(d) && d == 0.0)) {
153         value = v;
154         return;
155     }
156
157     int i = static_cast<int>(v.asDouble());
158     if (i != d)
159         value = v;
160     else
161         value = jsNumber(i);
162 }
163
164 ALWAYS_INLINE void MapData::const_iterator::operator++()
165 {
166     ASSERT(!atEnd());
167     Entry* entries = m_mapData->m_entries;
168     size_t index = m_index + 1;
169     size_t end = m_mapData->m_size;
170     while (index < end && !entries[index].key)
171         index++;
172     m_index = index;
173 }
174
175 ALWAYS_INLINE MapData::const_iterator::const_iterator(const MapData* mapData)
176     : m_mapData(mapData)
177     , m_index(0)
178 {
179     m_mapData->m_iteratorCount++;
180 }
181
182 ALWAYS_INLINE MapData::const_iterator::~const_iterator()
183 {
184     m_mapData->m_iteratorCount--;
185 }
186
187 ALWAYS_INLINE const WTF::KeyValuePair<JSValue, JSValue> MapData::const_iterator::operator*() const
188 {
189     Entry* entry = &m_mapData->m_entries[m_index];
190     return WTF::KeyValuePair<JSValue, JSValue>(entry->key.get(), entry->value.get());
191 }
192
193 ALWAYS_INLINE MapData::const_iterator MapData::const_iterator::end(const MapData* mapData)
194 {
195     const_iterator result(mapData);
196     result.m_index = -1;
197     return result;
198 }
199
200 ALWAYS_INLINE bool MapData::const_iterator::operator!=(const const_iterator& other)
201 {
202     ASSERT(other.m_mapData == m_mapData);
203     if (atEnd() && other.atEnd())
204         return false;
205     return m_index != other.m_index;
206 }
207
208 ALWAYS_INLINE bool MapData::const_iterator::operator==(const const_iterator& other)
209 {
210     return !(*this != other);
211 }
212
213 }
214
215 #endif /* !defined(MapData_h) */