Bug 649145 - Store properties on nsCSSCompressedDataBlocks in declaration order. r=dbaron
authorCameron McCormack <cam@mcc.id.au>
Fri, 19 Dec 2014 14:32:34 +1100
changeset 220562 adfa2efc886e612131e8a60c1273380c4a8c44a3
parent 220561 9bc70d029f38d732676eb3477b6ad9939c22ea1f
child 220563 13b2284f09c9eaeaf794b751c78bf92321f28386
push id10503
push userryanvm@gmail.com
push dateFri, 19 Dec 2014 20:13:42 +0000
treeherderfx-team@98ee95ac6be5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs649145
milestone37.0a1
Bug 649145 - Store properties on nsCSSCompressedDataBlocks in declaration order. r=dbaron
layout/style/Declaration.h
layout/style/nsCSSDataBlock.cpp
layout/style/nsCSSDataBlock.h
--- a/layout/style/Declaration.h
+++ b/layout/style/Declaration.h
@@ -141,17 +141,18 @@ public:
    * Transfer all of the state from |aExpandedData| into this declaration.
    * After calling, |aExpandedData| should be in its initial state.
    * Callers must make sure mOrder is updated as necessary.
    */
   void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
     NS_ABORT_IF_FALSE(!mData, "oops");
     NS_ABORT_IF_FALSE(!mImportantData, "oops");
     aExpandedData->Compress(getter_Transfers(mData),
-                            getter_Transfers(mImportantData));
+                            getter_Transfers(mImportantData),
+                            mOrder);
     aExpandedData->AssertInitialState();
   }
 
   /**
    * Transfer all of the state from this declaration into
    * |aExpandedData| and put this declaration temporarily into an
    * invalid state (ended by |CompressFrom| or |InitializeEmpty|) that
    * should last only during parsing.  During this time only
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -390,17 +390,18 @@ nsCSSExpandedDataBlock::ComputeNumProps(
             else
                 (*aNumPropsNormal)++;
         }
     }
 }
 
 void
 nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock,
-                                 nsCSSCompressedDataBlock **aImportantBlock)
+                                 nsCSSCompressedDataBlock **aImportantBlock,
+                                 const nsTArray<uint32_t>& aOrder)
 {
     nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important;
     uint32_t i_normal = 0, i_important = 0;
 
     uint32_t numPropsNormal, numPropsImportant;
     ComputeNumProps(&numPropsNormal, &numPropsImportant);
 
     result_normal =
@@ -413,47 +414,68 @@ nsCSSExpandedDataBlock::Compress(nsCSSCo
         result_important = nullptr;
     }
 
     /*
      * Save needless copying and allocation by copying the memory
      * corresponding to the stored data in the expanded block, and then
      * clearing the data in the expanded block.
      */
-    for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; ++iHigh) {
-        if (!mPropertiesSet.HasPropertyInChunk(iHigh))
+    for (size_t i = 0; i < aOrder.Length(); i++) {
+        nsCSSProperty iProp = static_cast<nsCSSProperty>(aOrder[i]);
+        if (iProp >= eCSSProperty_COUNT) {
+            // a custom property
             continue;
-        for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; ++iLow) {
-            if (!mPropertiesSet.HasPropertyAt(iHigh, iLow))
-                continue;
-            nsCSSProperty iProp = nsCSSPropertySet::CSSPropertyAt(iHigh, iLow);
-            NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
-            bool important =
-                mPropertiesImportant.HasPropertyAt(iHigh, iLow);
-            nsCSSCompressedDataBlock *result =
-                important ? result_important : result_normal;
-            uint32_t* ip = important ? &i_important : &i_normal;
-            nsCSSValue* val = PropertyAt(iProp);
-            NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null,
-                              "Null value while compressing");
-            result->SetPropertyAtIndex(*ip, iProp);
-            result->RawCopyValueToIndex(*ip, val);
-            new (val) nsCSSValue();
-            (*ip)++;
-            result->mStyleBits |=
-                nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]);
         }
+        NS_ABORT_IF_FALSE(mPropertiesSet.HasProperty(iProp),
+                          "aOrder identifies a property not in the expanded "
+                          "data block");
+        NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(iProp), "out of range");
+        bool important = mPropertiesImportant.HasProperty(iProp);
+        nsCSSCompressedDataBlock *result =
+            important ? result_important : result_normal;
+        uint32_t* ip = important ? &i_important : &i_normal;
+        nsCSSValue* val = PropertyAt(iProp);
+        NS_ABORT_IF_FALSE(val->GetUnit() != eCSSUnit_Null,
+                          "Null value while compressing");
+        result->SetPropertyAtIndex(*ip, iProp);
+        result->RawCopyValueToIndex(*ip, val);
+        new (val) nsCSSValue();
+        (*ip)++;
+        result->mStyleBits |=
+            nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]);
     }
 
     NS_ABORT_IF_FALSE(numPropsNormal == i_normal, "bad numProps");
 
     if (result_important) {
         NS_ABORT_IF_FALSE(numPropsImportant == i_important, "bad numProps");
     }
 
+#ifdef DEBUG
+    {
+      // assert that we didn't have any other properties on this expanded data
+      // block that we didn't find in aOrder
+      uint32_t numPropsInSet = 0;
+      for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; iHigh++) {
+          if (!mPropertiesSet.HasPropertyInChunk(iHigh)) {
+              continue;
+          }
+          for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; iLow++) {
+              if (mPropertiesSet.HasPropertyAt(iHigh, iLow)) {
+                  numPropsInSet++;
+              }
+          }
+      }
+      NS_ABORT_IF_FALSE(numPropsNormal + numPropsImportant == numPropsInSet,
+                        "aOrder missing properties from the expanded data "
+                        "block");
+    }
+#endif
+
     ClearSets();
     AssertInitialState();
     *aNormalBlock = result_normal.forget();
     *aImportantBlock = result_important.forget();
 }
 
 void
 nsCSSExpandedDataBlock::AddLonghandProperty(nsCSSProperty aProperty,
--- a/layout/style/nsCSSDataBlock.h
+++ b/layout/style/nsCSSDataBlock.h
@@ -202,19 +202,23 @@ public:
 
     /**
      * Allocate new compressed blocks and transfer all of the state
      * from this expanded block to the new blocks, clearing this
      * expanded block.  A normal block will always be allocated, but
      * an important block will only be allocated if there are
      * !important properties in the expanded block; otherwise
      * |*aImportantBlock| will be set to null.
+     *
+     * aOrder is an array of nsCSSProperty values specifying the order
+     * to store values in the two data blocks.
      */
     void Compress(nsCSSCompressedDataBlock **aNormalBlock,
-                  nsCSSCompressedDataBlock **aImportantBlock);
+                  nsCSSCompressedDataBlock **aImportantBlock,
+                  const nsTArray<uint32_t>& aOrder);
 
     /**
      * Copy a value into this expanded block.  This does NOT destroy
      * the source value object.  |aProperty| cannot be a shorthand.
      */
     void AddLonghandProperty(nsCSSProperty aProperty, const nsCSSValue& aValue);
 
     /**