Bug 1456609 - Expose a method readSkippableSubTree for BinTokenReader{Tester, Multipart} r=arai
authorDavid Teller <dteller@mozilla.com>
Tue, 24 Apr 2018 22:29:19 +0200
changeset 470460 b917e7e80a51f27410b9fde249c72ae49803a163
parent 470442 32192f022b8455c322d592e9785359a7c9496c6a
child 470461 5630f78d35cf0e4f7410ba08588ed055bdcc60bb
push id9182
push usernerli@mozilla.com
push dateFri, 04 May 2018 15:39:56 +0000
treeherdermozilla-beta@01ab1ea4c55a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1456609
milestone61.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 1456609 - Expose a method readSkippableSubTree for BinTokenReader{Tester, Multipart} r=arai MozReview-Commit-ID: 2jceBpJOOoS
js/src/frontend/BinTokenReaderBase.h
js/src/frontend/BinTokenReaderMultipart.cpp
js/src/frontend/BinTokenReaderMultipart.h
js/src/frontend/BinTokenReaderTester.cpp
js/src/frontend/BinTokenReaderTester.h
js/src/frontend/binsource/src/main.rs
--- a/js/src/frontend/BinTokenReaderBase.h
+++ b/js/src/frontend/BinTokenReaderBase.h
@@ -24,16 +24,40 @@ using namespace JS;
 // A constant used by tokenizers to represent a null float.
 extern const uint64_t NULL_FLOAT_REPRESENTATION;
 
 class MOZ_STACK_CLASS BinTokenReaderBase
 {
   public:
     template<typename T> using ErrorResult = mozilla::GenericErrorResult<T>;
 
+    // The information needed to skip a subtree.
+    class SkippableSubTree {
+      public:
+        SkippableSubTree(const uint8_t* start, const size_t length)
+          : start_(start)
+          , length_(length)
+        { }
+
+        // The position in the source buffer at which the subtree starts.
+        //
+        // `SkippableSubTree` does *not* attempt to keep anything alive.
+        const uint8_t* start() const {
+            return start_;
+        }
+
+        // The length of the subtree.
+        size_t length() const {
+            return length_;
+        }
+      private:
+        const uint8_t* start_;
+        const size_t length_;
+    };
+
     /**
      * Return the position of the latest token.
      */
     TokenPos pos();
     TokenPos pos(size_t startOffset);
     size_t offset() const;
 
      /**
--- a/js/src/frontend/BinTokenReaderMultipart.cpp
+++ b/js/src/frontend/BinTokenReaderMultipart.cpp
@@ -269,16 +269,32 @@ BinTokenReaderMultipart::readVariant()
         return raiseError("Invalid string enum variant");
 
     if (!variantsTable_.add(variantsPtr, index, *variant))
         return raiseOOM();
 
     return *variant;
 }
 
+JS::Result<BinTokenReaderBase::SkippableSubTree>
+BinTokenReaderMultipart::readSkippableSubTree()
+{
+    updateLatestKnownGood();
+    BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
+
+    if (current_ + byteLen > stop_ || current_ + byteLen < current_)
+        return raiseError("Invalid byte length in readSkippableSubTree");
+
+    const auto start = current_;
+
+    current_ += byteLen;
+
+    return BinTokenReaderBase::SkippableSubTree(start, byteLen);
+}
+
 // Untagged tuple:
 // - contents (specified by the higher-level grammar);
 JS::Result<Ok>
 BinTokenReaderMultipart::enterUntaggedTuple(AutoTuple& guard)
 {
     guard.init();
     return Ok();
 }
--- a/js/src/frontend/BinTokenReaderMultipart.h
+++ b/js/src/frontend/BinTokenReaderMultipart.h
@@ -112,16 +112,25 @@ class MOZ_STACK_CLASS BinTokenReaderMult
     MOZ_MUST_USE JS::Result<Ok> readChars(Chars&);
 
     /**
      * Read a single `BinVariant | null` value.
      */
     MOZ_MUST_USE JS::Result<Maybe<BinVariant>> readMaybeVariant();
     MOZ_MUST_USE JS::Result<BinVariant> readVariant();
 
+    /**
+     * Read over a single `[Skippable]` subtree value.
+     *
+     * This does *not* attempt to parse the subtree itself. Rather, the
+     * returned `SkippableSubTree` contains the necessary information
+     * to parse/tokenize the subtree at a later stage
+     */
+    MOZ_MUST_USE JS::Result<SkippableSubTree> readSkippableSubTree();
+
     // --- Composite values.
     //
     // The underlying format does NOT allows for a `null` composite value.
     //
     // Reading will return an error either in case of I/O error or in case of
     // a format problem. Reading from a poisoned tokenizer is an error and
     // will cause assertion failures.
 
--- a/js/src/frontend/BinTokenReaderTester.cpp
+++ b/js/src/frontend/BinTokenReaderTester.cpp
@@ -213,16 +213,32 @@ BinTokenReaderTester::readVariant()
     BINJS_MOZ_TRY_DECL(variant, cx_->runtime()->binast().binVariant(cx_, slice));
     if (!variant)
         return raiseError("Not a variant");
 
     MOZ_TRY(readConst("</string>"));
     return *variant;
 }
 
