source: webkit/trunk/JavaScriptCore/runtime/Structure.h@ 47304

Last change on this file since 47304 was 47022, checked in by [email protected], 16 years ago

Stack overflow crash in JavaScript garbage collector mark pass
https://bugs.webkit.org/show_bug.cgi?id=12216

Reviewed by Gavin Barraclough and Sam Weinig

Make the GC mark phase iterative by using an explicit mark stack.
To do this marking any single object is performed in multiple stages

  • The object is appended to the MarkStack, this sets the marked bit for the object using the new markDirect() function, and then returns
  • When the MarkStack is drain()ed the object is popped off the stack and markChildren(MarkStack&) is called on the object to collect all of its children. drain() then repeats until the stack is empty.

Additionally I renamed a number of methods from 'mark' to 'markAggregate'
in order to make it more clear that marking of those object was not
going to result in an actual recursive mark.

File size: 8.8 KB
Line 
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 Structure_h
27#define Structure_h
28
29#include "Identifier.h"
30#include "JSType.h"
31#include "JSValue.h"
32#include "MarkStack.h"
33#include "PropertyMapHashTable.h"
34#include "StructureChain.h"
35#include "StructureTransitionTable.h"
36#include "TypeInfo.h"
37#include "UString.h"
38#include <wtf/PassRefPtr.h>
39#include <wtf/RefCounted.h>
40
41#ifndef NDEBUG
42#define DUMP_PROPERTYMAP_STATS 0
43#else
44#define DUMP_PROPERTYMAP_STATS 0
45#endif
46
47namespace JSC {
48
49 class PropertyNameArray;
50 class PropertyNameArrayData;
51
52 class Structure : public RefCounted<Structure> {
53 public:
54 friend class JIT;
55 static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo)
56 {
57 return adoptRef(new Structure(prototype, typeInfo));
58 }
59
60 static void startIgnoringLeaks();
61 static void stopIgnoringLeaks();
62
63 static void dumpStatistics();
64
65 static PassRefPtr<Structure> addPropertyTransition(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
66 static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
67 static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
68 static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
69 static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
70 static PassRefPtr<Structure> getterSetterTransition(Structure*);
71 static PassRefPtr<Structure> toDictionaryTransition(Structure*);
72 static PassRefPtr<Structure> fromDictionaryTransition(Structure*);
73
74 ~Structure();
75
76 void markAggregate(MarkStack& markStack)
77 {
78 markStack.append(m_prototype);
79 }
80
81 // These should be used with caution.
82 size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
83 size_t removePropertyWithoutTransition(const Identifier& propertyName);
84 void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; }
85
86 bool isDictionary() const { return m_isDictionary; }
87
88 const TypeInfo& typeInfo() const { return m_typeInfo; }
89
90 JSValue storedPrototype() const { return m_prototype; }
91 JSValue prototypeForLookup(ExecState*) const;
92 StructureChain* prototypeChain(ExecState*) const;
93
94 Structure* previousID() const { return m_previous.get(); }
95
96 void growPropertyStorageCapacity();
97 size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; }
98 size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
99 bool isUsingInlineStorage() const;
100
101 size_t get(const Identifier& propertyName);
102 size_t get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue);
103 size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
104 {
105 ASSERT(!propertyName.isNull());
106 return get(propertyName._ustring.rep(), attributes, specificValue);
107 }
108
109 void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*);
110
111 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
112 void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
113
114 bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; }
115
116 JSCell* specificValue() { return m_specificValueInPrevious; }
117 void despecifyDictionaryFunction(const Identifier& propertyName);
118
119 private:
120 Structure(JSValue prototype, const TypeInfo&);
121
122 size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
123 size_t remove(const Identifier& propertyName);
124 void getEnumerableNamesFromPropertyTable(PropertyNameArray&);
125 void getEnumerableNamesFromClassInfoTable(ExecState*, const ClassInfo*, PropertyNameArray&);
126
127 void expandPropertyMapHashTable();
128 void rehashPropertyMapHashTable();
129 void rehashPropertyMapHashTable(unsigned newTableSize);
130 void createPropertyMapHashTable();
131 void createPropertyMapHashTable(unsigned newTableSize);
132 void insertIntoPropertyMapHashTable(const PropertyMapEntry&);
133 void checkConsistency();
134
135 bool despecifyFunction(const Identifier&);
136
137 PropertyMapHashTable* copyPropertyTable();
138 void materializePropertyMap();
139 void materializePropertyMapIfNecessary()
140 {
141 if (m_propertyTable || !m_previous)
142 return;
143 materializePropertyMap();
144 }
145
146 void clearEnumerationCache();
147
148 signed char transitionCount() const
149 {
150 // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
151 return m_offset == noOffset ? 0 : m_offset + 1;
152 }
153
154 bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
155
156 static const unsigned emptyEntryIndex = 0;
157
158 static const signed char s_maxTransitionLength = 64;
159
160 static const signed char noOffset = -1;
161
162 TypeInfo m_typeInfo;
163
164 JSValue m_prototype;
165 mutable RefPtr<StructureChain> m_cachedPrototypeChain;
166
167 RefPtr<Structure> m_previous;
168 RefPtr<UString::Rep> m_nameInPrevious;
169
170 union {
171 Structure* singleTransition;
172 StructureTransitionTable* table;
173 } m_transitions;
174 JSCell* m_specificValueInPrevious;
175
176 RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;
177
178 PropertyMapHashTable* m_propertyTable;
179
180 size_t m_propertyStorageCapacity;
181 signed char m_offset;
182
183 bool m_isDictionary : 1;
184 bool m_isPinnedPropertyTable : 1;
185 bool m_hasGetterSetterProperties : 1;
186 bool m_usingSingleTransitionSlot : 1;
187 unsigned m_attributesInPrevious : 7;
188 };
189
190 inline size_t Structure::get(const Identifier& propertyName)
191 {
192 ASSERT(!propertyName.isNull());
193
194 materializePropertyMapIfNecessary();
195 if (!m_propertyTable)
196 return WTF::notFound;
197
198 UString::Rep* rep = propertyName._ustring.rep();
199
200 unsigned i = rep->computedHash();
201
202#if DUMP_PROPERTYMAP_STATS
203 ++numProbes;
204#endif
205
206 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
207 if (entryIndex == emptyEntryIndex)
208 return WTF::notFound;
209
210 if (rep == m_propertyTable->entries()[entryIndex - 1].key)
211 return m_propertyTable->entries()[entryIndex - 1].offset;
212
213#if DUMP_PROPERTYMAP_STATS
214 ++numCollisions;
215#endif
216
217 unsigned k = 1 | WTF::doubleHash(rep->computedHash());
218
219 while (1) {
220 i += k;
221
222#if DUMP_PROPERTYMAP_STATS
223 ++numRehashes;
224#endif
225
226 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
227 if (entryIndex == emptyEntryIndex)
228 return WTF::notFound;
229
230 if (rep == m_propertyTable->entries()[entryIndex - 1].key)
231 return m_propertyTable->entries()[entryIndex - 1].offset;
232 }
233 }
234
235} // namespace JSC
236
237#endif // Structure_h
Note: See TracBrowser for help on using the repository browser.