Title: [255646] branches/safari-610.1.1-branch/Source/_javascript_Core
Revision
255646
Author
[email protected]
Date
2020-02-03 19:09:25 -0800 (Mon, 03 Feb 2020)

Log Message

Cherry-pick r254760. rdar://problem/59004377

    Separate storage of Structure::m_offset into transition and max offset
    https://bugs.webkit.org/show_bug.cgi?id=206365

    Reviewed by Saam Barati.

    Right now, deleteProperty/removePropertyTransition causes a structure transition to uncacheable dictionary. Other transitions
    assume that the transition offset (m_offset) is monotonically increasing. In order to support structure transitions for deletion that
    do not involve turning into a dictionary (<https://bugs.webkit.org/show_bug.cgi?id=206430>), we first need to separate the transition
    offset (the offset of the property that was added/deleted) from the maximum offset.

    For example, suppose we have the following operations:
      Structure 1 (pinned property table, transitionOffset = _, maxOffset = 2): x y z (delete y, assuming that deletion transitions have been added)
      Structure 2 (transitionOffset = 1, maxOffset = 2):                        x _ z (add w)
      Structure 3 (transitionOffset = 1, maxOffset = 2):                        x w z

    Note that without splitting the two, Structures 2/3 would be impossible to represent.

    This change:

    We split the existing Structure::m_offset into two 16-bit fields, transitionOffset and maxOffset, and put them in 32-bit rare data fields if they overflow. We also rename _inPrevious fields to
    transition_ and lastOffset to maxOffset to make the code more clear.

    * runtime/ClonedArguments.cpp:
    (JSC::ClonedArguments::createStructure):
    * runtime/JSObject.cpp:
    (JSC::JSObject::markAuxiliaryAndVisitOutOfLineProperties):
    (JSC::JSObject::visitButterflyImpl):
    * runtime/JSObject.h:
    * runtime/JSObjectInlines.h:
    (JSC::JSObject::prepareToPutDirectWithoutTransition):
    * runtime/ObjectInitializationScope.cpp:
    (JSC::ObjectInitializationScope::verifyPropertiesAreInitialized):
    * runtime/PropertyOffset.h:
    (JSC::numberOfOutOfLineSlotsForMaxOffset):
    (JSC::numberOfSlotsForMaxOffset):
    (JSC::numberOfOutOfLineSlotsForLastOffset): Deleted.
    (JSC::numberOfSlotsForLastOffset): Deleted.
    * runtime/Structure.cpp:
    (JSC::StructureTransitionTable::contains const):
    (JSC::StructureTransitionTable::get const):
    (JSC::StructureTransitionTable::add):
    (JSC::Structure::Structure):
    (JSC::Structure::create):
    (JSC::Structure::materializePropertyTable):
    (JSC::Structure::addPropertyTransitionToExistingStructureImpl):
    (JSC::Structure::addNewPropertyTransition):
    (JSC::Structure::changePrototypeTransition):
    (JSC::Structure::attributeChangeTransition):
    (JSC::Structure::toDictionaryTransition):
    (JSC::Structure::nonPropertyTransitionSlow):
    (JSC::Structure::flattenDictionaryStructure):
    (JSC::Structure::pin):
    (JSC::Structure::pinForCaching):
    (JSC::Structure::add):
    * runtime/Structure.h:
    * runtime/StructureInlines.h:
    (JSC::Structure::forEachPropertyConcurrently):
    (JSC::Structure::checkOffsetConsistency const):
    (JSC::Structure::add):
    * runtime/StructureRareData.cpp:
    (JSC::StructureRareData::StructureRareData):
    * runtime/StructureRareData.h:

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@254760 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Diff

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/ChangeLog (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/ChangeLog	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/ChangeLog	2020-02-04 03:09:25 UTC (rev 255646)
@@ -1,3 +1,138 @@
+2020-02-03  Alan Coon  <[email protected]>
+
+        Cherry-pick r254760. rdar://problem/59004377
+
+    Separate storage of Structure::m_offset into transition and max offset
+    https://bugs.webkit.org/show_bug.cgi?id=206365
+    
+    Reviewed by Saam Barati.
+    
+    Right now, deleteProperty/removePropertyTransition causes a structure transition to uncacheable dictionary. Other transitions
+    assume that the transition offset (m_offset) is monotonically increasing. In order to support structure transitions for deletion that
+    do not involve turning into a dictionary (<https://bugs.webkit.org/show_bug.cgi?id=206430>), we first need to separate the transition
+    offset (the offset of the property that was added/deleted) from the maximum offset.
+    
+    For example, suppose we have the following operations:
+      Structure 1 (pinned property table, transitionOffset = _, maxOffset = 2): x y z (delete y, assuming that deletion transitions have been added)
+      Structure 2 (transitionOffset = 1, maxOffset = 2):                        x _ z (add w)
+      Structure 3 (transitionOffset = 1, maxOffset = 2):                        x w z
+    
+    Note that without splitting the two, Structures 2/3 would be impossible to represent.
+    
+    This change:
+    
+    We split the existing Structure::m_offset into two 16-bit fields, transitionOffset and maxOffset, and put them in 32-bit rare data fields if they overflow. We also rename _inPrevious fields to
+    transition_ and lastOffset to maxOffset to make the code more clear.
+    
+    * runtime/ClonedArguments.cpp:
+    (JSC::ClonedArguments::createStructure):
+    * runtime/JSObject.cpp:
+    (JSC::JSObject::markAuxiliaryAndVisitOutOfLineProperties):
+    (JSC::JSObject::visitButterflyImpl):
+    * runtime/JSObject.h:
+    * runtime/JSObjectInlines.h:
+    (JSC::JSObject::prepareToPutDirectWithoutTransition):
+    * runtime/ObjectInitializationScope.cpp:
+    (JSC::ObjectInitializationScope::verifyPropertiesAreInitialized):
+    * runtime/PropertyOffset.h:
+    (JSC::numberOfOutOfLineSlotsForMaxOffset):
+    (JSC::numberOfSlotsForMaxOffset):
+    (JSC::numberOfOutOfLineSlotsForLastOffset): Deleted.
+    (JSC::numberOfSlotsForLastOffset): Deleted.
+    * runtime/Structure.cpp:
+    (JSC::StructureTransitionTable::contains const):
+    (JSC::StructureTransitionTable::get const):
+    (JSC::StructureTransitionTable::add):
+    (JSC::Structure::Structure):
+    (JSC::Structure::create):
+    (JSC::Structure::materializePropertyTable):
+    (JSC::Structure::addPropertyTransitionToExistingStructureImpl):
+    (JSC::Structure::addNewPropertyTransition):
+    (JSC::Structure::changePrototypeTransition):
+    (JSC::Structure::attributeChangeTransition):
+    (JSC::Structure::toDictionaryTransition):
+    (JSC::Structure::nonPropertyTransitionSlow):
+    (JSC::Structure::flattenDictionaryStructure):
+    (JSC::Structure::pin):
+    (JSC::Structure::pinForCaching):
+    (JSC::Structure::add):
+    * runtime/Structure.h:
+    * runtime/StructureInlines.h:
+    (JSC::Structure::forEachPropertyConcurrently):
+    (JSC::Structure::checkOffsetConsistency const):
+    (JSC::Structure::add):
+    * runtime/StructureRareData.cpp:
+    (JSC::StructureRareData::StructureRareData):
+    * runtime/StructureRareData.h:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@254760 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2020-01-17  Justin Michaud  <[email protected]>
+
+            Separate storage of Structure::m_offset into transition and max offset
+            https://bugs.webkit.org/show_bug.cgi?id=206365
+
+            Reviewed by Saam Barati.
+
+            Right now, deleteProperty/removePropertyTransition causes a structure transition to uncacheable dictionary. Other transitions
+            assume that the transition offset (m_offset) is monotonically increasing. In order to support structure transitions for deletion that
+            do not involve turning into a dictionary (<https://bugs.webkit.org/show_bug.cgi?id=206430>), we first need to separate the transition
+            offset (the offset of the property that was added/deleted) from the maximum offset.
+
+            For example, suppose we have the following operations:
+              Structure 1 (pinned property table, transitionOffset = _, maxOffset = 2): x y z (delete y, assuming that deletion transitions have been added)
+              Structure 2 (transitionOffset = 1, maxOffset = 2):                        x _ z (add w)
+              Structure 3 (transitionOffset = 1, maxOffset = 2):                        x w z
+
+            Note that without splitting the two, Structures 2/3 would be impossible to represent.
+
+            This change:
+
+            We split the existing Structure::m_offset into two 16-bit fields, transitionOffset and maxOffset, and put them in 32-bit rare data fields if they overflow. We also rename _inPrevious fields to
+            transition_ and lastOffset to maxOffset to make the code more clear.
+
+            * runtime/ClonedArguments.cpp:
+            (JSC::ClonedArguments::createStructure):
+            * runtime/JSObject.cpp:
+            (JSC::JSObject::markAuxiliaryAndVisitOutOfLineProperties):
+            (JSC::JSObject::visitButterflyImpl):
+            * runtime/JSObject.h:
+            * runtime/JSObjectInlines.h:
+            (JSC::JSObject::prepareToPutDirectWithoutTransition):
+            * runtime/ObjectInitializationScope.cpp:
+            (JSC::ObjectInitializationScope::verifyPropertiesAreInitialized):
+            * runtime/PropertyOffset.h:
+            (JSC::numberOfOutOfLineSlotsForMaxOffset):
+            (JSC::numberOfSlotsForMaxOffset):
+            (JSC::numberOfOutOfLineSlotsForLastOffset): Deleted.
+            (JSC::numberOfSlotsForLastOffset): Deleted.
+            * runtime/Structure.cpp:
+            (JSC::StructureTransitionTable::contains const):
+            (JSC::StructureTransitionTable::get const):
+            (JSC::StructureTransitionTable::add):
+            (JSC::Structure::Structure):
+            (JSC::Structure::create):
+            (JSC::Structure::materializePropertyTable):
+            (JSC::Structure::addPropertyTransitionToExistingStructureImpl):
+            (JSC::Structure::addNewPropertyTransition):
+            (JSC::Structure::changePrototypeTransition):
+            (JSC::Structure::attributeChangeTransition):
+            (JSC::Structure::toDictionaryTransition):
+            (JSC::Structure::nonPropertyTransitionSlow):
+            (JSC::Structure::flattenDictionaryStructure):
+            (JSC::Structure::pin):
+            (JSC::Structure::pinForCaching):
+            (JSC::Structure::add):
+            * runtime/Structure.h:
+            * runtime/StructureInlines.h:
+            (JSC::Structure::forEachPropertyConcurrently):
+            (JSC::Structure::checkOffsetConsistency const):
+            (JSC::Structure::add):
+            * runtime/StructureRareData.cpp:
+            (JSC::StructureRareData::StructureRareData):
+            * runtime/StructureRareData.h:
+
 2020-01-29  Alan Coon  <[email protected]>
 
         Cherry-pick r254632. rdar://problem/59001684

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/ClonedArguments.cpp (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/ClonedArguments.cpp	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/ClonedArguments.cpp	2020-02-04 03:09:25 UTC (rev 255646)
@@ -153,9 +153,9 @@
     Structure* structure = Structure::create(vm, globalObject, prototype, TypeInfo(ClonedArgumentsType, StructureFlags), info(), indexingType);
     structure->addPropertyWithoutTransition(
         vm, vm.propertyNames->length, static_cast<unsigned>(PropertyAttribute::DontEnum),
-        [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newLastOffset) {
+        [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
             RELEASE_ASSERT(offset == clonedArgumentsLengthPropertyOffset);
-            structure->setLastOffset(newLastOffset);
+            structure->setMaxOffset(vm, newMaxOffset);
         });
     return structure;
 }

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObject.cpp (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObject.cpp	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObject.cpp	2020-02-04 03:09:25 UTC (rev 255646)
@@ -92,7 +92,7 @@
     }
 }
 
-ALWAYS_INLINE void JSObject::markAuxiliaryAndVisitOutOfLineProperties(SlotVisitor& visitor, Butterfly* butterfly, Structure* structure, PropertyOffset lastOffset)
+ALWAYS_INLINE void JSObject::markAuxiliaryAndVisitOutOfLineProperties(SlotVisitor& visitor, Butterfly* butterfly, Structure* structure, PropertyOffset maxOffset)
 {
     // We call this when we found everything without races.
     ASSERT(structure);
@@ -113,13 +113,13 @@
         preCapacity = 0;
     
     HeapCell* base = bitwise_cast<HeapCell*>(
-        butterfly->base(preCapacity, Structure::outOfLineCapacity(lastOffset)));
+        butterfly->base(preCapacity, Structure::outOfLineCapacity(maxOffset)));
     
     ASSERT(Heap::heap(base) == visitor.heap());
     
     visitor.markAuxiliary(base);
     
-    unsigned outOfLineSize = Structure::outOfLineSize(lastOffset);
+    unsigned outOfLineSize = Structure::outOfLineSize(maxOffset);
     visitor.appendValuesHidden(butterfly->propertyStorage() - outOfLineSize, outOfLineSize);
 }
 
@@ -138,7 +138,7 @@
     
     Butterfly* butterfly;
     Structure* structure;
-    PropertyOffset lastOffset;
+    PropertyOffset maxOffset;
 
     auto visitElements = [&] (IndexingType indexingMode) {
         switch (indexingMode) {
@@ -159,9 +159,9 @@
     if (visitor.mutatorIsStopped()) {
         butterfly = this->butterfly();
         structure = this->structure(vm);
-        lastOffset = structure->lastOffset();
+        maxOffset = structure->maxOffset();
         
-        markAuxiliaryAndVisitOutOfLineProperties(visitor, butterfly, structure, lastOffset);
+        markAuxiliaryAndVisitOutOfLineProperties(visitor, butterfly, structure, maxOffset);
         visitElements(structure->indexingMode());
 
         return structure;
@@ -174,7 +174,7 @@
     //
     //     object->structure = nuke(object->structure)
     //     object->butterfly = newButterfly
-    //     structure->m_offset = newLastOffset
+    //     structure->m_offset = newMaxOffset
     //     object->structure = newStructure
     //
     // It's OK to skip this when reallocating the butterfly in a way that does not affect the m_offset.
@@ -230,143 +230,143 @@
     // the collector reads the size early and late as well. Lets consider the interleaving of the
     // mutator changing the size without changing the structure:
     //
-    //     NukeStructure ChangeButterfly ChangeLastOffset RestoreStructure
+    //     NukeStructure ChangeButterfly ChangeMaxOffset RestoreStructure
     //
     // Meanwhile the collector does:
     //
-    //     ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate
+    //     ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate
     //
     // The collector can detect races by not only comparing the early structure to the late structure
     // (which will be the same before and after the algorithm runs) but also by comparing the early and
-    // late lastOffsets.  Note: the IGNORE proofs do not cite all of the reasons why the collector will
+    // late maxOffsets. Note: the IGNORE proofs do not cite all of the reasons why the collector will
     // ignore the case, since we only need to identify one to say that we're in the ignore case.
     //
-    // NukeStructure ChangeButterfly ChangeLastOffset RestoreStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate: AFTER, trivially
-    // NukeStructure ChangeButterfly ChangeLastOffset ReadStructureEarly RestoreStructure ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ChangeLastOffset ReadStructureEarly ReadLastOffsetEarly RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ChangeLastOffset ReadStructureEarly ReadLastOffsetEarly ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ChangeLastOffset ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ChangeLastOffset ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ChangeLastOffset RestoreStructure ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ChangeLastOffset ReadLastOffsetEarly RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ChangeLastOffset ReadLastOffsetEarly ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ChangeLastOffset ReadLastOffsetEarly ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ChangeLastOffset ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ChangeLastOffset RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ChangeLastOffset ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ChangeLastOffset ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ChangeLastOffset ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ChangeButterfly ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ChangeLastOffset RestoreStructure ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ChangeLastOffset ReadLastOffsetEarly RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ChangeLastOffset ReadLastOffsetEarly ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ChangeLastOffset ReadLastOffsetEarly ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ChangeLastOffset ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ChangeLastOffset RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ChangeLastOffset ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ChangeLastOffset ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ChangeLastOffset ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ReadButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ReadButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ReadButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ChangeButterfly ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ChangeLastOffset RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ChangeLastOffset ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ChangeLastOffset ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ChangeLastOffset ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ReadButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ReadButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ReadButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure early
-    // NukeStructure ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeButterfly ChangeLastOffset RestoreStructure: IGNORE, read nuked structure early
-    // ReadStructureEarly NukeStructure ChangeButterfly ChangeLastOffset RestoreStructure ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate: AFTER, the ReadStructureEarly sees the same structure as after and everything else runs after.
-    // ReadStructureEarly NukeStructure ChangeButterfly ChangeLastOffset ReadLastOffsetEarly RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: AFTER, as above and the ReadLastOffsetEarly sees the lastOffset after.
-    // ReadStructureEarly NukeStructure ChangeButterfly ChangeLastOffset ReadLastOffsetEarly ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: AFTER, as above and the ReadButterfly sees the right butterfly after.
-    // ReadStructureEarly NukeStructure ChangeButterfly ChangeLastOffset ReadLastOffsetEarly ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure late
-    // ReadStructureEarly NukeStructure ChangeButterfly ChangeLastOffset ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ChangeLastOffset RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ChangeLastOffset ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ChangeLastOffset ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ChangeLastOffset ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ReadButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ReadButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ReadButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ChangeButterfly ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ChangeLastOffset RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ChangeLastOffset ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ChangeLastOffset ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ChangeLastOffset ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ReadButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ReadButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ReadButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ChangeButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ChangeButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ChangeButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly NukeStructure ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeButterfly ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ChangeLastOffset RestoreStructure ReadButterfly ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ChangeLastOffset ReadButterfly RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ChangeLastOffset ReadButterfly ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ChangeLastOffset ReadButterfly ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ReadButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ReadButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ReadButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ReadButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ReadButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ChangeButterfly ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ChangeButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ChangeButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ChangeButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ChangeButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ChangeButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ChangeButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ReadStructureLate ChangeButterfly ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ReadStructureLate ChangeButterfly ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ReadStructureLate ChangeButterfly ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly NukeStructure ReadButterfly ReadStructureLate ReadLastOffsetLate ChangeButterfly ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ChangeButterfly ChangeLastOffset RestoreStructure ReadStructureLate ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ChangeButterfly ChangeLastOffset ReadStructureLate RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ChangeButterfly ChangeLastOffset ReadStructureLate ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ChangeButterfly ReadStructureLate ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ChangeButterfly ReadStructureLate ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ChangeButterfly ReadStructureLate ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ReadStructureLate ChangeButterfly ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ReadStructureLate ChangeButterfly ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ReadStructureLate ChangeButterfly ReadLastOffsetLate ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly NukeStructure ReadStructureLate ReadLastOffsetLate ChangeButterfly ChangeLastOffset RestoreStructure: IGNORE, read nuked structure late
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate NukeStructure ChangeButterfly ChangeLastOffset RestoreStructure ReadLastOffsetLate: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate NukeStructure ChangeButterfly ChangeLastOffset ReadLastOffsetLate RestoreStructure: IGNORE, read different offsets
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate NukeStructure ChangeButterfly ReadLastOffsetLate ChangeLastOffset RestoreStructure: BEFORE, reads the offset before, everything else happens before
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate NukeStructure ReadLastOffsetLate ChangeButterfly ChangeLastOffset RestoreStructure: BEFORE, reads the offset before, everything else happens before
-    // ReadStructureEarly ReadLastOffsetEarly ReadButterfly ReadStructureLate ReadLastOffsetLate NukeStructure ChangeButterfly ChangeLastOffset RestoreStructure: BEFORE, trivially
+    // NukeStructure ChangeButterfly ChangeMaxOffset RestoreStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate: AFTER, trivially
+    // NukeStructure ChangeButterfly ChangeMaxOffset ReadStructureEarly RestoreStructure ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ChangeMaxOffset ReadStructureEarly ReadMaxOffsetEarly RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ChangeMaxOffset ReadStructureEarly ReadMaxOffsetEarly ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ChangeMaxOffset ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ChangeMaxOffset ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ChangeMaxOffset RestoreStructure ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ChangeMaxOffset ReadMaxOffsetEarly RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ChangeMaxOffset RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ChangeButterfly ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ChangeMaxOffset RestoreStructure ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ChangeMaxOffset ReadMaxOffsetEarly RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ChangeMaxOffset RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ChangeButterfly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ChangeMaxOffset RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ChangeMaxOffset ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ChangeMaxOffset ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ChangeMaxOffset ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ReadButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ReadButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ReadButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure early
+    // NukeStructure ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeButterfly ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure early
+    // ReadStructureEarly NukeStructure ChangeButterfly ChangeMaxOffset RestoreStructure ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate: AFTER, the ReadStructureEarly sees the same structure as after and everything else runs after.
+    // ReadStructureEarly NukeStructure ChangeButterfly ChangeMaxOffset ReadMaxOffsetEarly RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: AFTER, as above and the ReadMaxOffsetEarly sees the maxOffset after.
+    // ReadStructureEarly NukeStructure ChangeButterfly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: AFTER, as above and the ReadButterfly sees the right butterfly after.
+    // ReadStructureEarly NukeStructure ChangeButterfly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure late
+    // ReadStructureEarly NukeStructure ChangeButterfly ChangeMaxOffset ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ChangeMaxOffset RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ChangeMaxOffset ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ReadButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ChangeButterfly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ChangeMaxOffset RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ChangeMaxOffset ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ChangeMaxOffset ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ChangeMaxOffset ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ReadButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ReadButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ReadButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ChangeButterfly ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ChangeButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ChangeButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ChangeButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ChangeButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ReadStructureLate ChangeButterfly ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly NukeStructure ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeButterfly ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ChangeMaxOffset RestoreStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ChangeMaxOffset ReadButterfly RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ChangeMaxOffset ReadButterfly ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ChangeMaxOffset ReadButterfly ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ReadButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ReadButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ReadButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ReadButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ReadButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ChangeButterfly ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ChangeButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ChangeButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ChangeButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ChangeButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ChangeButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ChangeButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ReadStructureLate ChangeButterfly ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ReadStructureLate ChangeButterfly ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ReadStructureLate ChangeButterfly ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly NukeStructure ReadButterfly ReadStructureLate ReadMaxOffsetLate ChangeButterfly ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ChangeButterfly ChangeMaxOffset RestoreStructure ReadStructureLate ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ChangeButterfly ChangeMaxOffset ReadStructureLate RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ChangeButterfly ChangeMaxOffset ReadStructureLate ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ChangeButterfly ReadStructureLate ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ChangeButterfly ReadStructureLate ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ChangeButterfly ReadStructureLate ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ReadStructureLate ChangeButterfly ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ReadStructureLate ChangeButterfly ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ReadStructureLate ChangeButterfly ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly NukeStructure ReadStructureLate ReadMaxOffsetLate ChangeButterfly ChangeMaxOffset RestoreStructure: IGNORE, read nuked structure late
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate NukeStructure ChangeButterfly ChangeMaxOffset RestoreStructure ReadMaxOffsetLate: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate NukeStructure ChangeButterfly ChangeMaxOffset ReadMaxOffsetLate RestoreStructure: IGNORE, read different offsets
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate NukeStructure ChangeButterfly ReadMaxOffsetLate ChangeMaxOffset RestoreStructure: BEFORE, reads the offset before, everything else happens before
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate NukeStructure ReadMaxOffsetLate ChangeButterfly ChangeMaxOffset RestoreStructure: BEFORE, reads the offset before, everything else happens before
+    // ReadStructureEarly ReadMaxOffsetEarly ReadButterfly ReadStructureLate ReadMaxOffsetLate NukeStructure ChangeButterfly ChangeMaxOffset RestoreStructure: BEFORE, trivially
     //
     // Whew.
     //
@@ -392,7 +392,7 @@
     if (isNuked(structureID))
         return nullptr;
     structure = vm.getStructure(structureID);
-    lastOffset = structure->lastOffset();
+    maxOffset = structure->maxOffset();
     IndexingType indexingMode = structure->indexingMode();
     Dependency indexingModeDependency = Dependency::fence(indexingMode);
     Locker<JSCellLock> locker(NoLockingNecessary);
@@ -415,10 +415,10 @@
         return structure;
     if (butterflyDependency.consume(this)->structureID() != structureID)
         return nullptr;
-    if (butterflyDependency.consume(structure)->lastOffset() != lastOffset)
+    if (butterflyDependency.consume(structure)->maxOffset() != maxOffset)
         return nullptr;
     
-    markAuxiliaryAndVisitOutOfLineProperties(visitor, butterfly, structure, lastOffset);
+    markAuxiliaryAndVisitOutOfLineProperties(visitor, butterfly, structure, maxOffset);
     ASSERT(indexingMode == structure->indexingMode());
     visitElements(indexingMode);
     

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObject.h (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObject.h	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObject.h	2020-02-04 03:09:25 UTC (rev 255646)
@@ -941,7 +941,7 @@
     
     Structure* visitButterflyImpl(SlotVisitor&);
     
-    void markAuxiliaryAndVisitOutOfLineProperties(SlotVisitor&, Butterfly*, Structure*, PropertyOffset lastOffset);
+    void markAuxiliaryAndVisitOutOfLineProperties(SlotVisitor&, Butterfly*, Structure*, PropertyOffset maxOffset);
 
     // Call this if you know that the object is in a mode where it has array
     // storage. This will assert otherwise.

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObjectInlines.h (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObjectInlines.h	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/JSObjectInlines.h	2020-02-04 03:09:25 UTC (rev 255646)
@@ -216,16 +216,16 @@
     PropertyOffset result;
     structure->addPropertyWithoutTransition(
         vm, propertyName, attributes,
-        [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newLastOffset) {
-            unsigned newOutOfLineCapacity = Structure::outOfLineCapacity(newLastOffset);
+        [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
+            unsigned newOutOfLineCapacity = Structure::outOfLineCapacity(newMaxOffset);
             if (newOutOfLineCapacity != oldOutOfLineCapacity) {
                 Butterfly* butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity);
                 nukeStructureAndSetButterfly(vm, structureID, butterfly);
-                structure->setLastOffset(newLastOffset);
+                structure->setMaxOffset(vm, newMaxOffset);
                 WTF::storeStoreFence();
                 setStructureIDDirectly(structureID);
             } else
-                structure->setLastOffset(newLastOffset);
+                structure->setMaxOffset(vm, newMaxOffset);
 
             // This assertion verifies that the concurrent GC won't read garbage if the concurrentGC
             // is running at the same time we put without transitioning.

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/ObjectInitializationScope.cpp (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/ObjectInitializationScope.cpp	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/ObjectInitializationScope.cpp	2020-02-04 03:09:25 UTC (rev 255646)
@@ -104,7 +104,7 @@
 
     for (int64_t i = 0; i < static_cast<int64_t>(structure->outOfLineCapacity()); i++) {
         // We rely on properties past the last offset be zero for concurrent GC.
-        if (i + firstOutOfLineOffset > structure->lastOffset())
+        if (i + firstOutOfLineOffset > structure->maxOffset())
             ASSERT(isSafeEmptyValueForGCScanning(butterfly->propertyStorage()[-i - 1].get()));
         else if (isScribbledValue(butterfly->propertyStorage()[-i - 1].get())) {
             dataLogLn("Found scribbled property at i = ", -i - 1);

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/PropertyOffset.h (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/PropertyOffset.h	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/PropertyOffset.h	2020-02-04 03:09:25 UTC (rev 255646)
@@ -47,8 +47,8 @@
 inline size_t offsetInInlineStorage(PropertyOffset);
 inline size_t offsetInOutOfLineStorage(PropertyOffset);
 inline size_t offsetInRespectiveStorage(PropertyOffset);
-inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset);
-inline size_t numberOfSlotsForLastOffset(PropertyOffset, int inlineCapacity);
+inline size_t numberOfOutOfLineSlotsForMaxOffset(PropertyOffset);
+inline size_t numberOfSlotsForMaxOffset(PropertyOffset, int inlineCapacity);
 
 inline void checkOffset(PropertyOffset offset)
 {
@@ -117,7 +117,7 @@
     return offsetInOutOfLineStorage(offset);
 }
 
-inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset offset)
+inline size_t numberOfOutOfLineSlotsForMaxOffset(PropertyOffset offset)
 {
     checkOffset(offset);
     if (offset < firstOutOfLineOffset)
@@ -125,12 +125,12 @@
     return offset - firstOutOfLineOffset + 1;
 }
 
-inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, int inlineCapacity)
+inline size_t numberOfSlotsForMaxOffset(PropertyOffset offset, int inlineCapacity)
 {
     checkOffset(offset, inlineCapacity);
     if (offset < inlineCapacity)
         return offset + 1;
-    return inlineCapacity + numberOfOutOfLineSlotsForLastOffset(offset);
+    return inlineCapacity + numberOfOutOfLineSlotsForMaxOffset(offset);
 }
 
 inline PropertyOffset offsetForPropertyNumber(int propertyNumber, int inlineCapacity)

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/Structure.cpp (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/Structure.cpp	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/Structure.cpp	2020-02-04 03:09:25 UTC (rev 255646)
@@ -91,7 +91,7 @@
 {
     if (isUsingSingleSlot()) {
         Structure* transition = singleTransition();
-        return transition && transition->m_nameInPrevious == rep && transition->attributesInPrevious() == attributes;
+        return transition && transition->m_transitionPropertyName == rep && transition->transitionPropertyAttributes() == attributes;
     }
     return map()->get(std::make_pair(rep, attributes));
 }
@@ -100,7 +100,7 @@
 {
     if (isUsingSingleSlot()) {
         Structure* transition = singleTransition();
-        return (transition && transition->m_nameInPrevious == rep && transition->attributesInPrevious() == attributes) ? transition : 0;
+        return (transition && transition->m_transitionPropertyName == rep && transition->transitionPropertyAttributes() == attributes) ? transition : 0;
     }
     return map()->get(std::make_pair(rep, attributes));
 }
@@ -127,7 +127,7 @@
     // Newer versions of the STL have an std::make_pair function that takes rvalue references.
     // 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.
     // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
-    map()->set(std::make_pair(structure->m_nameInPrevious.get(), +structure->attributesInPrevious()), structure);
+    map()->set(std::make_pair(structure->m_transitionPropertyName.get(), +structure->transitionPropertyAttributes()), structure);
 }
 
 void Structure::dumpStatistics()
@@ -185,7 +185,6 @@
     , m_prototype(vm, this, prototype)
     , m_classInfo(classInfo)
     , m_transitionWatchpointSet(IsWatched)
-    , m_offset(invalidOffset)
     , m_propertyHash(0)
 {
     setDictionaryKind(NoneDictionaryKind);
@@ -195,7 +194,7 @@
     setHasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties());
     setHasUnderscoreProtoPropertyExcludingOriginalProto(false);
     setIsQuickPropertyAccessAllowedForEnumeration(true);
-    setAttributesInPrevious(0);
+    setTransitionPropertyAttributes(0);
     setDidPreventExtensions(false);
     setDidTransition(false);
     setStaticPropertiesReified(false);
@@ -202,6 +201,8 @@
     setTransitionWatchpointIsLikelyToBeFired(false);
     setHasBeenDictionary(false);
     setIsAddingPropertyForTransition(false);
+    setTransitionOffset(vm, invalidOffset);
+    setMaxOffset(vm, invalidOffset);
  
     ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity());
     ASSERT(static_cast<PropertyOffset>(inlineCapacity) < firstOutOfLineOffset);
@@ -220,7 +221,6 @@
     , m_prototype(vm, this, jsNull())
     , m_classInfo(info())
     , m_transitionWatchpointSet(IsWatched)
-    , m_offset(invalidOffset)
     , m_propertyHash(0)
 {
     setDictionaryKind(NoneDictionaryKind);
@@ -230,7 +230,7 @@
     setHasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties());
     setHasUnderscoreProtoPropertyExcludingOriginalProto(false);
     setIsQuickPropertyAccessAllowedForEnumeration(true);
-    setAttributesInPrevious(0);
+    setTransitionPropertyAttributes(0);
     setDidPreventExtensions(false);
     setDidTransition(false);
     setStaticPropertiesReified(false);
@@ -237,6 +237,8 @@
     setTransitionWatchpointIsLikelyToBeFired(false);
     setHasBeenDictionary(false);
     setIsAddingPropertyForTransition(false);
+    setTransitionOffset(vm, invalidOffset);
+    setMaxOffset(vm, invalidOffset);
  
     TypeInfo typeInfo = TypeInfo(CellType, StructureFlags);
     m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), 0, typeInfo);
@@ -254,7 +256,6 @@
     , m_prototype(vm, this, previous->m_prototype.get())
     , m_classInfo(previous->m_classInfo)
     , m_transitionWatchpointSet(IsWatched)
-    , m_offset(invalidOffset)
     , m_propertyHash(previous->m_propertyHash)
     , m_seenProperties(previous->m_seenProperties)
 {
@@ -266,12 +267,14 @@
     setHasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->hasReadOnlyOrGetterSetterPropertiesExcludingProto());
     setHasUnderscoreProtoPropertyExcludingOriginalProto(previous->hasUnderscoreProtoPropertyExcludingOriginalProto());
     setIsQuickPropertyAccessAllowedForEnumeration(previous->isQuickPropertyAccessAllowedForEnumeration());
-    setAttributesInPrevious(0);
+    setTransitionPropertyAttributes(0);
     setDidPreventExtensions(previous->didPreventExtensions());
     setDidTransition(true);
     setStaticPropertiesReified(previous->staticPropertiesReified());
     setHasBeenDictionary(previous->hasBeenDictionary());
     setIsAddingPropertyForTransition(false);
+    setTransitionOffset(vm, invalidOffset);
+    setMaxOffset(vm, invalidOffset);
  
     TypeInfo typeInfo = previous->typeInfo();
     m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), previous->indexingModeIncludingHistory(), typeInfo);
@@ -311,12 +314,12 @@
     unsigned oldOutOfLineCapacity = result->outOfLineCapacity();
     result->addPropertyWithoutTransition(
         vm, vm.propertyNames->builtinNames().polyProtoName(), static_cast<unsigned>(PropertyAttribute::DontEnum),
-        [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newLastOffset) {
-            RELEASE_ASSERT(Structure::outOfLineCapacity(newLastOffset) == oldOutOfLineCapacity);
+        [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
+            RELEASE_ASSERT(Structure::outOfLineCapacity(newMaxOffset) == oldOutOfLineCapacity);
             RELEASE_ASSERT(offset == knownPolyProtoOffset);
             RELEASE_ASSERT(isInlineOffset(knownPolyProtoOffset));
             result->m_prototype.setWithoutWriteBarrier(JSValue());
-            result->setLastOffset(newLastOffset);
+            result->setMaxOffset(vm, newMaxOffset);
         });
 
     return result;
@@ -363,7 +366,7 @@
     
     findStructuresAndMapForMaterialization(structures, structure, table);
     
-    unsigned capacity = numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
+    unsigned capacity = numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity);
     if (table) {
         table = table->copy(vm, capacity);
         structure->m_lock.unlock();
@@ -379,10 +382,12 @@
 
     for (size_t i = structures.size(); i--;) {
         structure = structures[i];
-        if (!structure->m_nameInPrevious)
+        if (!structure->m_transitionPropertyName)
             continue;
-        PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious());
-        table->add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange);
+        ASSERT(i == structures.size() - 1 || structure->maxOffset() > structures[i + 1]->maxOffset());
+        PropertyMapEntry entry(structure->m_transitionPropertyName.get(), structure->transitionOffset(), structure->transitionPropertyAttributes());
+        auto maxOffset = this->maxOffset();
+        table->add(entry, maxOffset, PropertyTable::PropertyOffsetMustNotChange);
     }
     
     checkOffsetConsistency(
@@ -406,8 +411,8 @@
     ASSERT(structure->isObject());
 
     if (Structure* existingTransition = structure->m_transitionTable.get(uid, attributes)) {
-        validateOffset(existingTransition->m_offset, existingTransition->inlineCapacity());
-        offset = existingTransition->m_offset;
+        validateOffset(existingTransition->transitionOffset(), existingTransition->inlineCapacity());
+        offset = existingTransition->transitionOffset();
         return existingTransition;
     }
 
@@ -474,11 +479,12 @@
         maxTransitionLength = s_maxTransitionLengthForNonEvalPutById;
     else
         maxTransitionLength = s_maxTransitionLength;
-    if (structure->transitionCount() > maxTransitionLength) {
+    if (structure->transitionCountEstimate() > maxTransitionLength) {
         ASSERT(!isCopyOnWrite(structure->indexingMode()));
         Structure* transition = toCacheableDictionaryTransition(vm, structure, deferred);
         ASSERT(structure != transition);
         offset = transition->add(vm, propertyName, attributes);
+        transition->setTransitionOffset(vm, offset);
         return transition;
     }
     
@@ -487,7 +493,7 @@
     transition->m_cachedPrototypeChain.setMayBeNull(vm, transition, structure->m_cachedPrototypeChain.get());
     
     // While we are adding the property, rematerializing the property table is super weird: we already
-    // have a m_nameInPrevious and attributesInPrevious but the m_offset is still wrong. If the
+    // have a m_transitionPropertyName and transitionPropertyAttributes but the m_transitionOffset is still wrong. If the
     // materialization algorithm runs, it'll build a property table that already has the property but
     // at a bogus offset. Rather than try to teach the materialization code how to create a table under
     // those conditions, we just tell the GC not to blow the table away during this period of time.
@@ -501,12 +507,13 @@
     }
 
     transition->m_blob.setIndexingModeIncludingHistory(structure->indexingModeIncludingHistory() & ~CopyOnWrite);
-    transition->m_nameInPrevious = propertyName.uid();
-    transition->setAttributesInPrevious(attributes);
+    transition->m_transitionPropertyName = propertyName.uid();
+    transition->setTransitionPropertyAttributes(attributes);
     transition->setPropertyTable(vm, structure->takePropertyTableOrCloneIfPinned(vm));
-    transition->m_offset = structure->m_offset;
+    transition->setMaxOffset(vm, structure->maxOffset());
 
     offset = transition->add(vm, propertyName, attributes);
+    transition->setTransitionOffset(vm, offset);
 
     // Now that everything is fine with the new structure's bookkeeping, the GC is free to blow the
     // table away if it wants. We can now rebuild it fine.
@@ -513,7 +520,7 @@
     WTF::storeStoreFence();
     transition->setIsAddingPropertyForTransition(false);
 
-    checkOffset(transition->m_offset, transition->inlineCapacity());
+    checkOffset(transition->transitionOffset(), transition->inlineCapacity());
     {
         ConcurrentJSLocker locker(structure->m_lock);
         DeferGC deferGC(vm.heap);
@@ -559,7 +566,7 @@
 
     PropertyTable* table = structure->copyPropertyTableForPinning(vm);
     transition->pin(holdLock(transition->m_lock), vm, table);
-    transition->m_offset = structure->m_offset;
+    transition->setMaxOffset(vm, structure->maxOffset());
     
     transition->checkOffsetConsistency();
     return transition;
@@ -572,7 +579,7 @@
 
         PropertyTable* table = structure->copyPropertyTableForPinning(vm);
         transition->pin(holdLock(transition->m_lock), vm, table);
-        transition->m_offset = structure->m_offset;
+        transition->setMaxOffset(vm, structure->maxOffset());
         
         structure = transition;
     }
@@ -594,7 +601,7 @@
 
     PropertyTable* table = structure->copyPropertyTableForPinning(vm);
     transition->pin(holdLock(transition->m_lock), vm, table);
-    transition->m_offset = structure->m_offset;
+    transition->setMaxOffset(vm, structure->maxOffset());
     transition->setDictionaryKind(kind);
     transition->setHasBeenDictionary(true);
     
@@ -649,7 +656,7 @@
     
     Structure* existingTransition;
     if (!structure->isDictionary() && (existingTransition = structure->m_transitionTable.get(0, attributes))) {
-        ASSERT(existingTransition->attributesInPrevious() == attributes);
+        ASSERT(existingTransition->transitionPropertyAttributes() == attributes);
         ASSERT(existingTransition->indexingModeIncludingHistory() == indexingModeIncludingHistory);
         return existingTransition;
     }
@@ -657,7 +664,7 @@
     DeferGC deferGC(vm.heap);
     
     Structure* transition = create(vm, structure);
-    transition->setAttributesInPrevious(attributes);
+    transition->setTransitionPropertyAttributes(attributes);
     transition->m_blob.setIndexingModeIncludingHistory(indexingModeIncludingHistory);
     
     if (preventsExtensions(transitionKind))
@@ -671,7 +678,7 @@
 
         PropertyTable* table = structure->copyPropertyTableForPinning(vm);
         transition->pinForCaching(holdLock(transition->m_lock), vm, table);
-        transition->m_offset = structure->m_offset;
+        transition->setMaxOffset(vm, structure->maxOffset());
         
         table = transition->propertyTableOrNull();
         RELEASE_ASSERT(table);
@@ -683,8 +690,8 @@
         }
     } else {
         transition->setPropertyTable(vm, structure->takePropertyTableOrCloneIfPinned(vm));
-        transition->m_offset = structure->m_offset;
-        checkOffset(transition->m_offset, transition->inlineCapacity());
+        transition->setMaxOffset(vm, structure->maxOffset());
+        checkOffset(transition->maxOffset(), transition->inlineCapacity());
     }
     
     if (setsReadOnlyOnNonAccessorProperties(transitionKind)
@@ -764,11 +771,13 @@
         // Copies out our values from their hashed locations, compacting property table offsets as we go.
         unsigned i = 0;
         PropertyTable::iterator end = table->end();
-        m_offset = invalidOffset;
+        auto offset = invalidOffset;
         for (PropertyTable::iterator iter = table->begin(); iter != end; ++iter, ++i) {
             values[i] = object->getDirect(iter->offset);
-            m_offset = iter->offset = offsetForPropertyNumber(i, m_inlineCapacity);
+            offset = iter->offset = offsetForPropertyNumber(i, m_inlineCapacity);
         }
+        setMaxOffset(vm, offset);
+        ASSERT(transitionOffset() == invalidOffset);
         
         // Copies in our values to their compacted locations.
         for (unsigned i = 0; i < propertyCount; i++)
@@ -823,7 +832,7 @@
     setIsPinnedPropertyTable(true);
     setPropertyTable(vm, table);
     clearPreviousID();
-    m_nameInPrevious = nullptr;
+    m_transitionPropertyName = nullptr;
 }
 
 void Structure::pinForCaching(const AbstractLocker&, VM& vm, PropertyTable* table)
@@ -830,7 +839,7 @@
 {
     setIsPinnedPropertyTable(true);
     setPropertyTable(vm, table);
-    m_nameInPrevious = nullptr;
+    m_transitionPropertyName = nullptr;
 }
 
 void Structure::allocateRareData(VM& vm)
@@ -962,8 +971,8 @@
 {
     return add<ShouldPin::No>(
         vm, propertyName, attributes,
-        [this] (const GCSafeConcurrentJSLocker&, PropertyOffset, PropertyOffset newLastOffset) {
-            setLastOffset(newLastOffset);
+        [this, &vm] (const GCSafeConcurrentJSLocker&, PropertyOffset, PropertyOffset newMaxOffset) {
+            setMaxOffset(vm, newMaxOffset);
         });
 }
 

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/Structure.h (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/Structure.h	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/Structure.h	2020-02-04 03:09:25 UTC (rev 255646)
@@ -352,15 +352,53 @@
         return static_cast<Structure*>(cell);
     }
     bool transitivelyTransitionedFrom(Structure* structureToFind);
+
+    PropertyOffset maxOffset() const
+    {
+        if (m_maxOffset == shortInvalidOffset)
+            return invalidOffset;
+        if (m_maxOffset == useRareDataFlag)
+            return rareData()->m_maxOffset;
+        return m_maxOffset;
+    }
     
-    PropertyOffset lastOffset() const { return m_offset; }
-    
-    void setLastOffset(PropertyOffset offset) { m_offset = offset; }
+    void setMaxOffset(VM& vm, PropertyOffset offset)
+    {
+        if (offset == invalidOffset)
+            m_maxOffset = shortInvalidOffset;
+        else if (offset < useRareDataFlag && offset < shortInvalidOffset)
+            m_maxOffset = offset;
+        else {
+            m_maxOffset = useRareDataFlag;
+            ensureRareData(vm)->m_maxOffset = offset;
+        }
+    }
 
-    static unsigned outOfLineCapacity(PropertyOffset lastOffset)
+    PropertyOffset transitionOffset() const
     {
-        unsigned outOfLineSize = Structure::outOfLineSize(lastOffset);
+        if (m_transitionOffset == shortInvalidOffset)
+            return invalidOffset;
+        if (m_transitionOffset == useRareDataFlag)
+            return rareData()->m_transitionOffset;
+        return m_transitionOffset;
+    }
 
+    void setTransitionOffset(VM& vm, PropertyOffset offset)
+    {
+        if (offset == invalidOffset)
+            m_transitionOffset = shortInvalidOffset;
+        else if (offset < useRareDataFlag && offset < shortInvalidOffset)
+            m_transitionOffset = offset;
+        else {
+            m_transitionOffset = useRareDataFlag;
+            ensureRareData(vm)->m_transitionOffset = offset;
+        }
+    }
+
+    static unsigned outOfLineCapacity(PropertyOffset maxOffset)
+    {
+        unsigned outOfLineSize = Structure::outOfLineSize(maxOffset);
+
         // This algorithm completely determines the out-of-line property storage growth algorithm.
         // The JSObject code will only trigger a resize if the value returned by this algorithm
         // changed between the new and old structure. So, it's important to keep this simple because
@@ -377,18 +415,18 @@
         return WTF::roundUpToPowerOfTwo(outOfLineSize);
     }
     
-    static unsigned outOfLineSize(PropertyOffset lastOffset)
+    static unsigned outOfLineSize(PropertyOffset maxOffset)
     {
-        return numberOfOutOfLineSlotsForLastOffset(lastOffset);
+        return numberOfOutOfLineSlotsForMaxOffset(maxOffset);
     }
 
     unsigned outOfLineCapacity() const
     {
-        return outOfLineCapacity(m_offset);
+        return outOfLineCapacity(maxOffset());
     }
     unsigned outOfLineSize() const
     {
-        return outOfLineSize(m_offset);
+        return outOfLineSize(maxOffset());
     }
     bool hasInlineStorage() const
     {
@@ -400,11 +438,11 @@
     }
     unsigned inlineSize() const
     {
-        return std::min<unsigned>(m_offset + 1, m_inlineCapacity);
+        return std::min<unsigned>(maxOffset() + 1, m_inlineCapacity);
     }
     unsigned totalStorageSize() const
     {
-        return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
+        return numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity);
     }
     unsigned totalStorageCapacity() const
     {
@@ -415,7 +453,7 @@
     bool isValidOffset(PropertyOffset offset) const
     {
         return JSC::isValidOffset(offset)
-            && offset <= m_offset
+            && offset <= maxOffset()
             && (offset < m_inlineCapacity || offset >= firstOutOfLineOffset);
     }
 
@@ -467,12 +505,6 @@
         if (!is__proto__)
             setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
     }
-    
-    bool isEmpty() const
-    {
-        ASSERT(checkOffsetConsistency());
-        return !JSC::isValidOffset(m_offset);
-    }
 
     void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
     JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
@@ -650,7 +682,7 @@
     DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
     DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
     DEFINE_BITFIELD(bool, isQuickPropertyAccessAllowedForEnumeration, IsQuickPropertyAccessAllowedForEnumeration, 1, 5);
-    DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
+    DEFINE_BITFIELD(unsigned, transitionPropertyAttributes, TransitionPropertyAttributes, 14, 6);
     DEFINE_BITFIELD(bool, didPreventExtensions, DidPreventExtensions, 1, 20);
     DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
     DEFINE_BITFIELD(bool, staticPropertiesReified, StaticPropertiesReified, 1, 22);
@@ -732,10 +764,11 @@
             m_previousOrRareData.clear();
     }
 
-    int transitionCount() const
+    int transitionCountEstimate() const
     {
-        // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
-        return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
+        // Since the number of transitions is often the same as the last offset (except if there are deletes)
+        // we keep the size of Structure down by not storing both.
+        return numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity);
     }
 
     bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain, JSObject* base) const;
@@ -777,7 +810,7 @@
 
     WriteBarrier<JSCell> m_previousOrRareData;
 
-    RefPtr<UniquedStringImpl> m_nameInPrevious;
+    RefPtr<UniquedStringImpl> m_transitionPropertyName;
 
     const ClassInfo* m_classInfo;
 
@@ -791,9 +824,12 @@
 
     COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
 
-    // m_offset does not account for anonymous slots
-    PropertyOffset m_offset;
+    static constexpr uint16_t shortInvalidOffset = std::numeric_limits<uint16_t>::max();
+    static constexpr uint16_t useRareDataFlag = std::numeric_limits<uint16_t>::max() - 1;
 
+    uint16_t m_transitionOffset;
+    uint16_t m_maxOffset;
+
     uint32_t m_propertyHash;
     TinyBloomFilter m_seenProperties;
 

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureInlines.h (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureInlines.h	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureInlines.h	2020-02-04 03:09:25 UTC (rev 255646)
@@ -180,10 +180,10 @@
     
     for (unsigned i = structures.size(); i--;) {
         structure = structures[i];
-        if (!structure->m_nameInPrevious)
+        if (!structure->m_transitionPropertyName)
             continue;
         
-        if (!functor(PropertyMapEntry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious())))
+        if (!functor(PropertyMapEntry(structure->m_transitionPropertyName.get(), structure->transitionOffset(), structure->transitionPropertyAttributes())))
             return;
     }
 }
