source: webkit/trunk/JavaScriptCore/kjs/StructureID.cpp@ 37799

Last change on this file since 37799 was 37747, checked in by [email protected], 17 years ago

2008-10-16 Sam Weinig <[email protected]>

Reviewed by Cameron Zwarich.

Fix for https://bugs.webkit.org/show_bug.cgi?id=21683
Don't create intermediate StructureIDs for builtin objects

Second stage in reduce number of StructureIDs created when initializing the
JSGlobalObject.

  • Use putDirectWithoutTransition for the remaining singleton objects to reduce the number of StructureIDs create for about:blank from 132 to 73.
  • kjs/ArrayConstructor.cpp: (JSC::ArrayConstructor::ArrayConstructor):
  • kjs/BooleanConstructor.cpp: (JSC::BooleanConstructor::BooleanConstructor):
  • kjs/BooleanPrototype.cpp: (JSC::BooleanPrototype::BooleanPrototype):
  • kjs/DateConstructor.cpp: (JSC::DateConstructor::DateConstructor):
  • kjs/ErrorConstructor.cpp: (JSC::ErrorConstructor::ErrorConstructor):
  • kjs/ErrorPrototype.cpp: (JSC::ErrorPrototype::ErrorPrototype):
  • kjs/FunctionConstructor.cpp: (JSC::FunctionConstructor::FunctionConstructor):
  • kjs/FunctionPrototype.cpp: (JSC::FunctionPrototype::FunctionPrototype): (JSC::FunctionPrototype::addFunctionProperties):
  • kjs/FunctionPrototype.h: (JSC::FunctionPrototype::createStructureID):
  • kjs/InternalFunction.cpp:
  • kjs/InternalFunction.h: (JSC::InternalFunction::InternalFunction):
  • kjs/JSGlobalObject.cpp: (JSC::JSGlobalObject::reset):
  • kjs/JSObject.h:
  • kjs/MathObject.cpp: (JSC::MathObject::MathObject):
  • kjs/NumberConstructor.cpp: (JSC::NumberConstructor::NumberConstructor):
  • kjs/NumberPrototype.cpp: (JSC::NumberPrototype::NumberPrototype):
  • kjs/ObjectConstructor.cpp: (JSC::ObjectConstructor::ObjectConstructor):
  • kjs/RegExpConstructor.cpp: (JSC::RegExpConstructor::RegExpConstructor):
  • kjs/RegExpPrototype.cpp: (JSC::RegExpPrototype::RegExpPrototype):
  • kjs/StringConstructor.cpp: (JSC::StringConstructor::StringConstructor):
  • kjs/StringPrototype.cpp: (JSC::StringPrototype::StringPrototype):
  • kjs/StructureID.cpp: (JSC::StructureID::dumpStatistics):
  • kjs/StructureID.h: (JSC::StructureID::setPrototypeWithoutTransition):
