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

Last change on this file since 48068 was 48068, checked in by Darin Adler, 16 years ago

DateInstance object collected on ARM JIT (JSValue: WTF_USE_JSVALUE32)
https://bugs.webkit.org/show_bug.cgi?id=28909

Patch by Darin Adler <Darin Adler> on 2009-09-04
Reviewed by Geoff Garen.

Part two.

Make some improvements to garbage collection code:

1) Create a runtime assertion that catches any classes that

override markChildren but have the HasDefaultMark bit set.

2) Remove checks of the mark bit outside the MarkStack::append

function; they are redundant.

3) Improve the efficiency of the asObject and asArray functions

when called on JSCell* to avoid a round trip to JSValue.

4) Make more callers use the checked asCell and asObject

casting functions rather than unchecked casts.

5) Removed the JSCell::marked function and other GC-related

functions because these operations are no longer things that
code other than the core GC code needs to do directly. Fixed
callers that were calling them.

  • runtime/Collector.cpp:

(JSC::Heap::markConservatively): Removed unneeded call to MarkStack::drain.
(JSC::Heap::markProtectedObjects): Removed unneeded check of the mark
bit and call to MarkStack::drain.
(JSC::Heap::collect): Removed unneeded checks of the mark bit and also
changed call to SmallStrings::mark to call markChildren instead to match
the rest of the objects.
(JSC::typeName): Removed unneeded cast to JSObject*.

  • runtime/JSArray.h:

(JSC::asArray): Added an overload for JSCell* and changed the JSValue
version to call it. Removed some unneeded casts.
(JSC::JSArray::markChildrenDirect): Marked this function inline. It's in
a header, and if not marked inline this could lead to linking problems.
(JSC::MarkStack::markChildren): Added. This helper function is used by
the drain function to avoid repating code. Also added the code here to
check fro default mark violations in debug code. If a markChildren
function adds something to the mark stack, but the type info claimed
hasDefaultMark was true, then we will get an assertion now. Also fixed
the assertion about the mark bit to use the Heap function directly
because we don't have a JSCell::marked function any more.
(JSC::MarkStack::drain): Changed a local variable from "v" to "value",
and from "currentCell" to "cell". Changed to call markChildren in two
places instead of repeating a chain of if statements twice. Changed
code that reads and writes the mark bit to use Heap::isCellMarked and
Heap::markCell so we can eliminate the JSCell::marked and
JSCell::markCellDirect functions.

  • runtime/JSCell.h: Removed JSCell's markCellDirect and marked member

functions. Added a comment explaining that asCell should be deprecated
in favor of the JSValue asCell member function.
(JSC::MarkStack::append): Added the assertion that catches callers
that have set the HasDefaultMark bit incorrectly. Changed
code that reads and writes the mark bit to use Heap::isCellMarked and
Heap::markCell so we can eliminate the JSCell::marked and
JSCell::markCellDirect functions. Moved the overload of
MarkStack::append for JSValue here so it can call through to the cell
version. The old version had a copy of all the code instead, but that
repeated the conversion from JSValue to JSCell* and the check for
whether a value is a cell multiple times.
(JSC::Structure::markAggregate): Moved this function here to avoid
dependencies for Structure.h, since this calls MarkStack::append.

  • runtime/JSObject.cpp:

(JSC::JSObject::markChildren): Added code to clear
m_isCheckingForDefaultMarkViolation so the marking done by JSObject
doesn't trigger the assertion.

  • runtime/JSValue.h: Moved some stray includes that were outside the

header guard inside it. Not sure how that happened! Removed the
GC-related member functions markChildren, hasChildren, marked, and
markDirect.

  • runtime/JSWrapperObject.h: Made markChildren private.

(JSC::JSWrapperObject::createStructure): Added. Fixes a bug where the
HasDefaultMark bit was set.

  • runtime/MarkStack.h: Added m_isCheckingForDefaultMarkViolation and

initialized it to false. Moved the append function body from here to
JSCell.h. Added a declaration of a private markChildren function used
inside the drain function.

  • runtime/SmallStrings.cpp:

(JSC::SmallStrings::markChildren): Changed the name and style of this
function to match other functions. This allows us to share the normal
mark stack code path.

  • runtime/SmallStrings.h: Changed the name and interface of mark to

the more-normal markChildren style.

  • runtime/Structure.h: Moved the body of markAggregate into the

JSCell.h to avoid a circular dependency with JSCell.h.

