Bug 1253137 - Baldr: update section header structure to match BinaryEncoding.md, part 2 (r=sunfish)
authorLuke Wagner <luke@mozilla.com>
Wed, 02 Mar 2016 21:48:05 -0600
changeset 286631 6257b3a68cfdc254619da53f56cbb8249b2b9bcf
parent 286630 56a5e1a497815ea0248d032fb388acdf8444ab43
child 286632 029e7b380dacbe4b5488719a7f89f12678184495
push id72848
push userlwagner@mozilla.com
push dateThu, 03 Mar 2016 16:07:52 +0000
treeherdermozilla-inbound@029e7b380dac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1253137
milestone47.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 1253137 - Baldr: update section header structure to match BinaryEncoding.md, part 2 (r=sunfish) MozReview-Commit-ID: 5taHsbHpcSz
js/src/asmjs/WasmBinary.h
js/src/jit-test/tests/wasm/binary.js
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -449,24 +449,29 @@ class Encoder
 
     MOZ_WARN_UNUSED_RESULT bool writeCString(const char* cstr) {
         return bytecode_.append(reinterpret_cast<const uint8_t*>(cstr), strlen(cstr) + 1);
     }
     MOZ_WARN_UNUSED_RESULT bool writeRawData(const uint8_t* bytes, uint32_t numBytes) {
         return bytecode_.append(bytes, numBytes);
     }
 
-    // A "section" is a contiguous region of bytes that stores its own size so
+    // A "section" is a contiguous range of bytes that stores its own size so
     // that it may be trivially skipped without examining the contents. Sections
     // require backpatching since the size of the section is only known at the
-    // end while the size's uint32 must be stored at the beginning.
+    // end while the size's uint32 must be stored at the beginning. Immediately
+    // after the section length is the string id of the section.
 
-    MOZ_WARN_UNUSED_RESULT bool startSection(const char* name, size_t* offset) {
+    template <size_t IdSizeWith0>
+    MOZ_WARN_UNUSED_RESULT bool startSection(const char (&id)[IdSizeWith0], size_t* offset) {
+        static const size_t IdSize = IdSizeWith0 - 1;
+        MOZ_ASSERT(id[IdSize] == '\0');
         return writePatchableVarU32(offset) &&
-               writeCString(name);
+               writeVarU32(IdSize) &&
+               writeRawData(reinterpret_cast<const uint8_t*>(id), IdSize);
     }
     void finishSection(size_t offset) {
         return patchVarU32(offset, bytecode_.length() - offset - varU32ByteLength(offset));
     }
 
     // Patching is necessary due to the combination of a preorder encoding and a
     // single-pass algorithm that only knows the precise opcode after visiting
     // children. Switching to a postorder encoding will remove these methods:
@@ -682,42 +687,54 @@ class Decoder
         cur_ += numBytes;
         return true;
     }
 
     // See "section" description in Encoder.
 
     static const uint32_t NotStarted = UINT32_MAX;
 
-    MOZ_WARN_UNUSED_RESULT bool startSection(const char* name, uint32_t* startOffset) {
+    template <size_t IdSizeWith0>
+    MOZ_WARN_UNUSED_RESULT bool startSection(const char (&id)[IdSizeWith0], uint32_t* startOffset) {
+        static const size_t IdSize = IdSizeWith0 - 1;
+        MOZ_ASSERT(id[IdSize] == '\0');
         const uint8_t* before = cur_;
-        uint32_t numBytes;
-        if (!readVarU32(&numBytes) || bytesRemain() < numBytes)
+        uint32_t size;
+        if (!readVarU32(&size))
+            goto backup;
+        if (bytesRemain() < size)
             return false;
-        if (!readCStringIf(name)) {
-            cur_ = before;
-            *startOffset = NotStarted;
-            return true;
-        }
+        uint32_t idSize;
+        if (!readVarU32(&idSize))
+            goto backup;
+        if (bytesRemain() < idSize)
+            return false;
+        if (idSize != IdSize || !!memcmp(cur_, id, IdSize))
+            goto backup;
+        cur_ += IdSize;
         *startOffset = before - beg_;
         return  true;
+      backup:
+        cur_ = before;
+        *startOffset = NotStarted;
+        return true;
     }
     MOZ_WARN_UNUSED_RESULT bool finishSection(uint32_t startOffset) {
         uint32_t currentOffset = cur_ - beg_;
         cur_ = beg_ + startOffset;
-        uint32_t numBytes = uncheckedReadVarU32();
-        uint32_t afterNumBytes = cur_ - beg_;
+        uint32_t size = uncheckedReadVarU32();
+        uint32_t afterSize = cur_ - beg_;
         cur_ = beg_ + currentOffset;
-        return numBytes == (currentOffset - afterNumBytes);
+        return size == (currentOffset - afterSize);
     }
     MOZ_WARN_UNUSED_RESULT bool skipSection() {
-        uint32_t numBytes;
-        if (!readVarU32(&numBytes) || bytesRemain() < numBytes)
+        uint32_t size;
+        if (!readVarU32(&size) || bytesRemain() < size)
             return false;
-        cur_ += numBytes;
+        cur_ += size;
         return true;
     }
 
     // The infallible "unchecked" decoding functions can be used when we are
     // sure that the bytecode is well-formed (by construction or due to previous
     // validation).
 
     uint32_t uncheckedReadFixedU32() {
--- a/js/src/jit-test/tests/wasm/binary.js
+++ b/js/src/jit-test/tests/wasm/binary.js
@@ -61,27 +61,34 @@ assertErrorMessage(() => wasmEval(toBuf(
 assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, 1])), TypeError, versionError);
 assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, ver0])), TypeError, versionError);
 assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, ver0, ver1, ver2])), TypeError, versionError);
 
 var o = wasmEval(toBuf(moduleHeaderThen(0)));
 assertEq(Object.getOwnPropertyNames(o).length, 0);
 
 assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(1))), TypeError, sectionError);
-assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 1))), TypeError, extraError);
+assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 0))), TypeError, extraError);
+assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 1))), TypeError, sectionError);
 
 function cstring(name) {
     return (name + '\0').split('').map(c => c.charCodeAt(0));
 }
 
+function string(name) {
+    return name.split('').map(c => c.charCodeAt(0));
+}
+
 function moduleWithSections(sectionArray) {
     var bytes = moduleHeaderThen();
     for (let section of sectionArray) {
-        bytes.push(...varU32(section.name.length + 1 + section.body.length));
-        bytes.push(...cstring(section.name));
+        var nameLength = varU32(section.name.length);
+        bytes.push(...varU32(nameLength.length + section.name.length + section.body.length));
+        bytes.push(...nameLength);
+        bytes.push(...string(section.name));
         bytes.push(...section.body);
     }
     bytes.push(0);
     return bytes;
 }
 
 function sigSection(sigs) {
     var body = [];