Merge inbound to mozilla-central. a=merge
authorGurzau Raul <rgurzau@mozilla.com>
Mon, 29 Apr 2019 00:53:59 +0300
changeset 530523 54cbb3745cdb9a8aa0a4428d405b3b2e1c7d13c2
parent 530518 dfadeda4637002db7add681209265524e1bd077e (current diff)
parent 530522 053685dc2ce746e373ec6146621b231bed610874 (diff)
child 530524 588535ba7633dee062173d41059b403fd3939e4e
child 530525 90c4bb8c0d5cb33135e4229c982f746bc1aa9ee7
child 530549 18bc3287830901a5ddb4025152d019367a27b72c
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
54cbb3745cdb / 68.0a1 / 20190428215643 / files
nightly linux64
54cbb3745cdb / 68.0a1 / 20190428215643 / files
nightly mac
54cbb3745cdb / 68.0a1 / 20190428215643 / files
nightly win32
54cbb3745cdb / 68.0a1 / 20190428215643 / files
nightly win64
54cbb3745cdb / 68.0a1 / 20190428215643 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
js/src/wasm/WasmOpIter.h
js/src/wasm/WasmValidate.cpp
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -88,17 +88,17 @@ void WebGLBuffer::BufferData(GLenum targ
                              GLenum usage) {
   // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
   // is like intptr_t.
   if (!CheckedInt<GLsizeiptr>(size).isValid())
     return mContext->ErrorOutOfMemory("bad size");
 
   if (!ValidateBufferUsageEnum(mContext, usage)) return;
 
-#ifdef XP_MACOSX
+#if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
   // bug 790879
   if (mContext->gl->WorkAroundDriverBugs() && size > INT32_MAX) {
     mContext->ErrorOutOfMemory("Allocation size too large.");
     return;
   }
 #endif
 
   const void* uploadData = data;
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -5390,17 +5390,17 @@ mozilla::ipc::IPCResult Snapshot::RecvDe
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult Snapshot::RecvCheckpoint(
     nsTArray<LSWriteInfo>&& aWriteInfos) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mUsage >= 0);
-  MOZ_ASSERT(mPeakUsage >= mUsage);
+  MOZ_DIAGNOSTIC_ASSERT(mPeakUsage >= mUsage);
 
   if (NS_WARN_IF(aWriteInfos.IsEmpty())) {
     ASSERT_UNLESS_FUZZING();
     return IPC_FAIL_NO_REASON(this);
   }
 
   mDatastore->BeginUpdateBatch(mUsage);
 
--- a/js/src/jit-test/tests/wasm/passive-segs-boundary.js
+++ b/js/src/jit-test/tests/wasm/passive-segs-boundary.js
@@ -3,45 +3,61 @@
 // Perform a test which,
 //
 // * if errKind is defined, is expected to fail with an exception
 //   characterised by errKind and errText.
 //
 // * if errKind is undefined, is expected to succeed, in which case errKind
 //   and errText are ignored.
 //
-// The function body will be [insn1, insn2].  isMem controls whether the
-// module is constructed with memory or table initializers.  haveMemOrTable
-// determines whether there is actually a memory or table to work with.
+// The function body will be [insn1, insn2] and is constructed according to
+// four booleans:
+//
+// * isMem controls whether the module is constructed with memory or
+//   table initializers.
+//
+// * haveStorage determines whether there is actually a memory or table to
+//   work with.
+//
+// * haveInitA controls whether active initializers are added.
+//
+// * haveInitP controls whether passive initializers are added.
 