+JS::Result<BinTokenReaderBase::SkippableSubTree>
+BinTokenReaderTester::readSkippableSubTree()
+{
+    updateLatestKnownGood();
+    BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
+
+    if (current_ + byteLen > stop_ || current_ + byteLen < current_)
+        return raiseError("Invalid byte length in readSkippableSubTree");
+
+    const auto start = current_;
+
+    current_ += byteLen;
+
+    return BinTokenReaderBase::SkippableSubTree(start, byteLen);
+}
+
 // Untagged tuple:
 // - "<tuple>";
 // - contents (specified by the higher-level grammar);
 // - "</tuple>"
 JS::Result<Ok>
 BinTokenReaderTester::enterUntaggedTuple(AutoTuple& guard)
 {
     MOZ_TRY(readConst("<tuple>"));
--- a/js/src/frontend/BinTokenReaderTester.h
+++ b/js/src/frontend/BinTokenReaderTester.h
@@ -133,16 +133,25 @@ class MOZ_STACK_CLASS BinTokenReaderTest
     MOZ_MUST_USE JS::Result<Ok> readChars(Chars&);
 
     /**
      * Read a single `BinVariant | null` value.
      */
     MOZ_MUST_USE JS::Result<Maybe<BinVariant>> readMaybeVariant();
     MOZ_MUST_USE JS::Result<BinVariant> readVariant();
 
+    /**
+     * Read over a single `[Skippable]` subtree value.
+     *
+     * This does *not* attempt to parse the subtree itself. Rather, the
+     * returned `SkippableSubTree` contains the necessary information
+     * to parse/tokenize the subtree at a later stage
+     */
+    MOZ_MUST_USE JS::Result<SkippableSubTree> readSkippableSubTree();
+
     // --- Composite values.
     //
     // The underlying format does NOT allows for a `null` composite value.
     //
     // Reading will return an error either in case of I/O error or in case of
     // a format problem. Reading from a poisoned tokenizer is an error and
     // will cause assertion failures.
 
--- a/js/src/frontend/binsource/src/main.rs
+++ b/js/src/frontend/binsource/src/main.rs
@@ -1043,21 +1043,21 @@ impl CPPExporter {
                         Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readBool());", var_name = var_name)))
                     } else {
                         (None,
                         Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readBool());", var_name = var_name)))
                     }
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::Offset }) => {
                     if needs_block {
-                        (Some(format!("uint32_t {var_name};", var_name = var_name)),
-                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readOffset());", var_name = var_name)))
+                        (Some(format!("BinTokenReaderBase::SkippableSubTree {var_name};", var_name = var_name)),
+                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readSkippableSubTree());", var_name = var_name)))
                     } else {
                         (None,
-                        Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readOffset());", var_name = var_name)))
+                        Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readSkippableSubTree());", var_name = var_name)))
                     }
                 }
                 Some(IsNullable { content: Primitive::Void, .. }) => {
                     warn!("Internal error: We shouldn't have any `void` types at this stage.");
                     (Some(format!("// Skipping void field {}", field.name().to_str())),
                         None)
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::String }) => {