Unreviewed, partially reverting Structure change due to Speedometer2 regression
[WebKit.git] / Source / JavaScriptCore / runtime / StructureInlines.h
1 /*
2  * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #pragma once
27
28 #include "JSArrayBufferView.h"
29 #include "JSCJSValueInlines.h"
30 #include "JSGlobalObject.h"
31 #include "PropertyMapHashTable.h"
32 #include "Structure.h"
33 #include "StructureChain.h"
34 #include "StructureRareDataInlines.h"
35 #include <wtf/Threading.h>
36
37 namespace JSC {
38
39 inline Structure* Structure::create(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingModeIncludingHistory, unsigned inlineCapacity)
40 {
41     ASSERT(vm.structureStructure);
42     ASSERT(classInfo);
43     if (auto* object = prototype.getObject()) {
44         ASSERT(!object->anyObjectInChainMayInterceptIndexedAccesses(vm) || hasSlowPutArrayStorage(indexingModeIncludingHistory) || !hasIndexedProperties(indexingModeIncludingHistory));
45         object->didBecomePrototype();
46     }
47
48     Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, globalObject, prototype, typeInfo, classInfo, indexingModeIncludingHistory, inlineCapacity);
49     structure->finishCreation(vm);
50     return structure;
51 }
52
53 inline Structure* Structure::createStructure(VM& vm)
54 {
55     ASSERT(!vm.structureStructure);
56     Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm);
57     structure->finishCreation(vm, CreatingEarlyCell);
58     return structure;
59 }
60
61 inline Structure* Structure::create(VM& vm, Structure* previous, DeferredStructureTransitionWatchpointFire* deferred)
62 {
63     ASSERT(vm.structureStructure);
64     Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, previous, deferred);
65     newStructure->finishCreation(vm, previous);
66     return newStructure;
67 }
68
69 inline bool Structure::mayInterceptIndexedAccesses() const
70 {
71     if (indexingModeIncludingHistory() & MayHaveIndexedAccessors)
72         return true;
73
74     // Consider a scenario where object O (of global G1)'s prototype is set to A
75     // (of global G2), and G2 is already having a bad time. If an object B with
76     // indexed accessors is then set as the prototype of A:
77     //      O -> A -> B
78     // Then, O should be converted to SlowPutArrayStorage (because it now has an
79     // object with indexed accessors in its prototype chain). But it won't be
80     // converted because this conversion is done by JSGlobalObject::haveAbadTime(),
81     // but G2 is already having a bad time. We solve this by conservatively
82     // treating A as potentially having indexed accessors if its global is already
83     // having a bad time. Hence, when A is set as O's prototype, O will be
84     // converted to SlowPutArrayStorage.
85
86     JSGlobalObject* globalObject = this->globalObject();
87     if (!globalObject)
88         return false;
89     return globalObject->isHavingABadTime();
90 }
91
92 inline JSObject* Structure::storedPrototypeObject() const
93 {
94     ASSERT(hasMonoProto());
95     JSValue value = m_prototype.get();
96     if (value.isNull())
97         return nullptr;
98     return asObject(value);
99 }
100
101 inline Structure* Structure::storedPrototypeStructure() const
102 {
103     ASSERT(hasMonoProto());
104     JSObject* object = storedPrototypeObject();
105     if (!object)
106         return nullptr;
107     return object->structure();
108 }
109
110 ALWAYS_INLINE JSValue Structure::storedPrototype(const JSObject* object) const
111 {
112     ASSERT(isCompilationThread() || Thread::mayBeGCThread() || object->structure() == this);
113     if (hasMonoProto())
114         return storedPrototype();
115     return object->getDirect(knownPolyProtoOffset);
116 }
117
118 ALWAYS_INLINE JSObject* Structure::storedPrototypeObject(const JSObject* object) const
119 {
120     ASSERT(isCompilationThread() || Thread::mayBeGCThread() || object->structure() == this);
121     if (hasMonoProto())
122         return storedPrototypeObject();
123     JSValue proto = object->getDirect(knownPolyProtoOffset);
124     if (proto.isNull())
125         return nullptr;
126     return asObject(proto);
127 }
128
129 ALWAYS_INLINE Structure* Structure::storedPrototypeStructure(const JSObject* object) const
130 {
131     if (JSObject* proto = storedPrototypeObject(object))
132         return proto->structure();
133     return nullptr;
134 }
135
136 ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName)
137 {
138     unsigned attributes;
139     return get(vm, propertyName, attributes);
140 }
141     
142 ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes)
143 {
144     ASSERT(!isCompilationThread());
145     ASSERT(structure(vm)->classInfo() == info());
146
147     if (m_seenProperties.ruleOut(bitwise_cast<uintptr_t>(propertyName.uid())))
148         return invalidOffset;
149
150     PropertyTable* propertyTable = ensurePropertyTableIfNotEmpty(vm);
151     if (!propertyTable)
152         return invalidOffset;
153
154     PropertyMapEntry* entry = propertyTable->get(propertyName.uid());
155     if (!entry)
156         return invalidOffset;
157
158     attributes = entry->attributes;
159     return entry->offset;
160 }
161
162 template<typename Functor>
163 void Structure::forEachPropertyConcurrently(const Functor& functor)
164 {
165     Vector<Structure*, 8> structures;
166     Structure* tableStructure;
167     PropertyTable* table;
168     
169     findStructuresAndMapForMaterialization(structures, tableStructure, table);
170
171     HashSet<UniquedStringImpl*> seenProperties;
172
173     for (auto* structure : structures) {
174         if (!structure->m_transitionPropertyName || seenProperties.contains(structure->m_transitionPropertyName.get()))
175             continue;
176
177         seenProperties.add(structure->m_transitionPropertyName.get());
178
179         if (structure->isPropertyDeletionTransition())
180             continue;
181
182         if (!functor(PropertyMapEntry(structure->m_transitionPropertyName.get(), structure->transitionOffset(), structure->transitionPropertyAttributes()))) {
183             if (table)
184                 tableStructure->m_lock.unlock();
185             return;
186         }
187     }
188     
189     if (table) {
190         for (auto& entry : *table) {
191             if (seenProperties.contains(entry.key))
192                 continue;
193
194             if (!functor(entry)) {
195                 tableStructure->m_lock.unlock();
196                 return;
197             }
198         }
199         tableStructure->m_lock.unlock();
200     }
201 }
202
203 template<typename Functor>
204 void Structure::forEachProperty(VM& vm, const Functor& functor)
205 {
206     if (PropertyTable* table = ensurePropertyTableIfNotEmpty(vm)) {
207         for (auto& entry : *table) {
208             if (!functor(entry))
209                 return;
210         }
211     }
212 }
213
214 inline PropertyOffset Structure::getConcurrently(UniquedStringImpl* uid)
215 {
216     unsigned attributesIgnored;
217     return getConcurrently(uid, attributesIgnored);
218 }
219
220 inline bool Structure::hasIndexingHeader(const JSCell* cell) const
221 {
222     if (hasIndexedProperties(indexingType()))
223         return true;
224     
225     if (!isTypedView(typedArrayTypeForType(m_blob.type())))
226         return false;
227
228     return jsCast<const JSArrayBufferView*>(cell)->mode() == WastefulTypedArray;
229 }
230
231 inline bool Structure::mayHaveIndexingHeader() const
232 {
233     if (hasIndexedProperties(indexingType()))
234         return true;
235
236     if (!isTypedView(typedArrayTypeForType(m_blob.type())))
237         return false;
238
239     return true;
240 }
241
242 inline bool Structure::canCacheDeleteIC() const
243 {
244     return !isTypedView(typedArrayTypeForType(m_blob.type()));
245 }
246
247 inline bool Structure::masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject)
248 {
249     return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject;
250 }
251
252 inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
253 {
254     for (Structure* current = this; current; current = current->previousID()) {
255         if (current == structureToFind)
256             return true;
257     }
258     return false;
259 }
260
261 inline void Structure::setCachedOwnKeys(VM& vm, JSImmutableButterfly* ownKeys)
262 {
263     ensureRareData(vm)->setCachedOwnKeys(vm, ownKeys);
264 }
265
266 inline JSImmutableButterfly* Structure::cachedOwnKeys() const
267 {
268     if (!hasRareData())
269         return nullptr;
270     return rareData()->cachedOwnKeys();
271 }
272
273 inline JSImmutableButterfly* Structure::cachedOwnKeysIgnoringSentinel() const
274 {
275     if (!hasRareData())
276         return nullptr;
277     return rareData()->cachedOwnKeysIgnoringSentinel();
278 }
279
280 inline bool Structure::canCacheOwnKeys() const
281 {
282     if (isDictionary())
283         return false;
284     if (hasIndexedProperties(indexingType()))
285         return false;
286     if (typeInfo().overridesGetPropertyNames())
287         return false;
288     return true;
289 }
290
291 ALWAYS_INLINE JSValue prototypeForLookupPrimitiveImpl(JSGlobalObject* globalObject, const Structure* structure)
292 {
293     ASSERT(!structure->isObject());
294
295     if (structure->typeInfo().type() == StringType)
296         return globalObject->stringPrototype();
297     
298     if (structure->typeInfo().type() == BigIntType)
299         return globalObject->bigIntPrototype();
300
301     ASSERT(structure->typeInfo().type() == SymbolType);
302     return globalObject->symbolPrototype();
303 }
304
305 inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const
306 {
307     ASSERT(hasMonoProto());
308     if (isObject())
309         return storedPrototype();
310     return prototypeForLookupPrimitiveImpl(globalObject, this);
311 }
312
313 inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject, JSCell* base) const
314 {
315     ASSERT(base->structure() == this);
316     if (isObject())
317         return storedPrototype(asObject(base));
318     return prototypeForLookupPrimitiveImpl(globalObject, this);
319 }
320
321 inline StructureChain* Structure::prototypeChain(VM& vm, JSGlobalObject* globalObject, JSObject* base) const
322 {
323     ASSERT(base->structure(vm) == this);
324     // We cache our prototype chain so our clients can share it.
325     if (!isValid(globalObject, m_cachedPrototypeChain.get(), base)) {
326         JSValue prototype = prototypeForLookup(globalObject, base);
327         m_cachedPrototypeChain.set(vm, this, StructureChain::create(vm, prototype.isNull() ? nullptr : asObject(prototype)));
328     }
329     return m_cachedPrototypeChain.get();
330 }
331
332 inline StructureChain* Structure::prototypeChain(JSGlobalObject* globalObject, JSObject* base) const
333 {
334     return prototypeChain(globalObject->vm(), globalObject, base);
335 }
336
337 inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain, JSObject* base) const
338 {
339     if (!cachedPrototypeChain)
340         return false;
341
342     VM& vm = globalObject->vm();
343     JSValue prototype = prototypeForLookup(globalObject, base);
344     StructureID* cachedStructure = cachedPrototypeChain->head();
345     while (*cachedStructure && !prototype.isNull()) {
346         if (asObject(prototype)->structureID() != *cachedStructure)
347             return false;
348         ++cachedStructure;
349         prototype = asObject(prototype)->getPrototypeDirect(vm);
350     }
351     return prototype.isNull() && !*cachedStructure;
352 }
353
354 inline void Structure::didReplaceProperty(PropertyOffset offset)
355 {
356     if (LIKELY(!hasRareData()))
357         return;
358     StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get();
359     if (LIKELY(!map))
360         return;
361     WatchpointSet* set = map->get(offset);
362     if (LIKELY(!set))
363         return;
364     set->fireAll(vm(), "Property did get replaced");
365 }
366
367 inline WatchpointSet* Structure::propertyReplacementWatchpointSet(PropertyOffset offset)
368 {
369     ConcurrentJSLocker locker(m_lock);
370     if (!hasRareData())
371         return nullptr;
372     WTF::loadLoadFence();
373     StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get();
374     if (!map)
375         return nullptr;
376     return map->get(offset);
377 }
378
379 template<typename DetailsFunc>
380 ALWAYS_INLINE bool Structure::checkOffsetConsistency(PropertyTable* propertyTable, const DetailsFunc& detailsFunc) const
381 {
382     // We cannot reliably assert things about the property table in the concurrent
383     // compilation thread. It is possible for the table to be stolen and then have
384     // things added to it, which leads to the offsets being all messed up. We could
385     // get around this by grabbing a lock here, but I think that would be overkill.
386     if (isCompilationThread())
387         return true;
388     
389     unsigned totalSize = propertyTable->propertyStorageSize();
390     unsigned inlineOverflowAccordingToTotalSize = totalSize < m_inlineCapacity ? 0 : totalSize - m_inlineCapacity;
391
392     auto fail = [&] (const char* description) {
393         dataLog("Detected offset inconsistency: ", description, "!\n");
394         dataLog("this = ", RawPointer(this), "\n");
395         dataLog("transitionOffset = ", transitionOffset(), "\n");
396         dataLog("maxOffset = ", maxOffset(), "\n");
397         dataLog("m_inlineCapacity = ", m_inlineCapacity, "\n");
398         dataLog("propertyTable = ", RawPointer(propertyTable), "\n");
399         dataLog("numberOfSlotsForMaxOffset = ", numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity), "\n");
400         dataLog("totalSize = ", totalSize, "\n");
401         dataLog("inlineOverflowAccordingToTotalSize = ", inlineOverflowAccordingToTotalSize, "\n");
402         dataLog("numberOfOutOfLineSlotsForMaxOffset = ", numberOfOutOfLineSlotsForMaxOffset(maxOffset()), "\n");
403         detailsFunc();
404         UNREACHABLE_FOR_PLATFORM();
405     };
406     
407     if (numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity) != totalSize)
408         fail("numberOfSlotsForMaxOffset doesn't match totalSize");
409     if (inlineOverflowAccordingToTotalSize != numberOfOutOfLineSlotsForMaxOffset(maxOffset()))
410         fail("inlineOverflowAccordingToTotalSize doesn't match numberOfOutOfLineSlotsForMaxOffset");
411
412     return true;
413 }
414
415 ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
416 {
417     PropertyTable* propertyTable = propertyTableOrNull();
418
419     if (!propertyTable) {
420         ASSERT(!isPinnedPropertyTable());
421         return true;
422     }
423
424     // We cannot reliably assert things about the property table in the concurrent
425     // compilation thread. It is possible for the table to be stolen and then have
426     // things added to it, which leads to the offsets being all messed up. We could
427     // get around this by grabbing a lock here, but I think that would be overkill.
428     if (isCompilationThread())
429         return true;
430
431     return checkOffsetConsistency(propertyTable, [] () { });
432 }
433
434 inline void Structure::checkConsistency()
435 {
436     checkOffsetConsistency();
437 }
438
439 inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
440 {
441     if (!currentCapacity)
442         return initialOutOfLineCapacity;
443     return currentCapacity * outOfLineGrowthFactor;
444 }
445
446 inline void Structure::setObjectToStringValue(JSGlobalObject* globalObject, VM& vm, JSString* value, PropertySlot toStringTagSymbolSlot)
447 {
448     if (!hasRareData())
449         allocateRareData(vm);
450     rareData()->setObjectToStringValue(globalObject, vm, this, value, toStringTagSymbolSlot);
451 }
452
453 template<Structure::ShouldPin shouldPin, typename Func>
454 inline PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned attributes, const Func& func)
455 {
456     PropertyTable* table = ensurePropertyTable(vm);
457
458     GCSafeConcurrentJSLocker locker(m_lock, vm.heap);
459
460     switch (shouldPin) {
461     case ShouldPin::Yes:
462         pin(locker, vm, table);
463         break;
464     case ShouldPin::No:
465         setPropertyTable(vm, table);
466         break;
467     }
468     
469     ASSERT(!JSC::isValidOffset(get(vm, propertyName)));
470
471     checkConsistency();
472     if (attributes & PropertyAttribute::DontEnum || propertyName.isSymbol())
473         setIsQuickPropertyAccessAllowedForEnumeration(false);
474     if (propertyName == vm.propertyNames->underscoreProto)
475         setHasUnderscoreProtoPropertyExcludingOriginalProto(true);
476
477     auto rep = propertyName.uid();
478
479     PropertyOffset newOffset = table->nextOffset(m_inlineCapacity);
480
481     m_propertyHash = m_propertyHash ^ rep->existingSymbolAwareHash();
482     m_seenProperties.add(bitwise_cast<uintptr_t>(rep));
483
484     auto result = table->add(PropertyMapEntry(rep, newOffset, attributes));
485     ASSERT_UNUSED(result, result.second);
486     ASSERT_UNUSED(result, result.first.first->offset == newOffset);
487     auto newMaxOffset = std::max(newOffset, maxOffset());
488     
489     func(locker, newOffset, newMaxOffset);
490     
491     ASSERT(maxOffset() == newMaxOffset);
492
493     checkConsistency();
494     return newOffset;
495 }
496
497 template<Structure::ShouldPin shouldPin, typename Func>
498 inline PropertyOffset Structure::remove(VM& vm, PropertyName propertyName, const Func& func)
499 {
500     PropertyTable* table = ensurePropertyTable(vm);
501     GCSafeConcurrentJSLocker locker(m_lock, vm.heap);
502
503     switch (shouldPin) {
504     case ShouldPin::Yes:
505         pin(locker, vm, table);
506         break;
507     case ShouldPin::No:
508         setPropertyTable(vm, table);
509         break;
510     }
511
512     ASSERT(JSC::isValidOffset(get(vm, propertyName)));
513
514     checkConsistency();
515
516     auto rep = propertyName.uid();
517
518     PropertyTable::find_iterator position = table->find(rep);
519     if (!position.first)
520         return invalidOffset;
521
522     setIsQuickPropertyAccessAllowedForEnumeration(false);
523     
524     PropertyOffset offset = position.first->offset;
525
526     table->remove(position);
527     table->addDeletedOffset(offset);
528
529     PropertyOffset newMaxOffset = maxOffset();
530
531     func(locker, offset, newMaxOffset);
532
533     ASSERT(maxOffset() == newMaxOffset);
534     ASSERT(!JSC::isValidOffset(get(vm, propertyName)));
535
536     checkConsistency();
537     return offset;
538 }
539
540 template<typename Func>
541 inline PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, const Func& func)
542 {
543     return add<ShouldPin::Yes>(vm, propertyName, attributes, func);
544 }
545
546 template<typename Func>
547 inline PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName propertyName, const Func& func)
548 {
549     ASSERT(isUncacheableDictionary());
550     ASSERT(isPinnedPropertyTable());
551     ASSERT(propertyTableOrNull());
552     
553     return remove<ShouldPin::Yes>(vm, propertyName, func);
554 }
555
556 ALWAYS_INLINE void Structure::setPrototypeWithoutTransition(VM& vm, JSValue prototype)
557 {
558     ASSERT(isValidPrototype(prototype));
559     m_prototype.set(vm, this, prototype);
560 }
561
562 ALWAYS_INLINE void Structure::setGlobalObject(VM& vm, JSGlobalObject* globalObject)
563 {
564     m_globalObject.set(vm, this, globalObject);
565 }
566
567 ALWAYS_INLINE void Structure::setPropertyTable(VM& vm, PropertyTable* table)
568 {
569     m_propertyTableUnsafe.setMayBeNull(vm, this, table);
570 }
571
572 ALWAYS_INLINE void Structure::setPreviousID(VM& vm, Structure* structure)
573 {
574     if (hasRareData())
575         rareData()->setPreviousID(vm, structure);
576     else
577         m_previousOrRareData.set(vm, this, structure);
578 }
579
580 ALWAYS_INLINE bool Structure::shouldConvertToPolyProto(const Structure* a, const Structure* b)
581 {
582     if (!a || !b)
583         return false;
584
585     if (a == b)
586         return false;
587
588     if (a->propertyHash() != b->propertyHash())
589         return false;
590
591     // We only care about objects created via a constructor's to_this. These
592     // all have Structures with rare data and a sharedPolyProtoWatchpoint.
593     if (!a->hasRareData() || !b->hasRareData())
594         return false;
595
596     // We only care about Structure's generated from functions that share
597     // the same executable.
598     const Box<InlineWatchpointSet>& aInlineWatchpointSet = a->rareData()->sharedPolyProtoWatchpoint();
599     const Box<InlineWatchpointSet>& bInlineWatchpointSet = b->rareData()->sharedPolyProtoWatchpoint();
600     if (aInlineWatchpointSet.get() != bInlineWatchpointSet.get() || !aInlineWatchpointSet)
601         return false;
602     ASSERT(aInlineWatchpointSet && bInlineWatchpointSet && aInlineWatchpointSet.get() == bInlineWatchpointSet.get());
603
604     if (a->hasPolyProto() || b->hasPolyProto())
605         return false;
606
607     if (a->storedPrototype() == b->storedPrototype())
608         return false;
609
610     VM& vm = a->vm();
611     JSObject* aObj = a->storedPrototypeObject();
612     JSObject* bObj = b->storedPrototypeObject();
613     while (aObj && bObj) {
614         a = aObj->structure(vm);
615         b = bObj->structure(vm);
616
617         if (a->propertyHash() != b->propertyHash())
618             return false;
619
620         aObj = a->storedPrototypeObject(aObj);
621         bObj = b->storedPrototypeObject(bObj);
622     }
623
624     return !aObj && !bObj;
625 }
626
627 inline Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPropertyTransition transitionKind)
628 {
629     IndexingType indexingModeIncludingHistory = newIndexingType(structure->indexingModeIncludingHistory(), transitionKind);
630
631     if (changesIndexingType(transitionKind)) {
632         if (JSGlobalObject* globalObject = structure->m_globalObject.get()) {
633             if (globalObject->isOriginalArrayStructure(structure)) {
634                 Structure* result = globalObject->originalArrayStructureForIndexingType(indexingModeIncludingHistory);
635                 if (result->indexingModeIncludingHistory() == indexingModeIncludingHistory) {
636                     structure->didTransitionFromThisStructure();
637                     return result;
638                 }
639             }
640         }
641     }
642
643     return nonPropertyTransitionSlow(vm, structure, transitionKind);
644 }
645
646 } // namespace JSC