]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Structure.cpp
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / runtime / Structure.cpp
CommitLineData
9dae56ea 1/*
93a37866 2 * Copyright (C) 2008, 2009, 2013 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 *
81345200 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
9dae56ea
A
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
81345200 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
9dae56ea
A
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
93a37866 29#include "CodeBlock.h"
81345200
A
30#include "DumpContext.h"
31#include "JSCInlines.h"
9dae56ea 32#include "JSObject.h"
f9bf01c6
A
33#include "JSPropertyNameIterator.h"
34#include "Lookup.h"
81345200 35#include "PropertyMapHashTable.h"
9dae56ea
A
36#include "PropertyNameArray.h"
37#include "StructureChain.h"
93a37866 38#include "StructureRareDataInlines.h"
81345200
A
39#include <wtf/CommaPrinter.h>
40#include <wtf/ProcessID.h>
9dae56ea
A
41#include <wtf/RefCountedLeakCounter.h>
42#include <wtf/RefPtr.h>
9dae56ea 43#include <wtf/Threading.h>
9dae56ea
A
44
45#define DUMP_STRUCTURE_ID_STATISTICS 0
46
47#ifndef NDEBUG
48#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
49#else
50#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
51#endif
52
53using namespace std;
54using namespace WTF;
55
14957cd0 56namespace JSC {
9dae56ea
A
57
58#if DUMP_STRUCTURE_ID_STATISTICS
ba379fdc 59static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
9dae56ea
A
60#endif
61
14957cd0 62bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const
4e4e5a6f 63{
14957cd0
A
64 if (isUsingSingleSlot()) {
65 Structure* transition = singleTransition();
66 return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes;
4e4e5a6f 67 }
81345200 68 return map()->get(std::make_pair(rep, attributes));
4e4e5a6f
A
69}
70
14957cd0 71inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const
4e4e5a6f 72{
14957cd0 73 if (isUsingSingleSlot()) {
4e4e5a6f 74 Structure* transition = singleTransition();
14957cd0 75 return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0;
4e4e5a6f 76 }
81345200 77 return map()->get(std::make_pair(rep, attributes));
4e4e5a6f
A
78}
79
93a37866 80inline void StructureTransitionTable::add(VM& vm, Structure* structure)
4e4e5a6f 81{
14957cd0
A
82 if (isUsingSingleSlot()) {
83 Structure* existingTransition = singleTransition();
84
85 // This handles the first transition being added.
86 if (!existingTransition) {
93a37866 87 setSingleTransition(vm, structure);
4e4e5a6f
A
88 return;
89 }
14957cd0
A
90
91 // This handles the second transition being added
92 // (or the first transition being despecified!)
93 setMap(new TransitionMap());
93a37866 94 add(vm, existingTransition);
4e4e5a6f 95 }
14957cd0
A
96
97 // Add the structure to the map.
98
99 // Newer versions of the STL have an std::make_pair function that takes rvalue references.
100 // 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.
101 // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
81345200 102 map()->set(std::make_pair(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious), structure);
4e4e5a6f
A
103}
104
9dae56ea
A
105void Structure::dumpStatistics()
106{
107#if DUMP_STRUCTURE_ID_STATISTICS
108 unsigned numberLeaf = 0;
109 unsigned numberUsingSingleSlot = 0;
110 unsigned numberSingletons = 0;
111 unsigned numberWithPropertyMaps = 0;
112 unsigned totalPropertyMapsSize = 0;
113
114 HashSet<Structure*>::const_iterator end = liveStructureSet.end();
115 for (HashSet<Structure*>::const_iterator it = liveStructureSet.begin(); it != end; ++it) {
116 Structure* structure = *it;
14957cd0
A
117
118 switch (structure->m_transitionTable.size()) {
119 case 0:
9dae56ea 120 ++numberLeaf;
93a37866 121 if (!structure->previousID())
14957cd0
A
122 ++numberSingletons;
123 break;
9dae56ea 124
14957cd0
A
125 case 1:
126 ++numberUsingSingleSlot;
127 break;
9dae56ea
A
128 }
129
93a37866 130 if (structure->propertyTable()) {
9dae56ea 131 ++numberWithPropertyMaps;
93a37866 132 totalPropertyMapsSize += structure->propertyTable()->sizeInMemory();
9dae56ea
A
133 }
134 }
135
93a37866
A
136 dataLogF("Number of live Structures: %d\n", liveStructureSet.size());
137 dataLogF("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
138 dataLogF("Number of Structures that are leaf nodes: %d\n", numberLeaf);
139 dataLogF("Number of Structures that singletons: %d\n", numberSingletons);
140 dataLogF("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
9dae56ea 141
93a37866
A
142 dataLogF("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
143 dataLogF("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
144 dataLogF("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
9dae56ea 145#else
93a37866 146 dataLogF("Dumping Structure statistics is not enabled.\n");
9dae56ea
A
147#endif
148}
149
93a37866
A
150Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
151 : JSCell(vm, vm.structureStructure.get())
81345200
A
152 , m_blob(vm.heap.structureIDTable().allocateID(this), indexingType, typeInfo)
153 , m_outOfLineTypeFlags(typeInfo.outOfLineTypeFlags())
93a37866
A
154 , m_globalObject(vm, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
155 , m_prototype(vm, this, prototype)
14957cd0 156 , m_classInfo(classInfo)
81345200 157 , m_transitionWatchpointSet(IsWatched)
93a37866 158 , m_offset(invalidOffset)
93a37866 159 , m_inlineCapacity(inlineCapacity)
ba379fdc 160 , m_dictionaryKind(NoneDictionaryKind)
81345200 161 , m_hasBeenFlattenedBefore(false)
9dae56ea 162 , m_isPinnedPropertyTable(false)
81345200
A
163 , m_hasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties(vm))
164 , m_hasCustomGetterSetterProperties(false)
165 , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties(vm))
14957cd0 166 , m_hasNonEnumerableProperties(false)
9dae56ea 167 , m_attributesInPrevious(0)
f9bf01c6 168 , m_specificFunctionThrashCount(0)
14957cd0
A
169 , m_preventExtensions(false)
170 , m_didTransition(false)
6fe7ccc8 171 , m_staticFunctionReified(false)
81345200 172 , m_hasRareData(false)
9dae56ea 173{
93a37866
A
174 ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity());
175 ASSERT(static_cast<PropertyOffset>(inlineCapacity) < firstOutOfLineOffset);
81345200
A
176 ASSERT(!m_hasRareData);
177 ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
178 ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
9dae56ea
A
179}
180
6fe7ccc8 181const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) };
9dae56ea 182
93a37866 183Structure::Structure(VM& vm)
6fe7ccc8 184 : JSCell(CreatingEarlyCell)
93a37866 185 , m_prototype(vm, this, jsNull())
81345200
A
186 , m_classInfo(info())
187 , m_transitionWatchpointSet(IsWatched)
93a37866 188 , m_offset(invalidOffset)
93a37866 189 , m_inlineCapacity(0)
14957cd0 190 , m_dictionaryKind(NoneDictionaryKind)
81345200 191 , m_hasBeenFlattenedBefore(false)
14957cd0 192 , m_isPinnedPropertyTable(false)
81345200
A
193 , m_hasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties(vm))
194 , m_hasCustomGetterSetterProperties(false)
195 , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties(vm))
14957cd0
A
196 , m_hasNonEnumerableProperties(false)
197 , m_attributesInPrevious(0)
198 , m_specificFunctionThrashCount(0)
14957cd0
A
199 , m_preventExtensions(false)
200 , m_didTransition(false)
6fe7ccc8 201 , m_staticFunctionReified(false)
81345200 202 , m_hasRareData(false)
9dae56ea 203{
81345200
A
204 TypeInfo typeInfo = TypeInfo(CompoundType, OverridesVisitChildren | StructureIsImmortal);
205 m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), 0, typeInfo);
206 m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags();
207
208 ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
209 ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
9dae56ea
A
210}
211
81345200 212Structure::Structure(VM& vm, Structure* previous)
93a37866
A
213 : JSCell(vm, vm.structureStructure.get())
214 , m_prototype(vm, this, previous->storedPrototype())
14957cd0 215 , m_classInfo(previous->m_classInfo)
81345200 216 , m_transitionWatchpointSet(IsWatched)
93a37866 217 , m_offset(invalidOffset)
93a37866 218 , m_inlineCapacity(previous->m_inlineCapacity)
6fe7ccc8 219 , m_dictionaryKind(previous->m_dictionaryKind)
81345200 220 , m_hasBeenFlattenedBefore(previous->m_hasBeenFlattenedBefore)
14957cd0
A
221 , m_isPinnedPropertyTable(false)
222 , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
81345200 223 , m_hasCustomGetterSetterProperties(previous->m_hasCustomGetterSetterProperties)
6fe7ccc8 224 , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto)
14957cd0
A
225 , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
226 , m_attributesInPrevious(0)
227 , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
14957cd0
A
228 , m_preventExtensions(previous->m_preventExtensions)
229 , m_didTransition(true)
6fe7ccc8 230 , m_staticFunctionReified(previous->m_staticFunctionReified)
81345200 231 , m_hasRareData(false)
9dae56ea 232{
81345200
A
233 TypeInfo typeInfo = previous->typeInfo();
234 m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), previous->indexingTypeIncludingHistory(), typeInfo);
235 m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags();
236
237 ASSERT(!previous->typeInfo().structureIsImmortal());
238 if (previous->m_hasRareData && previous->rareData()->needsCloning())
93a37866 239 cloneRareDataFrom(vm, previous);
81345200 240 setPreviousID(vm, previous);
93a37866
A
241
242 previous->notifyTransitionFromThisStructure();
6fe7ccc8 243 if (previous->m_globalObject)
93a37866 244 m_globalObject.set(vm, this, previous->m_globalObject.get());
81345200
A
245 ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
246 ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
247}
248
249Structure::~Structure()
250{
251 if (typeInfo().structureIsImmortal())
252 return;
253 Heap::heap(this)->structureIDTable().deallocateID(this, m_blob.structureID());
9dae56ea
A
254}
255
6fe7ccc8 256void Structure::destroy(JSCell* cell)
9dae56ea 257{
93a37866 258 static_cast<Structure*>(cell)->Structure::~Structure();
9dae56ea
A
259}
260
81345200 261void Structure::findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*& structure, PropertyTable*& table)
9dae56ea 262{
81345200
A
263 ASSERT(structures.isEmpty());
264 table = 0;
9dae56ea 265
81345200
A
266 for (structure = this; structure; structure = structure->previousID()) {
267 structure->m_lock.lock();
268
269 table = structure->propertyTable().get();
270 if (table) {
271 // Leave the structure locked, so that the caller can do things to it atomically
272 // before it loses its property table.
273 return;
9dae56ea 274 }
81345200 275
9dae56ea 276 structures.append(structure);
81345200 277 structure->m_lock.unlock();
9dae56ea 278 }
81345200
A
279
280 ASSERT(!structure);
281 ASSERT(!table);
282}
9dae56ea 283
81345200
A
284void Structure::materializePropertyMap(VM& vm)
285{
286 ASSERT(structure()->classInfo() == info());
287 ASSERT(!propertyTable());
9dae56ea 288
81345200
A
289 Vector<Structure*, 8> structures;
290 Structure* structure;
291 PropertyTable* table;
292
293 findStructuresAndMapForMaterialization(structures, structure, table);
294
295 if (table) {
296 table = table->copy(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
297 structure->m_lock.unlock();
298 }
299
300 // Must hold the lock on this structure, since we will be modifying this structure's
301 // property map. We don't want getConcurrently() to see the property map in a half-baked
302 // state.
303 GCSafeConcurrentJITLocker locker(m_lock, vm.heap);
304 if (!table)
305 createPropertyMap(locker, vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
306 else
307 propertyTable().set(vm, this, table);
308
309 for (size_t i = structures.size(); i--;) {
9dae56ea 310 structure = structures[i];
93a37866
A
311 if (!structure->m_nameInPrevious)
312 continue;
313 PropertyMapEntry entry(vm, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
314 propertyTable()->add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange);
9dae56ea 315 }
93a37866
A
316
317 checkOffsetConsistency();
9dae56ea
A
318}
319
93a37866 320void Structure::despecifyDictionaryFunction(VM& vm, PropertyName propertyName)
ba379fdc 321{
93a37866 322 StringImpl* rep = propertyName.uid();
ba379fdc 323
81345200
A
324 DeferGC deferGC(vm.heap);
325 materializePropertyMapIfNecessary(vm, deferGC);
ba379fdc
A
326
327 ASSERT(isDictionary());
93a37866 328 ASSERT(propertyTable());
ba379fdc 329
81345200 330 PropertyMapEntry* entry = propertyTable()->get(rep);
14957cd0
A
331 ASSERT(entry);
332 entry->specificValue.clear();
ba379fdc
A
333}
334
81345200 335Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
9dae56ea 336{
ba379fdc 337 ASSERT(!structure->isDictionary());
6fe7ccc8 338 ASSERT(structure->isObject());
9dae56ea 339
81345200 340 if (Structure* existingTransition = structure->m_transitionTable.get(uid, attributes)) {
14957cd0
A
341 JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get();
342 if (specificValueInPrevious && specificValueInPrevious != specificValue)
343 return 0;
93a37866 344 validateOffset(existingTransition->m_offset, existingTransition->inlineCapacity());
6fe7ccc8 345 offset = existingTransition->m_offset;
f9bf01c6 346 return existingTransition;
9dae56ea
A
347 }
348
349 return 0;
350}
351
81345200
A
352Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
353{
354 ASSERT(!isCompilationThread());
355 return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, specificValue, offset);
356}
357
358Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
359{
360 ConcurrentJITLocker locker(structure->m_lock);
361 return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, specificValue, offset);
362}
363
93a37866
A
364bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const
365{
366 for (const Structure* current = this; ;) {
367 if (current->mayInterceptIndexedAccesses())
368 return true;
369
370 JSValue prototype = current->storedPrototype();
371 if (prototype.isNull())
372 return false;
373
374 current = asObject(prototype)->structure();
375 }
376}
377
81345200
A
378bool Structure::holesMustForwardToPrototype(VM& vm) const
379{
380 if (this->mayInterceptIndexedAccesses())
381 return true;
382
383 JSValue prototype = this->storedPrototype();
384 if (!prototype.isObject())
385 return false;
386 JSObject* object = asObject(prototype);
387
388 while (true) {
389 Structure& structure = *object->structure(vm);
390 if (hasIndexedProperties(object->indexingType()) || structure.mayInterceptIndexedAccesses())
391 return true;
392 prototype = structure.storedPrototype();
393 if (!prototype.isObject())
394 return false;
395 object = asObject(prototype);
396 }
397
398 RELEASE_ASSERT_NOT_REACHED();
399 return false;
400}
401
93a37866
A
402bool Structure::needsSlowPutIndexing() const
403{
404 return anyObjectInChainMayInterceptIndexedAccesses()
405 || globalObject()->isHavingABadTime();
406}
407
408NonPropertyTransition Structure::suggestedArrayStorageTransition() const
409{
410 if (needsSlowPutIndexing())
411 return AllocateSlowPutArrayStorage;
412
413 return AllocateArrayStorage;
414}
415
81345200 416Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset, PutPropertySlot::Context context)
9dae56ea 417{
14957cd0
A
418 // If we have a specific function, we may have got to this point if there is
419 // already a transition with the correct property name and attributes, but
420 // specialized to a different function. In this case we just want to give up
421 // and despecialize the transition.
422 // In this case we clear the value of specificFunction which will result
423 // in us adding a non-specific transition, and any subsequent lookup in
424 // Structure::addPropertyTransitionToExistingStructure will just use that.
93a37866 425 if (specificValue && structure->m_transitionTable.contains(propertyName.uid(), attributes))
14957cd0
A
426 specificValue = 0;
427
ba379fdc 428 ASSERT(!structure->isDictionary());
6fe7ccc8 429 ASSERT(structure->isObject());
ba379fdc 430 ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
f9bf01c6
A
431
432 if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
433 specificValue = 0;
9dae56ea 434
81345200
A
435 int maxTransitionLength;
436 if (context == PutPropertySlot::PutById)
437 maxTransitionLength = s_maxTransitionLengthForNonEvalPutById;
438 else
439 maxTransitionLength = s_maxTransitionLength;
440 if (structure->transitionCount() > maxTransitionLength) {
93a37866 441 Structure* transition = toCacheableDictionaryTransition(vm, structure);
ba379fdc 442 ASSERT(structure != transition);
93a37866 443 offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue);
14957cd0 444 return transition;
9dae56ea 445 }
6fe7ccc8 446
93a37866 447 Structure* transition = create(vm, structure);
ba379fdc 448
93a37866 449 transition->m_cachedPrototypeChain.setMayBeNull(vm, transition, structure->m_cachedPrototypeChain.get());
93a37866 450 transition->m_nameInPrevious = propertyName.uid();
9dae56ea 451 transition->m_attributesInPrevious = attributes;
93a37866 452 transition->m_specificValueInPrevious.setMayBeNull(vm, transition, specificValue);
81345200 453 transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm));
93a37866 454 transition->m_offset = structure->m_offset;
9dae56ea 455
93a37866 456 offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue);
9dae56ea 457
93a37866 458 checkOffset(transition->m_offset, transition->inlineCapacity());
81345200
A
459 {
460 ConcurrentJITLocker locker(structure->m_lock);
461 structure->m_transitionTable.add(vm, transition);
462 }
93a37866
A
463 transition->checkOffsetConsistency();
464 structure->checkOffsetConsistency();
14957cd0 465 return transition;
9dae56ea
A
466}
467
93a37866 468Structure* Structure::removePropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, PropertyOffset& offset)
9dae56ea 469{
ba379fdc 470 ASSERT(!structure->isUncacheableDictionary());
9dae56ea 471
93a37866 472 Structure* transition = toUncacheableDictionaryTransition(vm, structure);
9dae56ea
A
473
474 offset = transition->remove(propertyName);
475
93a37866 476 transition->checkOffsetConsistency();
14957cd0 477 return transition;
9dae56ea
A
478}
479
93a37866 480Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JSValue prototype)
9dae56ea 481{
93a37866 482 Structure* transition = create(vm, structure);
9dae56ea 483
93a37866 484 transition->m_prototype.set(vm, transition, prototype);
9dae56ea 485
81345200
A
486 DeferGC deferGC(vm.heap);
487 structure->materializePropertyMapIfNecessary(vm, deferGC);
488 transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
93a37866 489 transition->m_offset = structure->m_offset;
6fe7ccc8
A
490 transition->pin();
491
93a37866 492 transition->checkOffsetConsistency();
14957cd0 493 return transition;
9dae56ea
A
494}
495
93a37866 496Structure* Structure::despecifyFunctionTransition(VM& vm, Structure* structure, PropertyName replaceFunction)
ba379fdc 497{
f9bf01c6 498 ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount);
93a37866 499 Structure* transition = create(vm, structure);
ba379fdc 500
14957cd0 501 ++transition->m_specificFunctionThrashCount;
ba379fdc 502
81345200
A
503 DeferGC deferGC(vm.heap);
504 structure->materializePropertyMapIfNecessary(vm, deferGC);
505 transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
93a37866 506 transition->m_offset = structure->m_offset;
6fe7ccc8 507 transition->pin();
ba379fdc 508
f9bf01c6 509 if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
93a37866 510 transition->despecifyAllFunctions(vm);
f9bf01c6 511 else {
93a37866 512 bool removed = transition->despecifyFunction(vm, replaceFunction);
f9bf01c6
A
513 ASSERT_UNUSED(removed, removed);
514 }
6fe7ccc8 515
93a37866 516 transition->checkOffsetConsistency();
14957cd0 517 return transition;
ba379fdc
A
518}
519
93a37866 520Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes)
9dae56ea 521{
81345200 522 DeferGC deferGC(vm.heap);
6fe7ccc8 523 if (!structure->isUncacheableDictionary()) {
93a37866 524 Structure* transition = create(vm, structure);
9dae56ea 525
81345200
A
526 structure->materializePropertyMapIfNecessary(vm, deferGC);
527 transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
93a37866 528 transition->m_offset = structure->m_offset;
6fe7ccc8
A
529 transition->pin();
530
531 structure = transition;
532 }
533
93a37866 534 ASSERT(structure->propertyTable());
81345200 535 PropertyMapEntry* entry = structure->propertyTable()->get(propertyName.uid());
6fe7ccc8
A
536 ASSERT(entry);
537 entry->attributes = attributes;
538
93a37866 539 structure->checkOffsetConsistency();
6fe7ccc8 540 return structure;
9dae56ea
A
541}
542
93a37866 543Structure* Structure::toDictionaryTransition(VM& vm, Structure* structure, DictionaryKind kind)
9dae56ea 544{
ba379fdc
A
545 ASSERT(!structure->isUncacheableDictionary());
546
93a37866 547 Structure* transition = create(vm, structure);
14957cd0 548
81345200
A
549 DeferGC deferGC(vm.heap);
550 structure->materializePropertyMapIfNecessary(vm, deferGC);
551 transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
93a37866 552 transition->m_offset = structure->m_offset;
ba379fdc 553 transition->m_dictionaryKind = kind;
6fe7ccc8
A
554 transition->pin();
555
93a37866 556 transition->checkOffsetConsistency();
14957cd0
A
557 return transition;
558}
559
93a37866 560Structure* Structure::toCacheableDictionaryTransition(VM& vm, Structure* structure)
14957cd0 561{
93a37866 562 return toDictionaryTransition(vm, structure, CachedDictionaryKind);
14957cd0
A
563}
564
93a37866 565Structure* Structure::toUncacheableDictionaryTransition(VM& vm, Structure* structure)
14957cd0 566{
93a37866 567 return toDictionaryTransition(vm, structure, UncachedDictionaryKind);
14957cd0
A
568}
569
570// In future we may want to cache this transition.
93a37866 571Structure* Structure::sealTransition(VM& vm, Structure* structure)
14957cd0 572{
93a37866 573 Structure* transition = preventExtensionsTransition(vm, structure);
14957cd0 574
93a37866
A
575 if (transition->propertyTable()) {
576 PropertyTable::iterator end = transition->propertyTable()->end();
577 for (PropertyTable::iterator iter = transition->propertyTable()->begin(); iter != end; ++iter)
14957cd0
A
578 iter->attributes |= DontDelete;
579 }
580
93a37866 581 transition->checkOffsetConsistency();
14957cd0
A
582 return transition;
583}
584
585// In future we may want to cache this transition.
93a37866 586Structure* Structure::freezeTransition(VM& vm, Structure* structure)
14957cd0 587{
93a37866 588 Structure* transition = preventExtensionsTransition(vm, structure);
14957cd0 589
93a37866
A
590 if (transition->propertyTable()) {
591 PropertyTable::iterator iter = transition->propertyTable()->begin();
592 PropertyTable::iterator end = transition->propertyTable()->end();
6fe7ccc8
A
593 if (iter != end)
594 transition->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
595 for (; iter != end; ++iter)
596 iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly);
14957cd0
A
597 }
598
81345200
A
599 ASSERT(transition->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties(vm));
600 ASSERT(transition->hasGetterSetterProperties() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties(vm));
93a37866 601 transition->checkOffsetConsistency();
14957cd0
A
602 return transition;
603}
604
605// In future we may want to cache this transition.
93a37866 606Structure* Structure::preventExtensionsTransition(VM& vm, Structure* structure)
14957cd0 607{
93a37866 608 Structure* transition = create(vm, structure);
14957cd0
A
609
610 // Don't set m_offset, as one can not transition to this.
611
81345200
A
612 DeferGC deferGC(vm.heap);
613 structure->materializePropertyMapIfNecessary(vm, deferGC);
614 transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
93a37866 615 transition->m_offset = structure->m_offset;
14957cd0 616 transition->m_preventExtensions = true;
6fe7ccc8 617 transition->pin();
14957cd0 618
93a37866
A
619 transition->checkOffsetConsistency();
620 return transition;
621}
622
81345200 623PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm)
93a37866 624{
81345200
A
625 DeferGC deferGC(vm.heap);
626 materializePropertyMapIfNecessaryForPinning(vm, deferGC);
627
93a37866 628 if (m_isPinnedPropertyTable)
81345200
A
629 return propertyTable()->copy(vm, propertyTable()->size() + 1);
630
631 // Hold the lock while stealing the table - so that getConcurrently() on another thread
632 // will either have to bypass this structure, or will get to use the property table
633 // before it is stolen.
634 ConcurrentJITLocker locker(m_lock);
93a37866
A
635 PropertyTable* takenPropertyTable = propertyTable().get();
636 propertyTable().clear();
637 return takenPropertyTable;
638}
639
640Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPropertyTransition transitionKind)
641{
642 unsigned attributes = toAttributes(transitionKind);
643 IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind);
644
645 if (JSGlobalObject* globalObject = structure->m_globalObject.get()) {
646 if (globalObject->isOriginalArrayStructure(structure)) {
647 Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType);
648 if (result->indexingTypeIncludingHistory() == indexingType) {
649 structure->notifyTransitionFromThisStructure();
650 return result;
651 }
652 }
653 }
654
81345200
A
655 Structure* existingTransition;
656 if (!structure->isDictionary() && (existingTransition = structure->m_transitionTable.get(0, attributes))) {
93a37866
A
657 ASSERT(existingTransition->m_attributesInPrevious == attributes);
658 ASSERT(existingTransition->indexingTypeIncludingHistory() == indexingType);
659 return existingTransition;
660 }
661
662 Structure* transition = create(vm, structure);
93a37866 663 transition->m_attributesInPrevious = attributes;
81345200
A
664 transition->m_blob.setIndexingType(indexingType);
665 transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm));
93a37866
A
666 transition->m_offset = structure->m_offset;
667 checkOffset(transition->m_offset, transition->inlineCapacity());
668
81345200
A
669 if (structure->isDictionary())
670 transition->pin();
671 else {
672 ConcurrentJITLocker locker(structure->m_lock);
673 structure->m_transitionTable.add(vm, transition);
674 }
93a37866 675 transition->checkOffsetConsistency();
14957cd0 676 return transition;
9dae56ea
A
677}
678
14957cd0 679// In future we may want to cache this property.
93a37866 680bool Structure::isSealed(VM& vm)
9dae56ea 681{
14957cd0
A
682 if (isExtensible())
683 return false;
684
81345200
A
685 DeferGC deferGC(vm.heap);
686 materializePropertyMapIfNecessary(vm, deferGC);
93a37866 687 if (!propertyTable())
14957cd0
A
688 return true;
689
93a37866
A
690 PropertyTable::iterator end = propertyTable()->end();
691 for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
14957cd0
A
692 if ((iter->attributes & DontDelete) != DontDelete)
693 return false;
694 }
695 return true;
ba379fdc 696}
9dae56ea 697
14957cd0 698// In future we may want to cache this property.
93a37866 699bool Structure::isFrozen(VM& vm)
ba379fdc 700{
14957cd0
A
701 if (isExtensible())
702 return false;
703
81345200
A
704 DeferGC deferGC(vm.heap);
705 materializePropertyMapIfNecessary(vm, deferGC);
93a37866 706 if (!propertyTable())
14957cd0
A
707 return true;
708
93a37866
A
709 PropertyTable::iterator end = propertyTable()->end();
710 for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
6fe7ccc8
A
711 if (!(iter->attributes & DontDelete))
712 return false;
713 if (!(iter->attributes & (ReadOnly | Accessor)))
14957cd0
A
714 return false;
715 }
716 return true;
ba379fdc 717}
9dae56ea 718
93a37866 719Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object)
ba379fdc 720{
93a37866 721 checkOffsetConsistency();
ba379fdc 722 ASSERT(isDictionary());
81345200
A
723
724 size_t beforeOutOfLineCapacity = this->outOfLineCapacity();
ba379fdc 725 if (isUncacheableDictionary()) {
93a37866
A
726 ASSERT(propertyTable());
727
728 size_t propertyCount = propertyTable()->size();
ba379fdc 729
93a37866 730 // Holds our values compacted by insertion order.
14957cd0
A
731 Vector<JSValue> values(propertyCount);
732
93a37866 733 // Copies out our values from their hashed locations, compacting property table offsets as we go.
14957cd0 734 unsigned i = 0;
93a37866
A
735 PropertyTable::iterator end = propertyTable()->end();
736 m_offset = invalidOffset;
737 for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter, ++i) {
738 values[i] = object->getDirect(iter->offset);
739 m_offset = iter->offset = offsetForPropertyNumber(i, m_inlineCapacity);
ba379fdc
A
740 }
741
93a37866 742 // Copies in our values to their compacted locations.
ba379fdc 743 for (unsigned i = 0; i < propertyCount; i++)
93a37866 744 object->putDirect(vm, offsetForPropertyNumber(i, m_inlineCapacity), values[i]);
ba379fdc 745
93a37866
A
746 propertyTable()->clearDeletedOffsets();
747 checkOffsetConsistency();
ba379fdc 748 }
9dae56ea 749
ba379fdc 750 m_dictionaryKind = NoneDictionaryKind;
81345200
A
751 m_hasBeenFlattenedBefore = true;
752
753 size_t afterOutOfLineCapacity = this->outOfLineCapacity();
754
755 if (beforeOutOfLineCapacity != afterOutOfLineCapacity) {
756 ASSERT(beforeOutOfLineCapacity > afterOutOfLineCapacity);
757 // If the object had a Butterfly but after flattening/compacting we no longer have need of it,
758 // we need to zero it out because the collector depends on the Structure to know the size for copying.
759 if (object->butterfly() && !afterOutOfLineCapacity && !this->hasIndexingHeader(object))
760 object->setStructureAndButterfly(vm, this, 0);
761 // If the object was down-sized to the point where the base of the Butterfly is no longer within the
762 // first CopiedBlock::blockSize bytes, we'll get the wrong answer if we try to mask the base back to
763 // the CopiedBlock header. To prevent this case we need to memmove the Butterfly down.
764 else if (object->butterfly())
765 object->shiftButterflyAfterFlattening(vm, beforeOutOfLineCapacity, afterOutOfLineCapacity);
766 }
12899fa2 767
ba379fdc 768 return this;
9dae56ea
A
769}
770
93a37866 771PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
9dae56ea 772{
93a37866 773 ASSERT(!enumerationCache());
f9bf01c6
A
774
775 if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
776 specificValue = 0;
9dae56ea 777
81345200
A
778 DeferGC deferGC(vm.heap);
779 materializePropertyMapIfNecessaryForPinning(vm, deferGC);
6fe7ccc8
A
780
781 pin();
f9bf01c6 782
93a37866 783 return putSpecificValue(vm, propertyName, attributes, specificValue);
9dae56ea
A
784}
785
93a37866 786PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName propertyName)
9dae56ea 787{
ba379fdc 788 ASSERT(isUncacheableDictionary());
93a37866 789 ASSERT(!enumerationCache());
9dae56ea 790
81345200
A
791 DeferGC deferGC(vm.heap);
792 materializePropertyMapIfNecessaryForPinning(vm, deferGC);
9dae56ea 793
6fe7ccc8 794 pin();
93a37866 795 return remove(propertyName);
9dae56ea
A
796}
797
6fe7ccc8
A
798void Structure::pin()
799{
93a37866 800 ASSERT(propertyTable());
6fe7ccc8 801 m_isPinnedPropertyTable = true;
93a37866 802 clearPreviousID();
6fe7ccc8
A
803 m_nameInPrevious.clear();
804}
805
93a37866
A
806void Structure::allocateRareData(VM& vm)
807{
81345200 808 ASSERT(!m_hasRareData);
93a37866 809 StructureRareData* rareData = StructureRareData::create(vm, previous());
93a37866 810 m_previousOrRareData.set(vm, this, rareData);
81345200
A
811 m_hasRareData = true;
812 ASSERT(m_hasRareData);
93a37866
A
813}
814
815void Structure::cloneRareDataFrom(VM& vm, const Structure* other)
816{
81345200
A
817 ASSERT(!m_hasRareData);
818 ASSERT(other->m_hasRareData);
93a37866 819 StructureRareData* newRareData = StructureRareData::clone(vm, other->rareData());
93a37866 820 m_previousOrRareData.set(vm, this, newRareData);
81345200
A
821 m_hasRareData = true;
822 ASSERT(m_hasRareData);
93a37866
A
823}
824
9dae56ea
A
825#if DUMP_PROPERTYMAP_STATS
826
81345200
A
827PropertyMapHashTableStats* propertyMapHashTableStats = 0;
828
9dae56ea 829struct PropertyMapStatisticsExitLogger {
81345200 830 PropertyMapStatisticsExitLogger();
9dae56ea
A
831 ~PropertyMapStatisticsExitLogger();
832};
833
81345200
A
834DEFINE_GLOBAL_FOR_LOGGING(PropertyMapStatisticsExitLogger, logger, );
835
836PropertyMapStatisticsExitLogger::PropertyMapStatisticsExitLogger()
837{
838 propertyMapHashTableStats = adoptPtr(new PropertyMapHashTableStats()).leakPtr();
839}
9dae56ea
A
840
841PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
842{
81345200
A
843 unsigned finds = propertyMapHashTableStats->numFinds;
844 unsigned collisions = propertyMapHashTableStats->numCollisions;
845 dataLogF("\nJSC::PropertyMap statistics for process %d\n\n", getCurrentProcessID());
846 dataLogF("%d finds\n", finds);
847 dataLogF("%d collisions (%.1f%%)\n", collisions, 100.0 * collisions / finds);
848 dataLogF("%d lookups\n", propertyMapHashTableStats->numLookups.load());
849 dataLogF("%d lookup probings\n", propertyMapHashTableStats->numLookupProbing.load());
850 dataLogF("%d adds\n", propertyMapHashTableStats->numAdds.load());
851 dataLogF("%d removes\n", propertyMapHashTableStats->numRemoves.load());
852 dataLogF("%d rehashes\n", propertyMapHashTableStats->numRehashes.load());
853 dataLogF("%d reinserts\n", propertyMapHashTableStats->numReinserts.load());
9dae56ea
A
854}
855
856#endif
857
9dae56ea
A
858#if !DO_PROPERTYMAP_CONSTENCY_CHECK
859
860inline void Structure::checkConsistency()
861{
93a37866 862 checkOffsetConsistency();
9dae56ea
A
863}
864
865#endif
866
81345200 867PropertyTable* Structure::copyPropertyTable(VM& vm)
9dae56ea 868{
93a37866
A
869 if (!propertyTable())
870 return 0;
81345200 871 return PropertyTable::clone(vm, *propertyTable().get());
9dae56ea
A
872}
873
81345200 874PropertyTable* Structure::copyPropertyTableForPinning(VM& vm)
6fe7ccc8 875{
93a37866 876 if (propertyTable())
81345200 877 return PropertyTable::clone(vm, *propertyTable().get());
93a37866 878 return PropertyTable::create(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
6fe7ccc8
A
879}
880
81345200 881PropertyOffset Structure::getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue)
9dae56ea 882{
81345200
A
883 Vector<Structure*, 8> structures;
884 Structure* structure;
885 PropertyTable* table;
886
887 findStructuresAndMapForMaterialization(structures, structure, table);
888
889 if (table) {
890 PropertyMapEntry* entry = table->get(uid);
891 if (entry) {
892 attributes = entry->attributes;
893 specificValue = entry->specificValue.get();
894 PropertyOffset result = entry->offset;
895 structure->m_lock.unlock();
896 return result;
897 }
898 structure->m_lock.unlock();
899 }
900
901 for (unsigned i = structures.size(); i--;) {
902 structure = structures[i];
903 if (structure->m_nameInPrevious.get() != uid)
904 continue;
905
906 attributes = structure->m_attributesInPrevious;
907 specificValue = structure->m_specificValueInPrevious.get();
908 return structure->m_offset;
909 }
910
911 return invalidOffset;
9dae56ea
A
912}
913
93a37866 914bool Structure::despecifyFunction(VM& vm, PropertyName propertyName)
ba379fdc 915{
81345200
A
916 DeferGC deferGC(vm.heap);
917 materializePropertyMapIfNecessary(vm, deferGC);
93a37866 918 if (!propertyTable())
ba379fdc
A
919 return false;
920
81345200 921 PropertyMapEntry* entry = propertyTable()->get(propertyName.uid());
14957cd0 922 if (!entry)
ba379fdc
A
923 return false;
924
14957cd0
A
925 ASSERT(entry->specificValue);
926 entry->specificValue.clear();
927 return true;
ba379fdc
A
928}
929
93a37866 930void Structure::despecifyAllFunctions(VM& vm)
f9bf01c6 931{
81345200
A
932 DeferGC deferGC(vm.heap);
933 materializePropertyMapIfNecessary(vm, deferGC);
93a37866 934 if (!propertyTable())
f9bf01c6 935 return;
14957cd0 936
93a37866
A
937 PropertyTable::iterator end = propertyTable()->end();
938 for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter)
14957cd0 939 iter->specificValue.clear();
f9bf01c6
A
940}
941
93a37866 942PropertyOffset Structure::putSpecificValue(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
9dae56ea 943{
81345200
A
944 GCSafeConcurrentJITLocker locker(m_lock, vm.heap);
945
93a37866 946 ASSERT(!JSC::isValidOffset(get(vm, propertyName)));
9dae56ea
A
947
948 checkConsistency();
f9bf01c6
A
949 if (attributes & DontEnum)
950 m_hasNonEnumerableProperties = true;
951
93a37866 952 StringImpl* rep = propertyName.uid();
9dae56ea 953
93a37866 954 if (!propertyTable())
81345200 955 createPropertyMap(locker, vm);
14957cd0 956
93a37866 957 PropertyOffset newOffset = propertyTable()->nextOffset(m_inlineCapacity);
9dae56ea 958
81345200 959 propertyTable()->add(PropertyMapEntry(vm, propertyTable().get(), rep, newOffset, attributes, specificValue), m_offset, PropertyTable::PropertyOffsetMayChange);
93a37866 960
9dae56ea
A
961 checkConsistency();
962 return newOffset;
963}
964
93a37866 965PropertyOffset Structure::remove(PropertyName propertyName)
9dae56ea 966{
81345200
A
967 ConcurrentJITLocker locker(m_lock);
968
9dae56ea
A
969 checkConsistency();
970
93a37866 971 StringImpl* rep = propertyName.uid();
9dae56ea 972
93a37866
A
973 if (!propertyTable())
974 return invalidOffset;
9dae56ea 975
93a37866 976 PropertyTable::find_iterator position = propertyTable()->find(rep);
14957cd0 977 if (!position.first)
93a37866 978 return invalidOffset;
9dae56ea 979
93a37866 980 PropertyOffset offset = position.first->offset;
9dae56ea 981
93a37866
A
982 propertyTable()->remove(position);
983 propertyTable()->addDeletedOffset(offset);
9dae56ea
A
984
985 checkConsistency();
986 return offset;
987}
988
81345200 989void Structure::createPropertyMap(const GCSafeConcurrentJITLocker&, VM& vm, unsigned capacity)
9dae56ea 990{
93a37866 991 ASSERT(!propertyTable());
9dae56ea
A
992
993 checkConsistency();
93a37866 994 propertyTable().set(vm, this, PropertyTable::create(vm, capacity));
9dae56ea
A
995}
996
93a37866 997void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propertyNames, EnumerationMode mode)
9dae56ea 998{
81345200
A
999 DeferGC deferGC(vm.heap);
1000 materializePropertyMapIfNecessary(vm, deferGC);
93a37866 1001 if (!propertyTable())
14957cd0 1002 return;
9dae56ea 1003
14957cd0 1004 bool knownUnique = !propertyNames.size();
9dae56ea 1005
93a37866
A
1006 PropertyTable::iterator end = propertyTable()->end();
1007 for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
14957cd0 1008 ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum));
81345200 1009 if (!iter->key->isEmptyUnique() && (!(iter->attributes & DontEnum) || mode == IncludeDontEnumProperties)) {
14957cd0
A
1010 if (knownUnique)
1011 propertyNames.addKnownUnique(iter->key);
1012 else
1013 propertyNames.add(iter->key);
9dae56ea
A
1014 }
1015 }
9dae56ea
A
1016}
1017
93a37866
A
1018JSValue Structure::prototypeForLookup(CodeBlock* codeBlock) const
1019{
1020 return prototypeForLookup(codeBlock->globalObject());
1021}
1022
6fe7ccc8
A
1023void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
1024{
1025 Structure* thisObject = jsCast<Structure*>(cell);
81345200 1026 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
6fe7ccc8 1027 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
93a37866 1028
6fe7ccc8 1029 JSCell::visitChildren(thisObject, visitor);
93a37866 1030 visitor.append(&thisObject->m_globalObject);
6fe7ccc8
A
1031 if (!thisObject->isObject())
1032 thisObject->m_cachedPrototypeChain.clear();
1033 else {
93a37866
A
1034 visitor.append(&thisObject->m_prototype);
1035 visitor.append(&thisObject->m_cachedPrototypeChain);
6fe7ccc8 1036 }
93a37866
A
1037 visitor.append(&thisObject->m_previousOrRareData);
1038 visitor.append(&thisObject->m_specificValueInPrevious);
1039
1040 if (thisObject->m_isPinnedPropertyTable) {
1041 ASSERT(thisObject->m_propertyTableUnsafe);
1042 visitor.append(&thisObject->m_propertyTableUnsafe);
1043 } else if (thisObject->m_propertyTableUnsafe)
1044 thisObject->m_propertyTableUnsafe.clear();
1045}
1046
1047bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyName)
1048{
1049 unsigned i = propertyName.asIndex();
1050 if (i != PropertyName::NotAnIndex)
1051 return anyObjectInChainMayInterceptIndexedAccesses();
1052
1053 for (Structure* current = this; ;) {
1054 JSValue prototype = current->storedPrototype();
1055 if (prototype.isNull())
1056 return false;
1057
81345200 1058 current = prototype.asCell()->structure(vm);
93a37866
A
1059
1060 unsigned attributes;
1061 JSCell* specificValue;
1062 PropertyOffset offset = current->get(vm, propertyName, attributes, specificValue);
1063 if (!JSC::isValidOffset(offset))
1064 continue;
1065
1066 if (attributes & (ReadOnly | Accessor))
1067 return true;
1068
1069 return false;
9dae56ea
A
1070 }
1071}
1072
81345200
A
1073void Structure::dump(PrintStream& out) const
1074{
1075 out.print(RawPointer(this), ":[", classInfo()->className, ", {");
1076
1077 Vector<Structure*, 8> structures;
1078 Structure* structure;
1079 PropertyTable* table;
1080
1081 const_cast<Structure*>(this)->findStructuresAndMapForMaterialization(
1082 structures, structure, table);
1083
1084 CommaPrinter comma;
1085
1086 if (table) {
1087 PropertyTable::iterator iter = table->begin();
1088 PropertyTable::iterator end = table->end();
1089 for (; iter != end; ++iter) {
1090 out.print(comma, iter->key, ":", static_cast<int>(iter->offset));
1091 if (iter->specificValue) {
1092 DumpContext dummyContext;
1093 out.print("=>", RawPointer(iter->specificValue.get()));
1094 }
1095 }
1096
1097 structure->m_lock.unlock();
1098 }
1099
1100 for (unsigned i = structures.size(); i--;) {
1101 Structure* structure = structures[i];
1102 if (!structure->m_nameInPrevious)
1103 continue;
1104 out.print(comma, structure->m_nameInPrevious.get(), ":", static_cast<int>(structure->m_offset));
1105 if (structure->m_specificValueInPrevious) {
1106 DumpContext dummyContext;
1107 out.print("=>", RawPointer(structure->m_specificValueInPrevious.get()));
1108 }
1109 }
1110
1111 out.print("}, ", IndexingTypeDump(indexingType()));
1112
1113 if (m_prototype.get().isCell())
1114 out.print(", Proto:", RawPointer(m_prototype.get().asCell()));
1115
1116 out.print("]");
1117}
1118
1119void Structure::dumpInContext(PrintStream& out, DumpContext* context) const
1120{
1121 if (context)
1122 context->structures.dumpBrief(this, out);
1123 else
1124 dump(out);
1125}
1126
1127void Structure::dumpBrief(PrintStream& out, const CString& string) const
1128{
1129 out.print("%", string, ":", classInfo()->className);
1130}
1131
1132void Structure::dumpContextHeader(PrintStream& out)
1133{
1134 out.print("Structures:");
1135}
1136
9dae56ea
A
1137#if DO_PROPERTYMAP_CONSTENCY_CHECK
1138
14957cd0 1139void PropertyTable::checkConsistency()
9dae56ea 1140{
93a37866 1141 checkOffsetConsistency();
14957cd0
A
1142 ASSERT(m_indexSize >= PropertyTable::MinimumTableSize);
1143 ASSERT(m_indexMask);
1144 ASSERT(m_indexSize == m_indexMask + 1);
1145 ASSERT(!(m_indexSize & m_indexMask));
9dae56ea 1146
14957cd0
A
1147 ASSERT(m_keyCount <= m_indexSize / 2);
1148 ASSERT(m_keyCount + m_deletedCount <= m_indexSize / 2);
1149 ASSERT(m_deletedCount <= m_indexSize / 4);
9dae56ea
A
1150
1151 unsigned indexCount = 0;
1152 unsigned deletedIndexCount = 0;
14957cd0
A
1153 for (unsigned a = 0; a != m_indexSize; ++a) {
1154 unsigned entryIndex = m_index[a];
1155 if (entryIndex == PropertyTable::EmptyEntryIndex)
9dae56ea 1156 continue;
14957cd0 1157 if (entryIndex == deletedEntryIndex()) {
9dae56ea
A
1158 ++deletedIndexCount;
1159 continue;
1160 }
14957cd0
A
1161 ASSERT(entryIndex < deletedEntryIndex());
1162 ASSERT(entryIndex - 1 <= usedCount());
9dae56ea
A
1163 ++indexCount;
1164
14957cd0
A
1165 for (unsigned b = a + 1; b != m_indexSize; ++b)
1166 ASSERT(m_index[b] != entryIndex);
9dae56ea 1167 }
14957cd0
A
1168 ASSERT(indexCount == m_keyCount);
1169 ASSERT(deletedIndexCount == m_deletedCount);
9dae56ea 1170
14957cd0 1171 ASSERT(!table()[deletedEntryIndex() - 1].key);
9dae56ea
A
1172
1173 unsigned nonEmptyEntryCount = 0;
14957cd0
A
1174 for (unsigned c = 0; c < usedCount(); ++c) {
1175 StringImpl* rep = table()[c].key;
1176 if (rep == PROPERTY_MAP_DELETED_ENTRY_KEY)
9dae56ea
A
1177 continue;
1178 ++nonEmptyEntryCount;
f9bf01c6 1179 unsigned i = rep->existingHash();
9dae56ea
A
1180 unsigned k = 0;
1181 unsigned entryIndex;
1182 while (1) {
14957cd0
A
1183 entryIndex = m_index[i & m_indexMask];
1184 ASSERT(entryIndex != PropertyTable::EmptyEntryIndex);
1185 if (rep == table()[entryIndex - 1].key)
9dae56ea
A
1186 break;
1187 if (k == 0)
f9bf01c6 1188 k = 1 | doubleHash(rep->existingHash());
9dae56ea
A
1189 i += k;
1190 }
1191 ASSERT(entryIndex == c + 1);
1192 }
1193
14957cd0
A
1194 ASSERT(nonEmptyEntryCount == m_keyCount);
1195}
1196
1197void Structure::checkConsistency()
1198{
93a37866 1199 if (!propertyTable())
14957cd0
A
1200 return;
1201
1202 if (!m_hasNonEnumerableProperties) {
93a37866
A
1203 PropertyTable::iterator end = propertyTable()->end();
1204 for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
14957cd0 1205 ASSERT(!(iter->attributes & DontEnum));
14957cd0
A
1206 }
1207 }
1208
93a37866 1209 propertyTable()->checkConsistency();
9dae56ea
A
1210}
1211
1212#endif // DO_PROPERTYMAP_CONSTENCY_CHECK
1213
81345200
A
1214bool ClassInfo::hasStaticSetterOrReadonlyProperties(VM& vm) const
1215{
1216 for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
1217 if (const HashTable* table = ci->propHashTable(vm)) {
1218 if (table->hasSetterOrReadonlyProperties)
1219 return true;
1220 }
1221 }
1222 return false;
1223}
1224
9dae56ea 1225} // namespace JSC