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