@@ -364,21 +364,22 @@
     auto fail = [&] (const char* description) {
         dataLog("Detected offset inconsistency: ", description, "!\n");
         dataLog("this = ", RawPointer(this), "\n");
-        dataLog("m_offset = ", m_offset, "\n");
+        dataLog("transitionOffset = ", transitionOffset(), "\n");
+        dataLog("maxOffset = ", maxOffset(), "\n");
         dataLog("m_inlineCapacity = ", m_inlineCapacity, "\n");
         dataLog("propertyTable = ", RawPointer(propertyTable), "\n");
-        dataLog("numberOfSlotsForLastOffset = ", numberOfSlotsForLastOffset(m_offset, m_inlineCapacity), "\n");
+        dataLog("numberOfSlotsForMaxOffset = ", numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity), "\n");
         dataLog("totalSize = ", totalSize, "\n");
         dataLog("inlineOverflowAccordingToTotalSize = ", inlineOverflowAccordingToTotalSize, "\n");
-        dataLog("numberOfOutOfLineSlotsForLastOffset = ", numberOfOutOfLineSlotsForLastOffset(m_offset), "\n");
+        dataLog("numberOfOutOfLineSlotsForMaxOffset = ", numberOfOutOfLineSlotsForMaxOffset(maxOffset()), "\n");
         detailsFunc();
         UNREACHABLE_FOR_PLATFORM();
     };
     