File size: 13.9 KB
Line 
1/*
2 * Copyright (C) 2008 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#include "config.h"
27#include "StructureID.h"
28
29#include "JSObject.h"
30#include "PropertyNameArray.h"
31#include "identifier.h"
32#include "lookup.h"
33#include <wtf/RefCountedLeakCounter.h>
34#include <wtf/RefPtr.h>
35
36#if ENABLE(JSC_MULTIPLE_THREADS)
37#include <wtf/Threading.h>
38#endif
39
40using namespace std;
41
42namespace JSC {
43
44#ifndef NDEBUG
45static WTF::RefCountedLeakCounter structureIDCounter("StructureID");
46
47#if ENABLE(JSC_MULTIPLE_THREADS)
48static Mutex ignoreSetMutex;
49#endif
50
51static bool shouldIgnoreLeaks;
52static HashSet<StructureID*> ignoreSet;
53#endif
54
55#if DUMP_STRUCTURE_ID_STATISTICS
56static HashSet<StructureID*> liveStructureIDSet;
57
58void StructureID::dumpStatistics()
59{
60 unsigned numberLeaf = 0;
61 unsigned numberUsingSingleSlot = 0;
62 unsigned numberSingletons = 0;
63
64 HashSet<StructureID*>::const_iterator end = liveStructureIDSet.end();
65 for (HashSet<StructureID*>::const_iterator it = liveStructureIDSet.begin(); it != end; ++it) {
66 StructureID* structureID = *it;
67 if (structureID->m_usingSingleTransitionSlot) {
68 if (!structureID->m_transitions.singleTransition)
69 ++numberLeaf;
70 else
71 ++numberUsingSingleSlot;
72
73 if (!structureID->m_previous && !structureID->m_transitions.singleTransition)
74 ++numberSingletons;
75 }
76 }
77
78 printf("Number of live StructureIDs: %d\n", liveStructureIDSet.size());
79 printf("Number of StructureIDs using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
80 printf("Number of StructureIDs that are leaf nodes: %d\n", numberLeaf);
81 printf("Number of StructureIDs that singletons: %d\n", numberSingletons);
82}
83#endif
84
85StructureID::StructureID(JSValuePtr prototype, const TypeInfo& typeInfo)
86 : m_typeInfo(typeInfo)
87 , m_isDictionary(false)
88 , m_hasGetterSetterProperties(false)
89 , m_prototype(prototype)
90 , m_cachedPrototypeChain(0)
91 , m_previous(0)
92 , m_nameInPrevious(0)
93 , m_transitionCount(0)
94 , m_usingSingleTransitionSlot(true)
95 , m_propertyStorageCapacity(JSObject::inlineStorageCapacity)
96 , m_cachedTransistionOffset(WTF::notFound)
97{
98 ASSERT(m_prototype);
99 ASSERT(m_prototype->isObject() || m_prototype->isNull());
100
101 m_transitions.singleTransition = 0;
102
103#ifndef NDEBUG
104#if ENABLE(JSC_MULTIPLE_THREADS)
105 MutexLocker protect(ignoreSetMutex);
106#endif
107 if (shouldIgnoreLeaks)
108 ignoreSet.add(this);
109 else
110 structureIDCounter.increment();
111#endif
112
113#if DUMP_STRUCTURE_ID_STATISTICS
114 liveStructureIDSet.add(this);
115#endif
116}
117
118StructureID::~StructureID()
119{
120 if (m_previous) {
121 if (m_previous->m_usingSingleTransitionSlot) {
122 m_previous->m_transitions.singleTransition = 0;
123 } else {
124 ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious, m_attributesInPrevious)));
125 m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious, m_attributesInPrevious));
126 }
127 }
128
129 if (m_cachedPropertyNameArrayData)
130 m_cachedPropertyNameArrayData->setCachedStructureID(0);
131
132 if (!m_usingSingleTransitionSlot)
133 delete m_transitions.table;
134
135#ifndef NDEBUG
136#if ENABLE(JSC_MULTIPLE_THREADS)
137 MutexLocker protect(ignoreSetMutex);
138#endif
139 HashSet<StructureID*>::iterator it = ignoreSet.find(this);
140 if (it != ignoreSet.end())
141 ignoreSet.remove(it);
142 else
143 structureIDCounter.decrement();
144#endif
145
146#if DUMP_STRUCTURE_ID_STATISTICS
147 liveStructureIDSet.remove(this);
148#endif
149}
150
151void StructureID::startIgnoringLeaks()
152{
153#ifndef NDEBUG
154 shouldIgnoreLeaks = true;
155#endif
156}
157
158void StructureID::stopIgnoringLeaks()
159{
160#ifndef NDEBUG
161 shouldIgnoreLeaks = false;
162#endif
163}
164
165void StructureID::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject)
166{
167 bool shouldCache = propertyNames.cacheable() && !(propertyNames.size() || m_isDictionary);
168
169 if (shouldCache) {
170 if (m_cachedPropertyNameArrayData) {
171 if (structureIDChainsAreEqual(m_cachedPropertyNameArrayData->cachedPrototypeChain(), cachedPrototypeChain())) {
172 propertyNames.setData(m_cachedPropertyNameArrayData);
173 return;
174 }
175 }
176 propertyNames.setCacheable(false);
177 }
178
179 m_propertyMap.getEnumerablePropertyNames(propertyNames);
180
181 // Add properties from the static hashtables of properties
182 for (const ClassInfo* info = baseObject->classInfo(); info; info = info->parentClass) {
183 const HashTable* table = info->propHashTable(exec);
184 if (!table)
185 continue;
186 table->initializeIfNeeded(exec);
187 ASSERT(table->table);
188 int hashSizeMask = table->hashSizeMask;
189 const HashEntry* entry = table->table;
190 for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
191 if (entry->key() && !(entry->attributes() & DontEnum))
192 propertyNames.add(entry->key());
193 }
194 }
195
196 if (m_prototype->isObject())
197 asObject(m_prototype)->getPropertyNames(exec, propertyNames);
198
199 if (shouldCache) {
200 if (m_cachedPropertyNameArrayData)
201 m_cachedPropertyNameArrayData->setCachedStructureID(0);
202
203 m_cachedPropertyNameArrayData = propertyNames.data();
204
205 StructureIDChain* chain = cachedPrototypeChain();
206 if (!chain)
207 chain = createCachedPrototypeChain();
208 m_cachedPropertyNameArrayData->setCachedPrototypeChain(chain);
209 m_cachedPropertyNameArrayData->setCachedStructureID(this);
210 }
211}
212
213void StructureID::clearEnumerationCache()
214{
215 if (m_cachedPropertyNameArrayData)
216 m_cachedPropertyNameArrayData->setCachedStructureID(0);
217 m_cachedPropertyNameArrayData.clear();
218}
219
220void StructureID::growPropertyStorageCapacity()
221{
222 if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity)
223 m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity;
224 else
225 m_propertyStorageCapacity *= 2;
226}
227
228PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structureID, const Identifier& propertyName, unsigned attributes, size_t& offset)
229{
230 ASSERT(!structureID->m_isDictionary);
231 ASSERT(structureID->typeInfo().type() == ObjectType);
232
233 if (structureID->m_usingSingleTransitionSlot) {
234 StructureID* existingTransition = structureID->m_transitions.singleTransition;
235 if (existingTransition && existingTransition->m_nameInPrevious == propertyName.ustring().rep() && existingTransition->m_attributesInPrevious == attributes) {
236 offset = structureID->m_transitions.singleTransition->cachedTransistionOffset();
237 ASSERT(offset != WTF::notFound);
238 return existingTransition;
239 }
240 } else {
241 if (StructureID* existingTransition = structureID->m_transitions.table->get(make_pair(propertyName.ustring().rep(), attributes))) {
242 offset = existingTransition->cachedTransistionOffset();
243 ASSERT(offset != WTF::notFound);
244 return existingTransition;
245 }
246 }
247
248 if (structureID->m_transitionCount > s_maxTransitionLength) {
249 RefPtr<StructureID> transition = toDictionaryTransition(structureID);
250 offset = transition->m_propertyMap.put(propertyName, attributes);
251 if (transition->m_propertyMap.storageSize() > transition->propertyStorageCapacity())
252 transition->growPropertyStorageCapacity();
253 return transition.release();
254 }
255
256 RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo());
257 transition->m_cachedPrototypeChain = structureID->m_cachedPrototypeChain;
258 transition->m_previous = structureID;
259 transition->m_nameInPrevious = propertyName.ustring().rep();
260 transition->m_attributesInPrevious = attributes;
261 transition->m_transitionCount = structureID->m_transitionCount + 1;
262 transition->m_propertyMap = structureID->m_propertyMap;
263 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;
264 transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties;
265
266 offset = transition->m_propertyMap.put(propertyName, attributes);
267 if (transition->m_propertyMap.storageSize() > transition->propertyStorageCapacity())
268 transition->growPropertyStorageCapacity();
269
270 transition->setCachedTransistionOffset(offset);
271
272 if (structureID->m_usingSingleTransitionSlot) {
273 if (!structureID->m_transitions.singleTransition) {
274 structureID->m_transitions.singleTransition = transition.get();
275 return transition.release();
276 }
277
278 StructureID* existingTransition = structureID->m_transitions.singleTransition;
279 structureID->m_usingSingleTransitionSlot = false;
280 TransitionTable* transitionTable = new TransitionTable;
281 structureID->m_transitions.table = transitionTable;
282 transitionTable->add(make_pair(existingTransition->m_nameInPrevious, existingTransition->m_attributesInPrevious), existingTransition);
283 }
284 structureID->m_transitions.table->add(make_pair(propertyName.ustring().rep(), attributes), transition.get());
285 return transition.release();
286}
287
288PassRefPtr<StructureID> StructureID::toDictionaryTransition(StructureID* structureID)
289{
290 ASSERT(!structureID->m_isDictionary);
291
292 RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo());
293 transition->m_isDictionary = true;
294 transition->m_propertyMap = structureID->m_propertyMap;
295 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;
296 transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties;
297 return transition.release();
298}
299
300PassRefPtr<StructureID> StructureID::fromDictionaryTransition(StructureID* structureID)
301{
302 ASSERT(structureID->m_isDictionary);
303
304 // Since dictionary StructureIDs are not shared, and no opcodes specialize
305 // for them, we don't need to allocate a new StructureID when transitioning
306 // to non-dictionary status.
307 structureID->m_isDictionary = false;
308 return structureID;
309}
310
311PassRefPtr<StructureID> StructureID::changePrototypeTransition(StructureID* structureID, JSValuePtr prototype)
312{
313 RefPtr<StructureID> transition = create(prototype, structureID->typeInfo());
314 transition->m_transitionCount = structureID->m_transitionCount + 1;
315 transition->m_propertyMap = structureID->m_propertyMap;
316 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;
317 transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties;
318 return transition.release();
319}
320
321PassRefPtr<StructureID> StructureID::getterSetterTransition(StructureID* structureID)
322{
323 RefPtr<StructureID> transition = create(structureID->storedPrototype(), structureID->typeInfo());
324 transition->m_transitionCount = structureID->m_transitionCount + 1;
325 transition->m_propertyMap = structureID->m_propertyMap;
326 transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity;
327 transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties;
328 return transition.release();
329}
330
331size_t StructureID::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes)
332{
333 size_t offset = m_propertyMap.put(propertyName, attributes);
334 if (m_propertyMap.storageSize() > propertyStorageCapacity())
335 growPropertyStorageCapacity();
336 return offset;
337}
338
339StructureIDChain* StructureID::createCachedPrototypeChain()
340{
341 ASSERT(typeInfo().type() == ObjectType);
342 ASSERT(!m_cachedPrototypeChain);
343
344 JSValuePtr prototype = storedPrototype();
345 if (JSImmediate::isImmediate(prototype))
346 return 0;
347
348 RefPtr<StructureIDChain> chain = StructureIDChain::create(asObject(prototype)->structureID());
349 setCachedPrototypeChain(chain.release());
350 return cachedPrototypeChain();
351}
352
353StructureIDChain::StructureIDChain(StructureID* structureID)
354{
355 size_t size = 1;
356
357 StructureID* tmp = structureID;
358 while (!tmp->storedPrototype()->isNull()) {
359 ++size;
360 tmp = asCell(tmp->storedPrototype())->structureID();
361 }
362
363 m_vector.set(new RefPtr<StructureID>[size + 1]);
364
365 size_t i;
366 for (i = 0; i < size - 1; ++i) {
367 m_vector[i] = structureID;
368 structureID = asObject(structureID->storedPrototype())->structureID();
369 }
370 m_vector[i] = structureID;
371 m_vector[i + 1] = 0;
372}
373
374bool structureIDChainsAreEqual(StructureIDChain* chainA, StructureIDChain* chainB)
375{
376 if (!chainA || !chainB)
377 return false;
378
379 RefPtr<StructureID>* a = chainA->head();
380 RefPtr<StructureID>* b = chainB->head();
381 while (1) {
382 if (*a != *b)
383 return false;
384 if (!*a)
385 return true;
386 a++;
387 b++;
388 }
389}
390
391} // namespace JSC
Note: See TracBrowser for help on using the repository browser.