File size: 9.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 "PropertyMapHashTable.h"
33#include "StructureChain.h"
34#include "StructureTransitionTable.h"
35#include "TypeInfo.h"
36#include "UString.h"
37#include <wtf/PassRefPtr.h>
38#include <wtf/RefCounted.h>
39
40#ifndef NDEBUG
41#define DUMP_PROPERTYMAP_STATS 0
42#else
43#define DUMP_PROPERTYMAP_STATS 0
44#endif
45
46namespace JSC {
47
48 class MarkStack;
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&);
77
78 // These should be used with caution.
79 size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
80 size_t removePropertyWithoutTransition(const Identifier& propertyName);
81 void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; }
82
83 bool isDictionary() const { return m_isDictionary; }
84
85 const TypeInfo& typeInfo() const { return m_typeInfo; }
86
87 JSValue storedPrototype() const { return m_prototype; }
88 JSValue prototypeForLookup(ExecState*) const;
89 StructureChain* prototypeChain(ExecState*) const;
90
91 Structure* previousID() const { return m_previous.get(); }
92
93 void growPropertyStorageCapacity();
94 size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; }
95 size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
96 bool isUsingInlineStorage() const;
97
98 size_t get(const Identifier& propertyName);
99 size_t get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue);
100 size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
101 {
102 ASSERT(!propertyName.isNull());
103 return get(propertyName.ustring().rep(), attributes, specificValue);
104 }
105 bool transitionedFor(const JSCell* specificValue)
106 {
107 return m_specificValueInPrevious == specificValue;
108 }
109 bool hasTransition(UString::Rep*, unsigned attributes);
110 bool hasTransition(const Identifier& propertyName, unsigned attributes)
111 {
112 return hasTransition(propertyName._ustring.rep(), attributes);
113 }
114
115 void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*);
116
117 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
118 void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
119
120 bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; }
121
122 JSCell* specificValue() { return m_specificValueInPrevious; }
123 void despecifyDictionaryFunction(const Identifier& propertyName);
124
125 private:
126 Structure(JSValue prototype, const TypeInfo&);
127
128 size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
129 size_t remove(const Identifier& propertyName);
130 void getEnumerableNamesFromPropertyTable(PropertyNameArray&);
131 void getEnumerableNamesFromClassInfoTable(ExecState*, const ClassInfo*, PropertyNameArray&);
132
133 void expandPropertyMapHashTable();
134 void rehashPropertyMapHashTable();
135 void rehashPropertyMapHashTable(unsigned newTableSize);
136 void createPropertyMapHashTable();
137 void createPropertyMapHashTable(unsigned newTableSize);
138 void insertIntoPropertyMapHashTable(const PropertyMapEntry&);
139 void checkConsistency();
140
141 bool despecifyFunction(const Identifier&);
142
143 PropertyMapHashTable* copyPropertyTable();
144 void materializePropertyMap();
145 void materializePropertyMapIfNecessary()
146 {
147 if (m_propertyTable || !m_previous)
148 return;
149 materializePropertyMap();
150 }
151
152 void clearEnumerationCache();
153
154 signed char transitionCount() const
155 {
156 // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
157 return m_offset == noOffset ? 0 : m_offset + 1;
158 }
159
160 bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
161
162 static const unsigned emptyEntryIndex = 0;
163
164 static const signed char s_maxTransitionLength = 64;
165
166 static const signed char noOffset = -1;
167
168 TypeInfo m_typeInfo;
169
170 JSValue m_prototype;
171 mutable RefPtr<StructureChain> m_cachedPrototypeChain;
172
173 RefPtr<Structure> m_previous;
174 RefPtr<UString::Rep> m_nameInPrevious;
175 JSCell* m_specificValueInPrevious;
176
177 union {
178 Structure* singleTransition;
179 StructureTransitionTable* table;
180 } m_transitions;
181
182 RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;
183
184 PropertyMapHashTable* m_propertyTable;
185
186 size_t m_propertyStorageCapacity;
187 signed char m_offset;
188
189 bool m_isDictionary : 1;
190 bool m_isPinnedPropertyTable : 1;
191 bool m_hasGetterSetterProperties : 1;
192 bool m_usingSingleTransitionSlot : 1;
193 unsigned m_attributesInPrevious : 7;
194 };
195
196 inline size_t Structure::get(const Identifier& propertyName)
197 {
198 ASSERT(!propertyName.isNull());
199
200 materializePropertyMapIfNecessary();
201 if (!m_propertyTable)
202 return WTF::notFound;
203
204 UString::Rep* rep = propertyName._ustring.rep();
205
206 unsigned i = rep->computedHash();
207
208#if DUMP_PROPERTYMAP_STATS
209 ++numProbes;
210#endif
211
212 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
213 if (entryIndex == emptyEntryIndex)
214 return WTF::notFound;
215
216 if (rep == m_propertyTable->entries()[entryIndex - 1].key)
217 return m_propertyTable->entries()[entryIndex - 1].offset;
218
219#if DUMP_PROPERTYMAP_STATS
220 ++numCollisions;
221#endif
222
223 unsigned k = 1 | WTF::doubleHash(rep->computedHash());
224
225 while (1) {
226 i += k;
227
228#if DUMP_PROPERTYMAP_STATS
229 ++numRehashes;
230#endif
231
232 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
233 if (entryIndex == emptyEntryIndex)
234 return WTF::notFound;
235
236 if (rep == m_propertyTable->entries()[entryIndex - 1].key)
237 return m_propertyTable->entries()[entryIndex - 1].offset;
238 }
239 }
240
241 bool StructureTransitionTable::contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
242 {
243 TransitionTable::iterator find = m_table.find(key);
244 if (find == m_table.end())
245 return false;
246
247 return find->second.first || find->second.second->transitionedFor(specificValue);
248 }
249
250 Structure* StructureTransitionTable::get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
251 {
252 Transition transition = m_table.get(key);
253 if (transition.second && transition.second->transitionedFor(specificValue))
254 return transition.second;
255 return transition.first;
256 }
257} // namespace JSC
258
259#endif // Structure_h
Note: See TracBrowser for help on using the repository browser.