Bug 1253137 - Baldr: update memory exports to match BinaryEncoding.md (r=sunfish)
authorLuke Wagner <luke@mozilla.com>
Fri, 04 Mar 2016 11:03:21 -0600
changeset 323135 374edef94056db96e54aef951ce678055c8acf83
parent 323134 310ca84e24faff0c25188c65b35c67bb255a69ab
child 323136 6bd419f5a9d04670b250e69e96049e38e7e181f1
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [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 memory exports to match BinaryEncoding.md (r=sunfish) MozReview-Commit-ID: 1khJ98KmHAe
js/src/asmjs/Wasm.cpp
js/src/asmjs/WasmText.cpp
js/src/jit-test/tests/wasm/basic.js
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -959,16 +959,26 @@ DecodeMemorySection(JSContext* cx, Decod
     if (!d.readVarU32(&maxSizePages))
         return Fail(cx, d, "expected initial memory size");
 
     CheckedInt<int32_t> maxSize = maxSizePages;
     maxSize *= PageSize;
     if (!maxSize.isValid())
         return Fail(cx, d, "initial memory size too big");
 
+    uint8_t exported;
+    if (!d.readFixedU8(&exported))
+        return Fail(cx, d, "expected exported byte");
+
+    if (exported) {
+        UniqueChars fieldName = DuplicateString("memory");
+        if (!fieldName || !mg.addMemoryExport(Move(fieldName)))
+            return false;
+    }
+
     if (!d.finishSection(sectionStart))
         return Fail(cx, d, "memory section byte size mismatch");
 
     bool signalsForOOB = CompileArgs(cx).useSignalHandlersForOOB;
     heap.set(ArrayBufferObject::createForWasm(cx, initialSize.value(), signalsForOOB));
     if (!heap)
         return false;
 
@@ -1015,54 +1025,38 @@ DecodeFunctionExport(JSContext* cx, Deco
     UniqueChars fieldName = DecodeFieldName(cx, d, dupSet);
     if (!fieldName)
         return false;
 
     return mg.declareExport(Move(fieldName), funcIndex);
 }
 
 static bool
-DecodeMemoryExport(JSContext* cx, Decoder& d, ModuleGenerator& mg, CStringSet* dupSet)
-{
-    if (!mg.usesHeap())
-        return Fail(cx, d, "cannot export memory with no memory section");
-
-    UniqueChars fieldName = DecodeFieldName(cx, d, dupSet);
-    if (!fieldName)
-        return false;
-
-    return mg.addMemoryExport(Move(fieldName));
-}
-
-static bool
 DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg)
 {
     uint32_t sectionStart;
     if (!d.startSection(ExportLabel, &sectionStart))
         return Fail(cx, d, "failed to start section");
     if (sectionStart == Decoder::NotStarted)
         return true;
 
     CStringSet dupSet(cx);
     if (!dupSet.init())
         return false;
 
-    for (uint32_t i = 0; !d.readCStringIf(EndLabel); i++) {
-        if (i >= MaxExports)
-            return Fail(cx, d, "too many exports");
+    uint32_t numExports;
+    if (!d.readVarU32(&numExports))
+        return false;
 
-        if (d.readCStringIf(FuncLabel)) {
-            if (!DecodeFunctionExport(cx, d, mg, &dupSet))
-                return false;
-        } else if (d.readCStringIf(MemoryLabel)) {
-            if (!DecodeMemoryExport(cx, d, mg, &dupSet))
-                return false;
-        } else {
-            return Fail(cx, d, "unexpected export subsection");
-        }
+    if (numExports > MaxExports)
+        return Fail(cx, d, "too many exports");
+
+    for (uint32_t i = 0; i < numExports; i++) {
+        if (!DecodeFunctionExport(cx, d, mg, &dupSet))
+            return false;
     }
 
     if (!d.finishSection(sectionStart))
         return Fail(cx, d, "export section byte size mismatch");
 
     return true;
 }
 
--- a/js/src/asmjs/WasmText.cpp
+++ b/js/src/asmjs/WasmText.cpp
@@ -73,16 +73,19 @@ class WasmName
 
     bool operator==(WasmName rhs) const {
         if (length() != rhs.length())
             return false;
         if (begin() == rhs.begin())
             return true;
         return EqualChars(begin(), rhs.begin(), length());
     }
+    bool operator!=(WasmName rhs) const {
+        return !(*this == rhs);
+    }
 };
 
 class WasmRef
 {
     WasmName name_;
     uint32_t index_;
 
   public:
@@ -2950,16 +2953,20 @@ ParseExport(WasmParseContext& c)
 
     WasmToken exportee = c.ts.get();
     switch (exportee.kind()) {
       case WasmToken::Index:
         return new(c.lifo) WasmAstExport(name.text(), WasmRef(WasmName(), exportee.index()));
       case WasmToken::Name:
         return new(c.lifo) WasmAstExport(name.text(), WasmRef(exportee.name(), WasmNoIndex));
       case WasmToken::Memory:
+        if (name.text() != WasmName(MOZ_UTF16("memory"), 6)) {
+            c.ts.generateError(exportee, c.error);
+            return nullptr;
+        }
         return new(c.lifo) WasmAstExport(name.text());
       default:
         break;
     }
 
     c.ts.generateError(exportee, c.error);
     return nullptr;
 
@@ -3824,16 +3831,27 @@ EncodeMemorySection(Encoder& e, WasmAstM
 
     if (!e.writeVarU32(memory.initialSize()))
         return false;
 
     uint32_t maxSize = memory.maxSize() ? *memory.maxSize() : memory.initialSize();
     if (!e.writeVarU32(maxSize))
         return false;
 
+    uint8_t exported = 0;
+    for (WasmAstExport* exp : module.exports()) {
+        if (exp->kind() == WasmAstExportKind::Memory) {
+            exported = 1;
+            break;
+        }
+    }
+
+    if (!e.writeU8(exported))
+        return false;
+
     e.finishSection(offset);
     return true;
 }
 
 static bool
 EncodeFunctionExport(Encoder& e, WasmAstExport& exp)
 {
     if (!e.writeVarU32(exp.func().index()))
@@ -3841,54 +3859,45 @@ EncodeFunctionExport(Encoder& e, WasmAst
 
     if (!EncodeCString(e, exp.name()))
         return false;
 
     return true;
 }
 
 static bool
-EncodeMemoryExport(Encoder& e, WasmAstExport& exp)
-{
-    if (!EncodeCString(e, exp.name()))
-        return false;
-
-    return true;
-}
-
-static bool
 EncodeExportSection(Encoder& e, WasmAstModule& module)
 {
-    if (module.exports().empty())
+    uint32_t numFuncExports = 0;
+    for (WasmAstExport* exp : module.exports()) {
+        if (exp->kind() == WasmAstExportKind::Func)
+            numFuncExports++;
+    }
+
+    if (!numFuncExports)
         return true;
 
     size_t offset;
     if (!e.startSection(ExportLabel, &offset))
         return false;
 
+    if (!e.writeVarU32(numFuncExports))
+        return false;
+
     for (WasmAstExport* exp : module.exports()) {
         switch (exp->kind()) {
           case WasmAstExportKind::Func:
-            if (!e.writeCString(FuncLabel))
-                return false;
             if (!EncodeFunctionExport(e, *exp))
                 return false;
             break;
           case WasmAstExportKind::Memory:
-            if (!e.writeCString(MemoryLabel))
-                return false;
-            if (!EncodeMemoryExport(e, *exp))
-                return false;
-            break;
+            continue;
         }
     }
 
-    if (!e.writeCString(EndLabel))
-        return false;
-
     e.finishSection(offset);
     return true;
 }
 
 static bool
 EncodeTableSection(Encoder& e, WasmAstModule& module)
 {
     if (!module.maybeTable())
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -140,64 +140,99 @@ assertErrorMessage(() => wasmEvalText('(
 // May OOM, but must not crash:
 try {
     wasmEvalText('(module (memory 32767))');
 } catch (e) {
     print(e);
     assertEq(String(e).indexOf("out of memory") != -1, true);
 }
 
-assertErrorMessage(() => wasmEvalText('(module (export "" memory))'), TypeError, /no memory section/);
+// Tests to reinstate pending a switch back to "real" memory exports:
+//
+//assertErrorMessage(() => wasmEvalText('(module (export "" memory))'), TypeError, /no memory section/);
+//
+//var buf = wasmEvalText('(module (memory 1) (export "" memory))');
+//assertEq(buf instanceof ArrayBuffer, true);
+//assertEq(buf.byteLength, 65536);
+//
+//assertErrorMessage(() => wasmEvalText('(module (memory 1) (export "a" memory) (export "a" memory))'), TypeError, /duplicate export/);
+//assertErrorMessage(() => wasmEvalText('(module (memory 1) (func) (export "a" memory) (export "a" 0))'), TypeError, /duplicate export/);
+//var {a, b} = wasmEvalText('(module (memory 1) (export "a" memory) (export "b" memory))');
+//assertEq(a instanceof ArrayBuffer, true);
+//assertEq(a, b);
+//
+//var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (func (nop)) (export "a" memory) (export "b" 0) (export "c" 1))');
+//assertEq(obj.a instanceof ArrayBuffer, true);
+//assertEq(obj.b instanceof Function, true);
+//assertEq(obj.c instanceof Function, true);
+//assertEq(obj.a.byteLength, 65536);
+//assertEq(obj.b(), 42);
+//assertEq(obj.c(), undefined);
+//
+//var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (export "" memory) (export "a" 0) (export "b" 0))');
+//assertEq(obj instanceof ArrayBuffer, true);
+//assertEq(obj.a instanceof Function, true);
+//assertEq(obj.b instanceof Function, true);
+//assertEq(obj.a, obj.b);
+//assertEq(obj.byteLength, 65536);
+//assertEq(obj.a(), 42);
+//
+//var buf = wasmEvalText('(module (memory 1 (segment 0 "")) (export "" memory))');
+//assertEq(new Uint8Array(buf)[0], 0);
+//
+//var buf = wasmEvalText('(module (memory 1 (segment 65536 "")) (export "" memory))');
+//assertEq(new Uint8Array(buf)[0], 0);
+//
+//var buf = wasmEvalText('(module (memory 1 (segment 0 "a")) (export "" memory))');
+//assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
+//
+//var buf = wasmEvalText('(module (memory 1 (segment 0 "a") (segment 2 "b")) (export "" memory))');
+//assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
+//assertEq(new Uint8Array(buf)[1], 0);
+//assertEq(new Uint8Array(buf)[2], 'b'.charCodeAt(0));
+//
+//var buf = wasmEvalText('(module (memory 1 (segment 65535 "c")) (export "" memory))');
+//assertEq(new Uint8Array(buf)[0], 0);
+//assertEq(new Uint8Array(buf)[65535], 'c'.charCodeAt(0));
+//
+//assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65536 "a")) (export "" memory))'), TypeError, /data segment does not fit/);
+//assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65535 "ab")) (export "" memory))'), TypeError, /data segment does not fit/);
 
-var buf = wasmEvalText('(module (memory 1) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1) (export "memory" memory))').memory;
 assertEq(buf instanceof ArrayBuffer, true);
 assertEq(buf.byteLength, 65536);
 
-assertErrorMessage(() => wasmEvalText('(module (memory 1) (export "a" memory) (export "a" memory))'), TypeError, /duplicate export/);
-assertErrorMessage(() => wasmEvalText('(module (memory 1) (func) (export "a" memory) (export "a" 0))'), TypeError, /duplicate export/);
-var {a, b} = wasmEvalText('(module (memory 1) (export "a" memory) (export "b" memory))');
-assertEq(a instanceof ArrayBuffer, true);
-assertEq(a, b);
-
-var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (func (nop)) (export "a" memory) (export "b" 0) (export "c" 1))');
-assertEq(obj.a instanceof ArrayBuffer, true);
+var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (func (nop)) (export "memory" memory) (export "b" 0) (export "c" 1))');
+assertEq(obj.memory instanceof ArrayBuffer, true);
 assertEq(obj.b instanceof Function, true);
 assertEq(obj.c instanceof Function, true);
-assertEq(obj.a.byteLength, 65536);
+assertEq(obj.memory.byteLength, 65536);
 assertEq(obj.b(), 42);
 assertEq(obj.c(), undefined);
 
-var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (export "" memory) (export "a" 0) (export "b" 0))');
-assertEq(obj instanceof ArrayBuffer, true);
-assertEq(obj.a instanceof Function, true);
-assertEq(obj.b instanceof Function, true);
-assertEq(obj.a, obj.b);
-assertEq(obj.byteLength, 65536);
-assertEq(obj.a(), 42);
-
-var buf = wasmEvalText('(module (memory 1 (segment 0 "")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 0 "")) (export "memory" memory))').memory;
 assertEq(new Uint8Array(buf)[0], 0);
 
-var buf = wasmEvalText('(module (memory 1 (segment 65536 "")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 65536 "")) (export "memory" memory))').memory;
 assertEq(new Uint8Array(buf)[0], 0);
 
-var buf = wasmEvalText('(module (memory 1 (segment 0 "a")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 0 "a")) (export "memory" memory))').memory;
 assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
 
-var buf = wasmEvalText('(module (memory 1 (segment 0 "a") (segment 2 "b")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 0 "a") (segment 2 "b")) (export "memory" memory))').memory;
 assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
 assertEq(new Uint8Array(buf)[1], 0);
 assertEq(new Uint8Array(buf)[2], 'b'.charCodeAt(0));
 
-var buf = wasmEvalText('(module (memory 1 (segment 65535 "c")) (export "" memory))');
+var buf = wasmEvalText('(module (memory 1 (segment 65535 "c")) (export "memory" memory))').memory;
 assertEq(new Uint8Array(buf)[0], 0);
 assertEq(new Uint8Array(buf)[65535], 'c'.charCodeAt(0));
 
-assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65536 "a")) (export "" memory))'), TypeError, /data segment does not fit/);
-assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65535 "ab")) (export "" memory))'), TypeError, /data segment does not fit/);
+assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65536 "a")) (export "memory" memory))'), TypeError, /data segment does not fit/);
+assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65535 "ab")) (export "memory" memory))'), TypeError, /data segment does not fit/);
 
 // ----------------------------------------------------------------------------
 // locals
 
 assertEq(wasmEvalText('(module (func (param i32) (result i32) (get_local 0)) (export "" 0))')(), 0);
 assertEq(wasmEvalText('(module (func (param i32) (result i32) (get_local 0)) (export "" 0))')(42), 42);
 assertEq(wasmEvalText('(module (func (param i32) (param i32) (result i32) (get_local 0)) (export "" 0))')(42, 43), 42);
 assertEq(wasmEvalText('(module (func (param i32) (param i32) (result i32) (get_local 1)) (export "" 0))')(42, 43), 43);