]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Structure.cpp
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / runtime / Structure.cpp
CommitLineData
9dae56ea 1/*
ba379fdc 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
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 "Structure.h"
28
29#include "Identifier.h"
30#include "JSObject.h"
f9bf01c6
A
31#include "JSPropertyNameIterator.h"
32#include "Lookup.h"
9dae56ea
A
33#include "PropertyNameArray.h"
34#include "StructureChain.h"
9dae56ea
A
35#include <wtf/RefCountedLeakCounter.h>
36#include <wtf/RefPtr.h>
9dae56ea 37#include <wtf/Threading.h>
9dae56ea
A
38
39#define DUMP_STRUCTURE_ID_STATISTICS 0
40
41#ifndef NDEBUG
42#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
43#else
44#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
45#endif
46
47using namespace std;
48using namespace WTF;
49
14957cd0 50#if DUMP_PROPERTYMAP_STATS
9dae56ea 51
14957cd0
A
52int numProbes;
53int numCollisions;
54int numRehashes;
55int numRemoves;
9dae56ea 56
9dae56ea
A
57#endif
58
14957cd0 59namespace JSC {
9dae56ea
A
60
61#if DUMP_STRUCTURE_ID_STATISTICS
ba379fdc 62static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
9dae56ea
A
63#endif
64
14957cd0 65bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const
4e4e5a6f 66{
14957cd0
A
67 if (isUsingSingleSlot()) {
68 Structure* transition = singleTransition();
69 return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes;
4e4e5a6f 70 }
14957cd0 71 return map()->contains(make_pair(rep, attributes));
4e4e5a6f
A
72}
73
14957cd0 74inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const
4e4e5a6f 75{
14957cd0 76 if (isUsingSingleSlot()) {
4e4e5a6f 77 Structure* transition = singleTransition();
14957cd0 78 return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0;
4e4e5a6f 79 }
14957cd0 80 return map()->get(make_pair(rep, attributes));
4e4e5a6f
A
81}
82
14957cd0 83inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* structure)
4e4e5a6f 84{
14957cd0
A
85 if (isUsingSingleSlot()) {
86 Structure* existingTransition = singleTransition();
87
88 // This handles the first transition being added.
89 if (!existingTransition) {
90 setSingleTransition(globalData, structure);
4e4e5a6f
A
91 return;
92 }
14957cd0
A
93
94 // This handles the second transition being added
95 // (or the first transition being despecified!)
96 setMap(new TransitionMap());
97 add(globalData, existingTransition);
4e4e5a6f 98 }
14957cd0
A
99
100 // Add the structure to the map.
101
102 // Newer versions of the STL have an std::make_pair function that takes rvalue references.
103 // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
104 // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
6fe7ccc8
A
105 TransitionMap::AddResult result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
106 if (!result.isNewEntry) {
14957cd0 107 // There already is an entry! - we should only hit this when despecifying.
6fe7ccc8 108 ASSERT(result.iterator.get().second->m_specificValueInPrevious);
14957cd0 109 ASSERT(!structure->m_specificValueInPrevious);
6fe7ccc8 110 map()->set(globalData, result.iterator.get().first, structure);
4e4e5a6f
A
111 }
112}
113
9dae56ea
A
114void Structure::dumpStatistics()
115{
116#if DUMP_STRUCTURE_ID_STATISTICS
117 unsigned numberLeaf = 0;
118 unsigned numberUsingSingleSlot = 0;
119 unsigned numberSingletons = 0;
120 unsigned numberWithPropertyMaps = 0;
121 unsigned totalPropertyMapsSize = 0;
122
123 HashSet<Structure*>::const_iterator end = liveStructureSet.end();
124 for (HashSet<Structure*>::const_iterator it = liveStructureSet.begin(); it != end; ++it) {
125 Structure* structure = *it;
14957cd0
A
126
127 switch (structure->m_transitionTable.size()) {
128 case 0:
9dae56ea 129 ++numberLeaf;
14957cd0
A
130 if (!structure->m_previous)
131 ++numberSingletons;
132 break;
9dae56ea 133
14957cd0
A
134 case 1:
135 ++numberUsingSingleSlot;
136 break;
9dae56ea
A
137 }
138
139 if (structure->m_propertyTable) {
140 ++numberWithPropertyMaps;
14957cd0 141 totalPropertyMapsSize += structure->m_propertyTable->sizeInMemory();
9dae56ea
A
142 }
143 }
144
6fe7ccc8
A
145 dataLog("Number of live Structures: %d\n", liveStructureSet.size());
146 dataLog("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
147 dataLog("Number of Structures that are leaf nodes: %d\n", numberLeaf);
148 dataLog("Number of Structures that singletons: %d\n", numberSingletons);
149 dataLog("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
9dae56ea 150
6fe7ccc8
A
151 dataLog("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
152 dataLog("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
153 dataLog("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
9dae56ea 154#else
6fe7ccc8 155 dataLog("Dumping Structure statistics is not enabled.\n");
9dae56ea
A
156#endif
157}
158
6fe7ccc8 159Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
14957cd0
A
160 : JSCell(globalData, globalData.structureStructure.get())
161 , m_typeInfo(typeInfo)
6fe7ccc8 162 , m_globalObject(globalData, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
14957cd0
A
163 , m_prototype(globalData, this, prototype)
164 , m_classInfo(classInfo)
6fe7ccc8 165 , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity)
9dae56ea 166 , m_offset(noOffset)
ba379fdc 167 , m_dictionaryKind(NoneDictionaryKind)
9dae56ea
A
168 , m_isPinnedPropertyTable(false)
169 , m_hasGetterSetterProperties(false)
6fe7ccc8 170 , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(false)
14957cd0 171 , m_hasNonEnumerableProperties(false)
9dae56ea 172 , m_attributesInPrevious(0)
f9bf01c6 173 , m_specificFunctionThrashCount(0)
14957cd0
A
174 , m_preventExtensions(false)
175 , m_didTransition(false)
6fe7ccc8 176 , m_staticFunctionReified(false)
9dae56ea 177{
9dae56ea
A
178}
179
6fe7ccc8 180const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) };
9dae56ea 181
14957cd0 182Structure::Structure(JSGlobalData& globalData)
6fe7ccc8 183 : JSCell(CreatingEarlyCell)
14957cd0
A
184 , m_typeInfo(CompoundType, OverridesVisitChildren)
185 , m_prototype(globalData, this, jsNull())
186 , m_classInfo(&s_info)
187 , m_propertyStorageCapacity(0)
188 , m_offset(noOffset)
189 , m_dictionaryKind(NoneDictionaryKind)
190 , m_isPinnedPropertyTable(false)
191 , m_hasGetterSetterProperties(false)
6fe7ccc8 192 , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(false)
14957cd0
A
193 , m_hasNonEnumerableProperties(false)
194 , m_attributesInPrevious(0)
195 , m_specificFunctionThrashCount(0)
14957cd0
A
196 , m_preventExtensions(false)
197 , m_didTransition(false)
6fe7ccc8 198 , m_staticFunctionReified(false)
9dae56ea 199{
9dae56ea
A
200}
201
14957cd0
A
202Structure::Structure(JSGlobalData& globalData, const Structure* previous)
203 : JSCell(globalData, globalData.structureStructure.get())
204 , m_typeInfo(previous->typeInfo())
205 , m_prototype(globalData, this, previous->storedPrototype())
206 , m_classInfo(previous->m_classInfo)
207 , m_propertyStorageCapacity(previous->m_propertyStorageCapacity)
208 , m_offset(noOffset)
6fe7ccc8 209 , m_dictionaryKind(previous->m_dictionaryKind)
14957cd0
A
210 , m_isPinnedPropertyTable(false)
211 , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
6fe7ccc8 212 , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto)
14957cd0
A
213 , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
214 , m_attributesInPrevious(0)
215 , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
14957cd0
A
216 , m_preventExtensions(previous->m_preventExtensions)
217 , m_didTransition(true)
6fe7ccc8 218 , m_staticFunctionReified(previous->m_staticFunctionReified)
9dae56ea 219{
6fe7ccc8
A
220 if (previous->m_globalObject)
221 m_globalObject.set(globalData, this, previous->m_globalObject.get());
9dae56ea
A
222}
223
6fe7ccc8 224void Structure::destroy(JSCell* cell)
9dae56ea 225{
6fe7ccc8 226 jsCast<Structure*>(cell)->Structure::~Structure();
9dae56ea
A
227}
228
14957cd0 229void Structure::materializePropertyMap(JSGlobalData& globalData)
9dae56ea 230{
14957cd0 231 ASSERT(structure()->classInfo() == &s_info);
9dae56ea
A
232 ASSERT(!m_propertyTable);
233
234 Vector<Structure*, 8> structures;
235 structures.append(this);
236
237 Structure* structure = this;
238
14957cd0 239 // Search for the last Structure with a property table.
9dae56ea
A
240 while ((structure = structure->previousID())) {
241 if (structure->m_isPinnedPropertyTable) {
242 ASSERT(structure->m_propertyTable);
243 ASSERT(!structure->m_previous);
244
14957cd0 245 m_propertyTable = structure->m_propertyTable->copy(globalData, 0, m_offset + 1);
9dae56ea
A
246 break;
247 }
248
249 structures.append(structure);
250 }
251
252 if (!m_propertyTable)
14957cd0 253 createPropertyMap(m_offset + 1);
9dae56ea
A
254
255 for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
256 structure = structures[i];
6fe7ccc8 257 PropertyMapEntry entry(globalData, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
14957cd0 258 m_propertyTable->add(entry);
9dae56ea
A
259 }
260}
261
9dae56ea
A
262void Structure::growPropertyStorageCapacity()
263{
14957cd0
A
264 if (isUsingInlineStorage())
265 m_propertyStorageCapacity = JSObject::baseExternalStorageCapacity;
9dae56ea
A
266 else
267 m_propertyStorageCapacity *= 2;
268}
269
6fe7ccc8
A
270size_t Structure::suggestedNewPropertyStorageSize()
271{
272 if (isUsingInlineStorage())
273 return JSObject::baseExternalStorageCapacity;
274 return m_propertyStorageCapacity * 2;
275}
276
14957cd0 277void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName)
ba379fdc 278{
14957cd0 279 StringImpl* rep = propertyName.impl();
ba379fdc 280
14957cd0 281 materializePropertyMapIfNecessary(globalData);
ba379fdc
A
282
283 ASSERT(isDictionary());
284 ASSERT(m_propertyTable);
285
14957cd0
A
286 PropertyMapEntry* entry = m_propertyTable->find(rep).first;
287 ASSERT(entry);
288 entry->specificValue.clear();
ba379fdc
A
289}
290
14957cd0 291Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
9dae56ea 292{
ba379fdc 293 ASSERT(!structure->isDictionary());
6fe7ccc8 294 ASSERT(structure->isObject());
9dae56ea 295
14957cd0
A
296 if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.impl(), attributes)) {
297 JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get();
298 if (specificValueInPrevious && specificValueInPrevious != specificValue)
299 return 0;
f9bf01c6 300 ASSERT(existingTransition->m_offset != noOffset);
6fe7ccc8 301 offset = existingTransition->m_offset;
f9bf01c6 302 return existingTransition;
9dae56ea
A
303 }
304
305 return 0;
306}
307
14957cd0 308Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
9dae56ea 309{
14957cd0
A
310 // If we have a specific function, we may have got to this point if there is
311 // already a transition with the correct property name and attributes, but
312 // specialized to a different function. In this case we just want to give up
313 // and despecialize the transition.
314 // In this case we clear the value of specificFunction which will result
315 // in us adding a non-specific transition, and any subsequent lookup in
316 // Structure::addPropertyTransitionToExistingStructure will just use that.
317 if (specificValue && structure->m_transitionTable.contains(propertyName.impl(), attributes))
318 specificValue = 0;
319
ba379fdc 320 ASSERT(!structure->isDictionary());
6fe7ccc8 321 ASSERT(structure->isObject());
ba379fdc 322 ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
f9bf01c6
A
323
324 if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
325 specificValue = 0;
9dae56ea
A
326
327 if (structure->transitionCount() > s_maxTransitionLength) {
14957cd0 328 Structure* transition = toCacheableDictionaryTransition(globalData, structure);
ba379fdc 329 ASSERT(structure != transition);
14957cd0 330 offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
9dae56ea
A
331 if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
332 transition->growPropertyStorageCapacity();
14957cd0 333 return transition;
9dae56ea 334 }
6fe7ccc8 335
14957cd0 336 Structure* transition = create(globalData, structure);
ba379fdc 337
14957cd0
A
338 transition->m_cachedPrototypeChain.setMayBeNull(globalData, transition, structure->m_cachedPrototypeChain.get());
339 transition->m_previous.set(globalData, transition, structure);
340 transition->m_nameInPrevious = propertyName.impl();
9dae56ea 341 transition->m_attributesInPrevious = attributes;
14957cd0 342 transition->m_specificValueInPrevious.setMayBeNull(globalData, transition, specificValue);
9dae56ea
A
343
344 if (structure->m_propertyTable) {
345 if (structure->m_isPinnedPropertyTable)
6fe7ccc8 346 transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1);
14957cd0
A
347 else
348 transition->m_propertyTable = structure->m_propertyTable.release();
9dae56ea
A
349 } else {
350 if (structure->m_previous)
14957cd0 351 transition->materializePropertyMap(globalData);
9dae56ea 352 else
14957cd0 353 transition->createPropertyMap();
9dae56ea
A
354 }
355
14957cd0 356 offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
9dae56ea
A
357 if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
358 transition->growPropertyStorageCapacity();
359
6fe7ccc8 360 transition->m_offset = offset;
14957cd0
A
361 structure->m_transitionTable.add(globalData, transition);
362 return transition;
9dae56ea
A
363}
364
14957cd0 365Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, size_t& offset)
9dae56ea 366{
ba379fdc 367 ASSERT(!structure->isUncacheableDictionary());
9dae56ea 368
14957cd0 369 Structure* transition = toUncacheableDictionaryTransition(globalData, structure);
9dae56ea
A
370
371 offset = transition->remove(propertyName);
372
14957cd0 373 return transition;
9dae56ea
A
374}
375
14957cd0 376Structure* Structure::changePrototypeTransition(JSGlobalData& globalData, Structure* structure, JSValue prototype)
9dae56ea 377{
14957cd0 378 Structure* transition = create(globalData, structure);
9dae56ea 379
14957cd0 380 transition->m_prototype.set(globalData, transition, prototype);
9dae56ea
A
381
382 // Don't set m_offset, as one can not transition to this.
383
14957cd0 384 structure->materializePropertyMapIfNecessary(globalData);
6fe7ccc8
A
385 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
386 transition->pin();
387
14957cd0 388 return transition;
9dae56ea
A
389}
390
14957cd0 391Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Structure* structure, const Identifier& replaceFunction)
ba379fdc 392{
f9bf01c6 393 ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount);
14957cd0 394 Structure* transition = create(globalData, structure);
ba379fdc 395
14957cd0 396 ++transition->m_specificFunctionThrashCount;
ba379fdc
A
397
398 // Don't set m_offset, as one can not transition to this.
399
14957cd0 400 structure->materializePropertyMapIfNecessary(globalData);
6fe7ccc8
A
401 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
402 transition->pin();
ba379fdc 403
f9bf01c6 404 if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
14957cd0 405 transition->despecifyAllFunctions(globalData);
f9bf01c6 406 else {
14957cd0 407 bool removed = transition->despecifyFunction(globalData, replaceFunction);
f9bf01c6
A
408 ASSERT_UNUSED(removed, removed);
409 }
6fe7ccc8 410
14957cd0 411 return transition;
ba379fdc
A
412}
413
6fe7ccc8 414Structure* Structure::attributeChangeTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, unsigned attributes)
9dae56ea 415{
6fe7ccc8
A
416 if (!structure->isUncacheableDictionary()) {
417 Structure* transition = create(globalData, structure);
9dae56ea 418
6fe7ccc8 419 // Don't set m_offset, as one can not transition to this.
9dae56ea 420
6fe7ccc8
A
421 structure->materializePropertyMapIfNecessary(globalData);
422 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
423 transition->pin();
424
425 structure = transition;
426 }
427
428 ASSERT(structure->m_propertyTable);
429 PropertyMapEntry* entry = structure->m_propertyTable->find(propertyName.impl()).first;
430 ASSERT(entry);
431 entry->attributes = attributes;
432
433 return structure;
9dae56ea
A
434}
435
14957cd0 436Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure* structure, DictionaryKind kind)
9dae56ea 437{
ba379fdc
A
438 ASSERT(!structure->isUncacheableDictionary());
439
14957cd0
A
440 Structure* transition = create(globalData, structure);
441
442 structure->materializePropertyMapIfNecessary(globalData);
6fe7ccc8 443 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
ba379fdc 444 transition->m_dictionaryKind = kind;
6fe7ccc8
A
445 transition->pin();
446
14957cd0
A
447 return transition;
448}
449
450Structure* Structure::toCacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure)
451{
452 return toDictionaryTransition(globalData, structure, CachedDictionaryKind);
453}
454
455Structure* Structure::toUncacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure)
456{
457 return toDictionaryTransition(globalData, structure, UncachedDictionaryKind);
458}
459
460// In future we may want to cache this transition.
461Structure* Structure::sealTransition(JSGlobalData& globalData, Structure* structure)
462{
463 Structure* transition = preventExtensionsTransition(globalData, structure);
464
465 if (transition->m_propertyTable) {
466 PropertyTable::iterator end = transition->m_propertyTable->end();
467 for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
468 iter->attributes |= DontDelete;
469 }
470
471 return transition;
472}
473
474// In future we may want to cache this transition.
475Structure* Structure::freezeTransition(JSGlobalData& globalData, Structure* structure)
476{
477 Structure* transition = preventExtensionsTransition(globalData, structure);
478
479 if (transition->m_propertyTable) {
6fe7ccc8 480 PropertyTable::iterator iter = transition->m_propertyTable->begin();
14957cd0 481 PropertyTable::iterator end = transition->m_propertyTable->end();
6fe7ccc8
A
482 if (iter != end)
483 transition->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
484 for (; iter != end; ++iter)
485 iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly);
14957cd0
A
486 }
487
488 return transition;
489}
490
491// In future we may want to cache this transition.
492Structure* Structure::preventExtensionsTransition(JSGlobalData& globalData, Structure* structure)
493{
494 Structure* transition = create(globalData, structure);
495
496 // Don't set m_offset, as one can not transition to this.
497
498 structure->materializePropertyMapIfNecessary(globalData);
6fe7ccc8 499 transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
14957cd0 500 transition->m_preventExtensions = true;
6fe7ccc8 501 transition->pin();
14957cd0 502
14957cd0 503 return transition;
9dae56ea
A
504}
505
14957cd0
A
506// In future we may want to cache this property.
507bool Structure::isSealed(JSGlobalData& globalData)
9dae56ea 508{
14957cd0
A
509 if (isExtensible())
510 return false;
511
512 materializePropertyMapIfNecessary(globalData);
513 if (!m_propertyTable)
514 return true;
515
516 PropertyTable::iterator end = m_propertyTable->end();
517 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
518 if ((iter->attributes & DontDelete) != DontDelete)
519 return false;
520 }
521 return true;
ba379fdc 522}
9dae56ea 523
14957cd0
A
524// In future we may want to cache this property.
525bool Structure::isFrozen(JSGlobalData& globalData)
ba379fdc 526{
14957cd0
A
527 if (isExtensible())
528 return false;
529
530 materializePropertyMapIfNecessary(globalData);
531 if (!m_propertyTable)
532 return true;
533
534 PropertyTable::iterator end = m_propertyTable->end();
535 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
6fe7ccc8
A
536 if (!(iter->attributes & DontDelete))
537 return false;
538 if (!(iter->attributes & (ReadOnly | Accessor)))
14957cd0
A
539 return false;
540 }
541 return true;
ba379fdc 542}
9dae56ea 543
14957cd0 544Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObject* object)
ba379fdc
A
545{
546 ASSERT(isDictionary());
547 if (isUncacheableDictionary()) {
548 ASSERT(m_propertyTable);
ba379fdc 549
14957cd0
A
550 size_t propertyCount = m_propertyTable->size();
551 Vector<JSValue> values(propertyCount);
552
553 unsigned i = 0;
554 PropertyTable::iterator end = m_propertyTable->end();
555 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
556 values[i] = object->getDirectOffset(iter->offset);
ba379fdc 557 // Update property table to have the new property offsets
6fe7ccc8 558 iter->offset = i;
ba379fdc
A
559 }
560
561 // Copy the original property values into their final locations
562 for (unsigned i = 0; i < propertyCount; i++)
6fe7ccc8 563 object->putDirectOffset(globalData, i, values[i]);
ba379fdc 564
14957cd0 565 m_propertyTable->clearDeletedOffsets();
ba379fdc 566 }
9dae56ea 567
ba379fdc
A
568 m_dictionaryKind = NoneDictionaryKind;
569 return this;
9dae56ea
A
570}
571
14957cd0 572size_t Structure::addPropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
9dae56ea 573{
f9bf01c6
A
574 ASSERT(!m_enumerationCache);
575
576 if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
577 specificValue = 0;
9dae56ea 578
6fe7ccc8
A
579 materializePropertyMapIfNecessaryForPinning(globalData);
580
581 pin();
f9bf01c6 582
14957cd0 583 size_t offset = putSpecificValue(globalData, propertyName, attributes, specificValue);
9dae56ea
A
584 if (propertyStorageSize() > propertyStorageCapacity())
585 growPropertyStorageCapacity();
9dae56ea
A
586 return offset;
587}
588
14957cd0 589size_t Structure::removePropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName)
9dae56ea 590{
ba379fdc 591 ASSERT(isUncacheableDictionary());
f9bf01c6 592 ASSERT(!m_enumerationCache);
9dae56ea 593
6fe7ccc8 594 materializePropertyMapIfNecessaryForPinning(globalData);
9dae56ea 595
6fe7ccc8 596 pin();
9dae56ea 597 size_t offset = remove(propertyName);
9dae56ea
A
598 return offset;
599}
600
6fe7ccc8
A
601void Structure::pin()
602{
603 ASSERT(m_propertyTable);
604 m_isPinnedPropertyTable = true;
605 m_previous.clear();
606 m_nameInPrevious.clear();
607}
608
9dae56ea
A
609#if DUMP_PROPERTYMAP_STATS
610
9dae56ea
A
611struct PropertyMapStatisticsExitLogger {
612 ~PropertyMapStatisticsExitLogger();
613};
614
615static PropertyMapStatisticsExitLogger logger;
616
617PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
618{
6fe7ccc8
A
619 dataLog("\nJSC::PropertyMap statistics\n\n");
620 dataLog("%d probes\n", numProbes);
621 dataLog("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
622 dataLog("%d rehashes\n", numRehashes);
623 dataLog("%d removes\n", numRemoves);
9dae56ea
A
624}
625
626#endif
627
9dae56ea
A
628#if !DO_PROPERTYMAP_CONSTENCY_CHECK
629
630inline void Structure::checkConsistency()
631{
632}
633
634#endif
635
14957cd0 636PassOwnPtr<PropertyTable> Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner)
9dae56ea 637{
14957cd0 638 return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0);
9dae56ea
A
639}
640
6fe7ccc8
A
641PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
642{
643 return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(m_offset == noOffset ? 0 : m_offset));
644}
645
14957cd0 646size_t Structure::get(JSGlobalData& globalData, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue)
9dae56ea 647{
14957cd0 648 materializePropertyMapIfNecessary(globalData);
9dae56ea 649 if (!m_propertyTable)
14957cd0 650 return WTF::notFound;
9dae56ea 651
14957cd0
A
652 PropertyMapEntry* entry = m_propertyTable->find(propertyName).first;
653 if (!entry)
654 return WTF::notFound;
9dae56ea 655
14957cd0
A
656 attributes = entry->attributes;
657 specificValue = entry->specificValue.get();
14957cd0 658 return entry->offset;
9dae56ea
A
659}
660
14957cd0 661bool Structure::despecifyFunction(JSGlobalData& globalData, const Identifier& propertyName)
ba379fdc 662{
14957cd0 663 materializePropertyMapIfNecessary(globalData);
ba379fdc
A
664 if (!m_propertyTable)
665 return false;
666
14957cd0
A
667 ASSERT(!propertyName.isNull());
668 PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
669 if (!entry)
ba379fdc
A
670 return false;
671
14957cd0
A
672 ASSERT(entry->specificValue);
673 entry->specificValue.clear();
674 return true;
ba379fdc
A
675}
676
14957cd0 677void Structure::despecifyAllFunctions(JSGlobalData& globalData)
f9bf01c6 678{
14957cd0 679 materializePropertyMapIfNecessary(globalData);
f9bf01c6
A
680 if (!m_propertyTable)
681 return;
14957cd0
A
682
683 PropertyTable::iterator end = m_propertyTable->end();
684 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter)
685 iter->specificValue.clear();
f9bf01c6
A
686}
687
14957cd0 688size_t Structure::putSpecificValue(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
9dae56ea
A
689{
690 ASSERT(!propertyName.isNull());
14957cd0 691 ASSERT(get(globalData, propertyName) == notFound);
9dae56ea
A
692
693 checkConsistency();
f9bf01c6
A
694 if (attributes & DontEnum)
695 m_hasNonEnumerableProperties = true;
696
14957cd0 697 StringImpl* rep = propertyName.impl();
9dae56ea
A
698
699 if (!m_propertyTable)
14957cd0 700 createPropertyMap();
9dae56ea
A
701
702 unsigned newOffset;
14957cd0
A
703
704 if (m_propertyTable->hasDeletedOffset())
705 newOffset = m_propertyTable->getDeletedOffset();
706 else
6fe7ccc8 707 newOffset = m_propertyTable->size();
9dae56ea 708
14957cd0 709 m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));
9dae56ea
A
710
711 checkConsistency();
712 return newOffset;
713}
714
715size_t Structure::remove(const Identifier& propertyName)
716{
717 ASSERT(!propertyName.isNull());
718
719 checkConsistency();
720
14957cd0 721 StringImpl* rep = propertyName.impl();
9dae56ea
A
722
723 if (!m_propertyTable)
724 return notFound;
725
14957cd0
A
726 PropertyTable::find_iterator position = m_propertyTable->find(rep);
727 if (!position.first)
728 return notFound;
9dae56ea 729
14957cd0 730 size_t offset = position.first->offset;
9dae56ea 731
14957cd0
A
732 m_propertyTable->remove(position);
733 m_propertyTable->addDeletedOffset(offset);
9dae56ea
A
734
735 checkConsistency();
736 return offset;
737}
738
14957cd0 739void Structure::createPropertyMap(unsigned capacity)
9dae56ea
A
740{
741 ASSERT(!m_propertyTable);
9dae56ea
A
742
743 checkConsistency();
14957cd0 744 m_propertyTable = adoptPtr(new PropertyTable(capacity));
9dae56ea
A
745 checkConsistency();
746}
747
6fe7ccc8 748void Structure::getPropertyNamesFromStructure(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode)
9dae56ea 749{
14957cd0
A
750 materializePropertyMapIfNecessary(globalData);
751 if (!m_propertyTable)
752 return;
9dae56ea 753
14957cd0 754 bool knownUnique = !propertyNames.size();
9dae56ea 755
14957cd0
A
756 PropertyTable::iterator end = m_propertyTable->end();
757 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
758 ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum));
759 if (!(iter->attributes & DontEnum) || (mode == IncludeDontEnumProperties)) {
760 if (knownUnique)
761 propertyNames.addKnownUnique(iter->key);
762 else
763 propertyNames.add(iter->key);
9dae56ea
A
764 }
765 }
9dae56ea
A
766}
767
6fe7ccc8
A
768void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
769{
770 Structure* thisObject = jsCast<Structure*>(cell);
771 ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
772 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
773 JSCell::visitChildren(thisObject, visitor);
774 if (thisObject->m_globalObject)
775 visitor.append(&thisObject->m_globalObject);
776 if (!thisObject->isObject())
777 thisObject->m_cachedPrototypeChain.clear();
778 else {
779 if (thisObject->m_prototype)
780 visitor.append(&thisObject->m_prototype);
781 if (thisObject->m_cachedPrototypeChain)
782 visitor.append(&thisObject->m_cachedPrototypeChain);
783 }
784 if (thisObject->m_previous)
785 visitor.append(&thisObject->m_previous);
786 if (thisObject->m_specificValueInPrevious)
787 visitor.append(&thisObject->m_specificValueInPrevious);
788 if (thisObject->m_enumerationCache)
789 visitor.append(&thisObject->m_enumerationCache);
790 if (thisObject->m_propertyTable) {
791 PropertyTable::iterator end = thisObject->m_propertyTable->end();
792 for (PropertyTable::iterator ptr = thisObject->m_propertyTable->begin(); ptr != end; ++ptr) {
14957cd0
A
793 if (ptr->specificValue)
794 visitor.append(&ptr->specificValue);
9dae56ea 795 }
9dae56ea 796 }
6fe7ccc8
A
797 if (thisObject->m_objectToStringValue)
798 visitor.append(&thisObject->m_objectToStringValue);
9dae56ea
A
799}
800
9dae56ea
A
801#if DO_PROPERTYMAP_CONSTENCY_CHECK
802
14957cd0 803void PropertyTable::checkConsistency()
9dae56ea 804{
14957cd0
A
805 ASSERT(m_indexSize >= PropertyTable::MinimumTableSize);
806 ASSERT(m_indexMask);
807 ASSERT(m_indexSize == m_indexMask + 1);
808 ASSERT(!(m_indexSize & m_indexMask));
9dae56ea 809
14957cd0
A
810 ASSERT(m_keyCount <= m_indexSize / 2);
811 ASSERT(m_keyCount + m_deletedCount <= m_indexSize / 2);
812 ASSERT(m_deletedCount <= m_indexSize / 4);
9dae56ea
A
813
814 unsigned indexCount = 0;
815 unsigned deletedIndexCount = 0;
14957cd0
A
816 for (unsigned a = 0; a != m_indexSize; ++a) {
817 unsigned entryIndex = m_index[a];
818 if (entryIndex == PropertyTable::EmptyEntryIndex)
9dae56ea 819 continue;
14957cd0 820 if (entryIndex == deletedEntryIndex()) {
9dae56ea
A
821 ++deletedIndexCount;
822 continue;
823 }
14957cd0
A
824 ASSERT(entryIndex < deletedEntryIndex());
825 ASSERT(entryIndex - 1 <= usedCount());
9dae56ea
A
826 ++indexCount;
827
14957cd0
A
828 for (unsigned b = a + 1; b != m_indexSize; ++b)
829 ASSERT(m_index[b] != entryIndex);
9dae56ea 830 }
14957cd0
A
831 ASSERT(indexCount == m_keyCount);
832 ASSERT(deletedIndexCount == m_deletedCount);
9dae56ea 833
14957cd0 834 ASSERT(!table()[deletedEntryIndex() - 1].key);
9dae56ea
A
835
836 unsigned nonEmptyEntryCount = 0;
14957cd0
A
837 for (unsigned c = 0; c < usedCount(); ++c) {
838 StringImpl* rep = table()[c].key;
839 if (rep == PROPERTY_MAP_DELETED_ENTRY_KEY)
9dae56ea
A
840 continue;
841 ++nonEmptyEntryCount;
f9bf01c6 842 unsigned i = rep->existingHash();
9dae56ea
A
843 unsigned k = 0;
844 unsigned entryIndex;
845 while (1) {
14957cd0
A
846 entryIndex = m_index[i & m_indexMask];
847 ASSERT(entryIndex != PropertyTable::EmptyEntryIndex);
848 if (rep == table()[entryIndex - 1].key)
9dae56ea
A
849 break;
850 if (k == 0)
f9bf01c6 851 k = 1 | doubleHash(rep->existingHash());
9dae56ea
A
852 i += k;
853 }
854 ASSERT(entryIndex == c + 1);
855 }
856
14957cd0
A
857 ASSERT(nonEmptyEntryCount == m_keyCount);
858}
859
860void Structure::checkConsistency()
861{
862 if (!m_propertyTable)
863 return;
864
865 if (!m_hasNonEnumerableProperties) {
866 PropertyTable::iterator end = m_propertyTable->end();
867 for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
868 ASSERT(!(iter->attributes & DontEnum));
14957cd0
A
869 }
870 }
871
872 m_propertyTable->checkConsistency();
9dae56ea
A
873}
874
875#endif // DO_PROPERTYMAP_CONSTENCY_CHECK
876
877} // namespace JSC