-    if (numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) != totalSize)
-        fail("numberOfSlotsForLastOffset doesn't match totalSize");
-    if (inlineOverflowAccordingToTotalSize != numberOfOutOfLineSlotsForLastOffset(m_offset))
-        fail("inlineOverflowAccordingToTotalSize doesn't match numberOfOutOfLineSlotsForLastOffset");
+    if (numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity) != totalSize)
+        fail("numberOfSlotsForMaxOffset doesn't match totalSize");
+    if (inlineOverflowAccordingToTotalSize != numberOfOutOfLineSlotsForMaxOffset(maxOffset()))
+        fail("inlineOverflowAccordingToTotalSize doesn't match numberOfOutOfLineSlotsForMaxOffset");
 
     return true;
 }
@@ -453,12 +454,12 @@
 
     m_seenProperties.add(bitwise_cast<uintptr_t>(rep));
     
-    PropertyOffset newLastOffset = m_offset;
-    table->add(PropertyMapEntry(rep, newOffset, attributes), newLastOffset, PropertyTable::PropertyOffsetMayChange);
+    PropertyOffset newMaxOffset = maxOffset();
+    table->add(PropertyMapEntry(rep, newOffset, attributes), newMaxOffset, PropertyTable::PropertyOffsetMayChange);
     