-function do_test(insn1, insn2, errKind, errText, isMem, haveMemOrTable)
+function do_test(insn1, insn2, errKind, errText,
+                 isMem, haveStorage, haveInitA, haveInitP)
 {
     let preamble;
     if (isMem) {
-        let mem_def  = haveMemOrTable ? "(memory 1 1)" : "";
-        let mem_init = haveMemOrTable
-                       ? `(data (i32.const 2) "\\03\\01\\04\\01")
-                          (data passive "\\02\\07\\01\\08")
-                          (data (i32.const 12) "\\07\\05\\02\\03\\06")
-                          (data passive "\\05\\09\\02\\07\\06")`
-                       : "";
+        let mem_def  = haveStorage ? "(memory 1 1)" : "";
+        let mem_ia1  = `(data (i32.const 2) "\\03\\01\\04\\01")`;
+        let mem_ia2  = `(data (i32.const 12) "\\07\\05\\02\\03\\06")`;
+        let mem_ip1  = `(data passive "\\02\\07\\01\\08")`;
+        let mem_ip2  = `(data passive "\\05\\09\\02\\07\\06")`;
+        let mem_init = ``;
+        if (haveInitA && haveInitP)
+            mem_init = `${mem_ia1} ${mem_ip1} ${mem_ia2} ${mem_ip2}`;
+        else if (haveInitA && !haveInitP) mem_init = `${mem_ia1} ${mem_ia2}`;
+        else if (!haveInitA && haveInitP) mem_init = `${mem_ip1} ${mem_ip2}`;
         preamble
             = `;; -------- Memories --------
                ${mem_def}
                ;; -------- Memory initialisers --------
                ${mem_init}
               `;
     } else {
-        let tab_def  = haveMemOrTable ? "(table 30 30 funcref)" : "";
-        let tab_init = haveMemOrTable
-                       ? `(elem (i32.const 2) 3 1 4 1)
-                          (elem passive 2 7 1 8)
-                          (elem (i32.const 12) 7 5 2 3 6)
-                          (elem passive 5 9 2 7 6)`
-                       : "";
+        let tab_def  = haveStorage ? "(table 30 30 funcref)" : "";
+        let tab_ia1  = `(elem (i32.const 2) 3 1 4 1)`;
+        let tab_ia2  = `(elem (i32.const 12) 7 5 2 3 6)`;
+        let tab_ip1  = `(elem passive 2 7 1 8)`;
+        let tab_ip2  = `(elem passive 5 9 2 7 6)`;
+        let tab_init = ``;
+        if (haveInitA && haveInitP)
+            tab_init = `${tab_ia1} ${tab_ip1} ${tab_ia2} ${tab_ip2}`;
+        else if (haveInitA && !haveInitP) tab_init = `${tab_ia1} ${tab_ia2}`;
+        else if (!haveInitA && haveInitP) tab_init = `${tab_ip1} ${tab_ip2}`;
         preamble
             = `;; -------- Tables --------
                ${tab_def}
                ;; -------- Table initialisers --------
                ${tab_init}
                ;; ------ Functions (0..9) referred by the table/esegs ------
                (func (result i32) (i32.const 0))
                (func (result i32) (i32.const 1))
@@ -74,48 +90,89 @@ function do_test(insn1, insn2, errKind, 
             errText
         );
     } else {
         let inst = wasmEvalText(txt);
         assertEq(undefined, inst.exports.testfn());
     }
 }
 
-function mem_test(insn1, insn2, errKind, errText, haveMem=true) {
+
+// Some handy specialisations of do_test().
+
+function mem_test(insn1, insn2, errKind, errText,
+                  haveStorage=true, haveInitA=true, haveInitP=true) {
     do_test(insn1, insn2, errKind, errText,
-            /*isMem=*/true, haveMem);
+            /*isMem=*/true, haveStorage, haveInitA, haveInitP);
 }
 
-function mem_test_nofail(insn1, insn2) {
+function mem_test_nofail(insn1, insn2,
+                         haveStorage=true, haveInitA=true, haveInitP=true) {
     do_test(insn1, insn2, undefined, undefined,
-            /*isMem=*/true, /*haveMemOrTable=*/true);
+            /*isMem=*/true, haveStorage, haveInitA, haveInitP);
 }
 
-function tab_test(insn1, insn2, errKind, errText, haveTab=true) {
+function tab_test(insn1, insn2, errKind, errText,
+                  haveStorage=true, haveInitA=true, haveInitP=true) {
     do_test(insn1, insn2, errKind, errText,
-            /*isMem=*/false, haveTab);
+            /*isMem=*/false, haveStorage, haveInitA, haveInitP);
 }
 
-function tab_test_nofail(insn1, insn2) {
+function tab_test_nofail(insn1, insn2,
+                         haveStorage=true, haveInitA=true, haveInitP=true) {
     do_test(insn1, insn2, undefined, undefined,
-            /*isMem=*/false, /*haveMemOrTable=*/true);
+            /*isMem=*/false, haveStorage, haveInitA, haveInitP);
 }
 
 
 //---- memory.{drop,init,copy} -------------------------------------------------
 
-// drop with no memory
+// The tested semantics for memory.drop, in the case where there's no memory,
+// are as follows.  table.drop is analogous.
+//
+// no memory, no data segments:
+//    drop with any args -> fail OOB
+//                          [because there's nothing to drop]
+//
+// no memory, data segments, at least one of which is active:
+//    -> always fails, regardless of insns
+//       [because active segments implicitly reference memory 0]
+//
+// no memory, data segments, all of which are passive:
+//    drop, segment index is OOB -> fail OOB
+//                                  [because it refers to non existent segment]
+//
+//    drop, segment index is IB -> OK
+
+// drop with no memory and no data segments
+mem_test("data.drop 0", "",
+         WebAssembly.CompileError, /data.drop segment index out of range/,
+         /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/false);
+
+// drop with no memory but with both passive and active segments, ix in range
+// and refers to a passive segment
 mem_test("data.drop 3", "",
-         WebAssembly.CompileError, /can't touch memory without memory/,
-         false);
+         WebAssembly.CompileError,
+         /active data segment requires a memory section/,
+         /*haveStorage=*/false, /*haveInitA=*/true, /*haveInitP=*/true);
 
-// init with no memory
+// drop with no memory but with passive segments only, ix out of range
+mem_test("data.drop 2", "",
+         WebAssembly.CompileError, /data.drop segment index out of range/,
+         /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/true);
+
+// drop with no memory but with passive segments only, ix in range
+mem_test_nofail("data.drop 1", "",
+                /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/true);
+
+
+// init with no memory and no data segs
 mem_test("(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))", "",
          WebAssembly.CompileError, /can't touch memory without memory/,
-         false);
+         /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/false);
 
 // drop with data seg ix out of range
 mem_test("data.drop 4", "",
          WebAssembly.CompileError, /data.drop segment index out of range/);
 
 // init with data seg ix out of range
 mem_test("(memory.init 4 (i32.const 1234) (i32.const 1) (i32.const 1))", "",
          WebAssembly.CompileError, /memory.init segment index out of range/);
@@ -205,25 +262,44 @@ mem_test("(memory.init 1 (i32.const 1) (
         let i1 = `(memory.init 1 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))`;
         mem_test(i1, "", WebAssembly.CompileError, /type mismatch/);
     }}}
 }
 
 //
 //---- table.{drop,init} --------------------------------------------------
 
-// drop with no table
+// drop with no tables and no elem segments
+tab_test("elem.drop 0", "",
+         WebAssembly.CompileError,
+         /element segment index out of range for elem.drop/,
+         /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/false);
+
+// drop with no tables but with both passive and active segments, ix in range
+// and refers to a passive segment
 tab_test("elem.drop 3", "",
-         WebAssembly.CompileError, /can't elem.drop without a table/,
-         false);
+         WebAssembly.CompileError,
+         /active elem segment requires a table section/,
+         /*haveStorage=*/false, /*haveInitA=*/true, /*haveInitP=*/true);
+
+// drop with no tables but with passive segments only, ix out of range
+tab_test("elem.drop 2", "",
+         WebAssembly.CompileError,
+         /element segment index out of range for elem.drop/,
+         /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/true);
+
+// drop with no tables but with passive segments only, ix in range
+tab_test_nofail("elem.drop 1", "",
+                /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/true);
+
 
 // init with no table
 tab_test("(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", "",
          WebAssembly.CompileError, /table index out of range/,
-         false);
+         /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/false);
 
 // drop with elem seg ix out of range
 tab_test("elem.drop 4", "",
          WebAssembly.CompileError, /element segment index out of range for elem.drop/);
 
 // init with elem seg ix out of range
 tab_test("(table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))", "",
          WebAssembly.CompileError, /table.init segment index out of range/);
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -568,21 +568,32 @@ static uint32_t EvaluateInitExpr(const V
       return initExpr.val().i32();
     case InitExpr::Kind::GetGlobal:
       return globalImportValues[initExpr.globalIndex()].i32();
   }
 
   MOZ_CRASH("bad initializer expression");
 }
 
+#ifdef DEBUG
+static bool AllSegmentsArePassive(const DataSegmentVector& vec) {
+  for (const DataSegment* seg : vec) {
+    if (seg->active()) {
+      return false;
+    }
+  }
+  return true;
+}
+#endif
+
 bool Module::initSegments(JSContext* cx, HandleWasmInstanceObject instanceObj,
                           const JSFunctionVector& funcImports,
                           HandleWasmMemoryObject memoryObj,
                           const ValVector& globalImportValues) const {
-  MOZ_ASSERT_IF(!memoryObj, dataSegments_.empty());
+  MOZ_ASSERT_IF(!memoryObj, AllSegmentsArePassive(dataSegments_));
 
   Instance& instance = instanceObj->instance();
   const SharedTableVector& tables = instance.tables();
 
 #ifndef ENABLE_WASM_BULKMEM_OPS
   // Bulk memory changes the error checking behavior: we may write partial data.
 
   // Perform all error checks up front so that this function does not perform
@@ -799,17 +810,17 @@ static bool CheckSharing(JSContext* cx, 
 
 // asm.js module instantiation supplies its own buffer, but for wasm, create and
 // initialize the buffer if one is requested. Either way, the buffer is wrapped
 // in a WebAssembly.Memory object which is what the Instance stores.
 bool Module::instantiateMemory(JSContext* cx,
                                MutableHandleWasmMemoryObject memory) const {
   if (!metadata().usesMemory()) {
     MOZ_ASSERT(!memory);
-    MOZ_ASSERT(dataSegments_.empty());
+    MOZ_ASSERT(AllSegmentsArePassive(dataSegments_));
     return true;
   }
 
   uint32_t declaredMin = metadata().minMemoryLength;
   Maybe<uint32_t> declaredMax = metadata().maxMemoryLength;
   bool declaredShared = metadata().memoryUsage == MemoryUsage::Shared;
 
   if (memory) {
--- a/js/src/wasm/WasmOpIter.h
+++ b/js/src/wasm/WasmOpIter.h
@@ -1847,26 +1847,16 @@ inline bool OpIter<Policy>::readMemOrTab
   return true;
 }
 
 template <typename Policy>
 inline bool OpIter<Policy>::readDataOrElemDrop(bool isData,
                                                uint32_t* segIndex) {
   MOZ_ASSERT(Classify(op_) == OpKind::DataOrElemDrop);
 
-  if (isData) {
-    if (!env_.usesMemory()) {
-      return fail("can't touch memory without memory");
-    }
-  } else {
-    if (env_.tables.length() == 0) {
-      return fail("can't elem.drop without a table");
-    }
-  }
-
   if (!readVarU32(segIndex)) {
     return false;
   }
 
   if (isData) {
     if (env_.dataCount.isNothing()) {
       return fail("data.drop requires a DataCount section");
     }
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -2241,32 +2241,34 @@ static bool DecodeElemSection(Decoder& d
       case uint32_t(InitializerKind::ActiveWithIndex):
         break;
       default:
         return d.fail("invalid elem initializer-kind field");
     }
 
     InitializerKind initializerKind = InitializerKind(initializerKindVal);
 
-    if (env->tables.length() == 0) {
-      return d.fail("elem segment requires a table section");
+    if (initializerKind != InitializerKind::Passive &&
+        env->tables.length() == 0) {
+      return d.fail("active elem segment requires a table section");
     }
 
     MutableElemSegment seg = js_new<ElemSegment>();
     if (!seg) {
       return false;
     }
 
     uint32_t tableIndex = 0;
     if (initializerKind == InitializerKind::ActiveWithIndex) {
       if (!d.readVarU32(&tableIndex)) {
         return d.fail("expected table index");
       }
     }
-    if (tableIndex >= env->tables.length()) {
+    if (initializerKind != InitializerKind::Passive &&
+        tableIndex >= env->tables.length()) {
       return d.fail("table index out of range for element segment");
     }
     if (initializerKind == InitializerKind::Passive) {
       // Too many bugs result from keeping this value zero.  For passive
       // segments, there really is no segment index, and we should never
       // touch the field.
       tableIndex = (uint32_t)-1;
     } else if (env->tables[tableIndex].kind != TableKind::AnyFunction) {
@@ -2580,18 +2582,18 @@ static bool DecodeDataSection(Decoder& d
       case uint32_t(InitializerKind::ActiveWithIndex):
         break;
       default:
         return d.fail("invalid data initializer-kind field");
     }
 
     InitializerKind initializerKind = InitializerKind(initializerKindVal);
 
-    if (!env->usesMemory()) {
-      return d.fail("data segment requires a memory section");
+    if (initializerKind != InitializerKind::Passive && !env->usesMemory()) {
+      return d.fail("active data segment requires a memory section");
     }
 
     uint32_t memIndex = 0;
     if (initializerKind == InitializerKind::ActiveWithIndex) {
       if (!d.readVarU32(&memIndex)) {
         return d.fail("expected memory index");
       }
       if (memIndex > 0) {