Bug 1503961 - part 1 - factor out a slice iterator for XDRIncrementalEncoder; r=nbp
authorNathan Froyd <froydnj@mozilla.com>
Mon, 19 Nov 2018 11:21:09 -0500
changeset 503520 9718b942ff558203eaea91981084e9329fbf52a7
parent 503519 b1c306693151539e0772bf462cea6ac9f22194d2
child 503521 f949c4870f0267c86506199a8bbcedda82129c54
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1503961
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1503961 - part 1 - factor out a slice iterator for XDRIncrementalEncoder; r=nbp We're going to do two passes over the tree, so we might as well have some common code to do the iteration.
js/src/vm/Xdr.cpp
js/src/vm/Xdr.h
--- a/js/src/vm/Xdr.cpp
+++ b/js/src/vm/Xdr.cpp
@@ -254,16 +254,82 @@ AutoXDRTree::~AutoXDRTree()
         xdr_->endSubTree();
     }
 }
 
 constexpr AutoXDRTree::Key AutoXDRTree::noKey;
 constexpr AutoXDRTree::Key AutoXDRTree::noSubTree;
 constexpr AutoXDRTree::Key AutoXDRTree::topLevel;
 
+class XDRIncrementalEncoder::DepthFirstSliceIterator {
+public:
+    DepthFirstSliceIterator(JSContext* cx, const SlicesTree& tree)
+        : stack_(cx)
+        , tree_(tree)
+    {
+    }
+
+    template<typename SliceFun>
+    bool iterate(SliceFun&& f) {
+        MOZ_ASSERT(stack_.empty());
+
+        if (!appendChildrenForKey(AutoXDRTree::topLevel)) {
+            return false;
+        }
+
+        while (!done()) {
+            SlicesNode::ConstRange& iter = next();
+            Slice slice = iter.popCopyFront();
+            // These fields have different meaning, but they should be
+            // correlated if the tree is well formatted.
+            MOZ_ASSERT_IF(slice.child == AutoXDRTree::noSubTree, iter.empty());
+            if (iter.empty()) {
+                pop();
+            }
+
+            if (!f(slice)) {
+                return false;
+            }
+
+            // If we are at the end, go back to the parent script.
+            if (slice.child == AutoXDRTree::noSubTree) {
+                continue;
+            }
+
+            if (!appendChildrenForKey(slice.child)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+private:
+    bool done() const {
+        return stack_.empty();
+    }
+    SlicesNode::ConstRange& next() {
+        return stack_.back();
+    }
+    void pop() {
+        stack_.popBack();
+    }
+
+    MOZ_MUST_USE bool appendChildrenForKey(AutoXDRTree::Key key) {
+        MOZ_ASSERT(key != AutoXDRTree::noSubTree);
+
+        SlicesTree::Ptr p = tree_.lookup(key);
+        MOZ_ASSERT(p);
+        return stack_.append(((const SlicesNode&) p->value()).all());
+    }
+
+    Vector<SlicesNode::ConstRange> stack_;
+    const SlicesTree& tree_;
+};
+
 AutoXDRTree::Key
 XDRIncrementalEncoder::getTopLevelTreeKey() const
 {
     return AutoXDRTree::topLevel;
 }
 
 AutoXDRTree::Key
 XDRIncrementalEncoder::getTreeKey(JSFunction* fun) const
@@ -381,58 +447,31 @@ XDRIncrementalEncoder::linearize(JS::Tra
     if (buffer.length() % alignLen) {
         alignLen = ComputeByteAlignment(buffer.length(), alignLen);
         if (!buffer.appendN(0, alignLen)) {
             ReportOutOfMemory(cx());
             return fail(JS::TranscodeResult_Throw);
         }
     }
 
-    // Visit the tree parts in a depth first order, to linearize the bits.
-    Vector<SlicesNode::ConstRange> depthFirst(cx());
-
-    SlicesTree::Ptr p = tree_.lookup(AutoXDRTree::topLevel);
-    MOZ_ASSERT(p);
-
-    if (!depthFirst.append(((const SlicesNode&) p->value()).all())) {
-        ReportOutOfMemory(cx());
-        return fail(JS::TranscodeResult_Throw);
-    }
+    // Visit the tree parts in a depth first order to linearize the bits.
+    DepthFirstSliceIterator dfs(cx(), tree_);
 
-    while (!depthFirst.empty()) {
-        SlicesNode::ConstRange& iter = depthFirst.back();
-        Slice slice = iter.popCopyFront();
-        // These fields have different meaning, but they should be correlated if
-        // the tree is well formatted.
-        MOZ_ASSERT_IF(slice.child == AutoXDRTree::noSubTree, iter.empty());
-        if (iter.empty()) {
-            depthFirst.popBack();
-        }
-
+    auto sliceCopier = [&](const Slice& slice) -> bool {
         // Copy the bytes associated with the current slice to the transcode
         // buffer which would be serialized.
         MOZ_ASSERT(slice.sliceBegin <= slices_.length());
         MOZ_ASSERT(slice.sliceBegin + slice.sliceLength <= slices_.length());
         MOZ_ASSERT(buffer.length() % sizeof(XDRAlignment) == 0);
         MOZ_ASSERT(slice.sliceLength % sizeof(XDRAlignment) == 0);
-        if (!buffer.append(slices_.begin() + slice.sliceBegin, slice.sliceLength)) {
-            ReportOutOfMemory(cx());
-            return fail(JS::TranscodeResult_Throw);
-        }
+
+        return buffer.append(slices_.begin() + slice.sliceBegin, slice.sliceLength);
+    };
 
-        // If we are at the end, go to back to the parent script.
-        if (slice.child == AutoXDRTree::noSubTree) {
-            continue;
-        }
-
-        // Visit the sub-parts before visiting the rest of the current slice.
-        SlicesTree::Ptr p = tree_.lookup(slice.child);
-        MOZ_ASSERT(p);
-        if (!depthFirst.append(((const SlicesNode&) p->value()).all())) {
-            ReportOutOfMemory(cx());
-            return fail(JS::TranscodeResult_Throw);
-        }
+    if (!dfs.iterate(sliceCopier)) {
+        ReportOutOfMemory(cx());
+        return fail(JS::TranscodeResult_Throw);
     }
 
     tree_.clearAndCompact();
     slices_.clearAndFree();
     return Ok();
 }
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -600,16 +600,18 @@ class XDRIncrementalEncoder : public XDR
     AutoXDRTree* scope_;
     // Node corresponding to the opened scope.
     SlicesNode* node_;
     // Tree of slices.
     SlicesTree tree_;
     JS::TranscodeBuffer slices_;
     bool oom_;
 
+    class DepthFirstSliceIterator;
+
   public:
     explicit XDRIncrementalEncoder(JSContext* cx)
       : XDREncoder(cx, slices_, 0),
         scope_(nullptr),
         node_(nullptr),
         oom_(false)
     {
     }