-    func(locker, newOffset, newLastOffset);
+    func(locker, newOffset, newMaxOffset);
     
-    ASSERT(m_offset == newLastOffset);
+    ASSERT(maxOffset() == newMaxOffset);
 
     checkConsistency();
     return newOffset;

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureRareData.cpp (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureRareData.cpp	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureRareData.cpp	2020-02-04 03:09:25 UTC (rev 255646)
@@ -58,6 +58,8 @@
 StructureRareData::StructureRareData(VM& vm, Structure* previous)
     : JSCell(vm, vm.structureRareDataStructure.get())
     , m_giveUpOnObjectToStringValueCache(false)
+    , m_maxOffset(invalidOffset)
+    , m_transitionOffset(invalidOffset)
 {
     if (previous)
         m_previous.set(vm, this, previous);

Modified: branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureRareData.h (255645 => 255646)


--- branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureRareData.h	2020-02-04 03:09:21 UTC (rev 255645)
+++ branches/safari-610.1.1-branch/Source/_javascript_Core/runtime/StructureRareData.h	2020-02-04 03:09:25 UTC (rev 255646)
@@ -114,6 +114,9 @@
     std::unique_ptr<ObjectToStringAdaptiveInferredPropertyValueWatchpoint> m_objectToStringAdaptiveInferredValueWatchpoint;
     Box<InlineWatchpointSet> m_polyProtoWatchpoint;
     bool m_giveUpOnObjectToStringValueCache;
+
+    PropertyOffset m_maxOffset;
+    PropertyOffset m_transitionOffset;
 };
 
 } // namespace JSC
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to