merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 10 Mar 2017 11:38:18 +0100
changeset 346935 9b0f116a58d6adb6934f50bcf220cc3ca4343d60
parent 346910 e18d3dd20e8d60bb21524e1b6ef4a87288369afe (current diff)
parent 346934 c6e386b4db2bfd2ef57923661b1327955964504e (diff)
child 346936 92c5b7bcd598c55f88979c014acfb79fd1ad7e45
child 346955 787c3968b20c4e4a4e7267976280e0dfce91cb6f
child 347127 ec668909445a115e5ca6fbe3651c23357624f936
push id31481
push usercbook@mozilla.com
push dateFri, 10 Mar 2017 10:38:29 +0000
treeherdermozilla-central@9b0f116a58d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.0a1
first release with
nightly linux32
9b0f116a58d6 / 55.0a1 / 20170310110248 / files
nightly linux64
9b0f116a58d6 / 55.0a1 / 20170310110248 / files
nightly mac
9b0f116a58d6 / 55.0a1 / 20170310030205 / files
nightly win32
9b0f116a58d6 / 55.0a1 / 20170310030205 / files
nightly win64
9b0f116a58d6 / 55.0a1 / 20170310030205 / 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 mozilla-inbound to mozilla-central a=merge
dom/canvas/WebGLElementArrayCache.cpp
dom/canvas/WebGLElementArrayCache.h
dom/canvas/gtest/TestWebGLElementArrayCache.cpp
dom/webidl/ServiceWorkerMessageEvent.webidl
modules/libpref/init/all.js
testing/web-platform/meta/html/webappapis/scripting/events/messageevent-constructor.https.html.ini
testing/web-platform/meta/service-workers/service-worker/postmessage-to-client.https.html.ini
testing/web-platform/meta/service-workers/service-worker/serviceworker-message-event-historical.https.html.ini
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -140,17 +140,17 @@ PostMessageEvent::Run()
   }
 
   // Create the event
   nsCOMPtr<mozilla::dom::EventTarget> eventTarget = do_QueryObject(targetWindow);
   RefPtr<MessageEvent> event =
     new MessageEvent(eventTarget, nullptr, nullptr);
 
 
-  Nullable<WindowProxyOrMessagePort> source;
+  Nullable<WindowProxyOrMessagePortOrServiceWorker> source;
   source.SetValue().SetAsWindowProxy() = mSource ? mSource->AsOuter() : nullptr;
 
   Sequence<OwningNonNull<MessagePort>> ports;
   if (!TakeTransferredPortsAsSequence(ports)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"),
--- a/dom/broadcastchannel/BroadcastChannelChild.cpp
+++ b/dom/broadcastchannel/BroadcastChannelChild.cpp
@@ -90,23 +90,18 @@ BroadcastChannelChild::RecvNotify(const 
   }
 
   RootedDictionary<MessageEventInit> init(cx);
   init.mBubbles = false;
   init.mCancelable = false;
   init.mOrigin = mOrigin;
   init.mData = value;
 
-  ErrorResult rv;
   RefPtr<MessageEvent> event =
-    MessageEvent::Constructor(mBC, NS_LITERAL_STRING("message"), init, rv);
-  if (NS_WARN_IF(rv.Failed())) {
-    rv.SuppressException();
-    return IPC_OK();
-  }
+    MessageEvent::Constructor(mBC, NS_LITERAL_STRING("message"), init);
 
   event->SetTrusted(true);
 
   bool status;
   mBC->DispatchEvent(static_cast<Event*>(event.get()), &status);
 
   return IPC_OK();
 }
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLBuffer.h"
 
 #include "GLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "WebGLContext.h"
-#include "WebGLElementArrayCache.h"
 
 namespace mozilla {
 
 WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf)
     : WebGLRefCountedObject(webgl)
     , mGLName(buf)
     , mContent(Kind::Undefined)
     , mUsage(LOCAL_GL_STATIC_DRAW)
@@ -33,19 +32,16 @@ void
 WebGLBuffer::SetContentAfterBind(GLenum target)
 {
     if (mContent != Kind::Undefined)
         return;
 
     switch (target) {
     case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
         mContent = Kind::ElementArray;
-        if (!mCache) {
-            mCache.reset(new WebGLElementArrayCache);
-        }
         break;
 
     case LOCAL_GL_ARRAY_BUFFER:
     case LOCAL_GL_PIXEL_PACK_BUFFER:
     case LOCAL_GL_PIXEL_UNPACK_BUFFER:
     case LOCAL_GL_UNIFORM_BUFFER:
     case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
     case LOCAL_GL_COPY_READ_BUFFER:
@@ -59,17 +55,18 @@ WebGLBuffer::SetContentAfterBind(GLenum 
 }
 
 void
 WebGLBuffer::Delete()
 {
     mContext->MakeContextCurrent();
     mContext->gl->fDeleteBuffers(1, &mGLName);
     mByteLength = 0;
-    mCache = nullptr;
+    mIndexCache = nullptr;
+    mIndexRanges.clear();
     LinkedListElement<WebGLBuffer>::remove(); // remove from mContext->mBuffers
 }
 
 ////////////////////////////////////////
 
 static bool
 ValidateBufferUsageEnum(WebGLContext* webgl, const char* funcName, GLenum usage)
 {
@@ -105,56 +102,107 @@ WebGLBuffer::BufferData(GLenum target, s
     // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
     // is like intptr_t.
     if (!CheckedInt<GLsizeiptr>(size).isValid())
         return mContext->ErrorOutOfMemory("%s: bad size", funcName);
 
     if (!ValidateBufferUsageEnum(mContext, funcName, usage))
         return;
 
-    const auto& gl = mContext->gl;
-    gl->MakeCurrent();
-    const ScopedLazyBind lazyBind(gl, target, this);
-    mContext->InvalidateBufferFetching();
-
 #ifdef XP_MACOSX
     // bug 790879
-    if (gl->WorkAroundDriverBugs() &&
+    if (mContext->gl->WorkAroundDriverBugs() &&
         size > INT32_MAX)
     {
         mContext->ErrorOutOfMemory("%s: Allocation size too large.", funcName);
         return;
     }
 #endif
 
+    const void* uploadData = data;
+
+    UniqueBuffer newIndexCache;
+    if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER &&
+        mContext->mNeedsIndexValidation)
+    {
+        newIndexCache = malloc(size);
+        if (!newIndexCache) {
+            mContext->ErrorOutOfMemory("%s: Failed to alloc index cache.", funcName);
+            return;
+        }
+        memcpy(newIndexCache.get(), data, size);
+        uploadData = newIndexCache.get();
+    }
+
+    const auto& gl = mContext->gl;
+    gl->MakeCurrent();
+    const ScopedLazyBind lazyBind(gl, target, this);
+
     const bool sizeChanges = (size != ByteLength());
     if (sizeChanges) {
+        mContext->InvalidateBufferFetching();
+
         gl::GLContext::LocalErrorScope errorScope(*gl);
-        gl->fBufferData(target, size, data, usage);
+        gl->fBufferData(target, size, uploadData, usage);
         const auto error = errorScope.GetError();
 
         if (error) {
             MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY);
             mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error);
             return;
         }
     } else {
-        gl->fBufferData(target, size, data, usage);
+        gl->fBufferData(target, size, uploadData, usage);
     }
 
     mUsage = usage;
     mByteLength = size;
+    mIndexCache = Move(newIndexCache);
 
-    // Warning: Possibly shared memory.  See bug 1225033.
-    if (!ElementArrayCacheBufferData(data, size)) {
-        mByteLength = 0;
-        mContext->ErrorOutOfMemory("%s: Failed update index buffer cache.", funcName);
+    if (mIndexCache) {
+        if (mIndexRanges.size()) {
+            mContext->GeneratePerfWarning("[%p] Invalidating %u ranges.", this,
+                                          uint32_t(mIndexRanges.size()));
+            mIndexRanges.clear();
+        }
     }
 }
 
+void
+WebGLBuffer::BufferSubData(GLenum target, size_t dstByteOffset, size_t dataLen,
+                           const void* data) const
+{
+    const char funcName[] = "bufferSubData";
+
+    if (!ValidateRange(funcName, dstByteOffset, dataLen))
+        return;
+
+    if (!CheckedInt<GLintptr>(dataLen).isValid())
+        return mContext->ErrorOutOfMemory("%s: Size too large.", funcName);
+
+    ////
+
+    const void* uploadData = data;
+    if (mIndexCache) {
+        const auto cachedDataBegin = (uint8_t*)mIndexCache.get() + dstByteOffset;
+        memcpy(cachedDataBegin, data, dataLen);
+        uploadData = cachedDataBegin;
+
+        InvalidateCacheRange(dstByteOffset, dataLen);
+    }
+
+    ////
+
+    const auto& gl = mContext->gl;
+    gl->MakeCurrent();
+    const ScopedLazyBind lazyBind(gl, target, this);
+
+    gl->fBufferSubData(target, dstByteOffset, dataLen, uploadData);
+}
+
 bool
 WebGLBuffer::ValidateRange(const char* funcName, size_t byteOffset, size_t byteLen) const
 {
     auto availLength = mByteLength;
     if (byteOffset > availLength) {
         mContext->ErrorInvalidValue("%s: Offset passes the end of the buffer.", funcName);
         return false;
     }
@@ -166,64 +214,141 @@ WebGLBuffer::ValidateRange(const char* f
         return false;
     }
 
     return true;
 }
 
 ////////////////////////////////////////
 
-bool
-WebGLBuffer::ElementArrayCacheBufferData(const void* ptr,
-                                         size_t bufferSizeInBytes)
+static uint8_t
+IndexByteSizeByType(GLenum type)
 {
-    if (mContext->IsWebGL2())
-        return true;
-
-    if (mContent == Kind::ElementArray)
-        return mCache->BufferData(ptr, bufferSizeInBytes);
-
-    return true;
+    switch (type) {
+    case LOCAL_GL_UNSIGNED_BYTE:  return 1;
+    case LOCAL_GL_UNSIGNED_SHORT: return 2;
+    case LOCAL_GL_UNSIGNED_INT:   return 4;
+    default:
+        MOZ_CRASH();
+    }
 }
 
 void
-WebGLBuffer::ElementArrayCacheBufferSubData(size_t pos, const void* ptr,
-                                            size_t updateSizeInBytes)
+WebGLBuffer::InvalidateCacheRange(size_t byteOffset, size_t byteLength) const
 {
-    if (mContext->IsWebGL2())
-        return;
+    MOZ_ASSERT(mIndexCache);
 
-    if (mContent == Kind::ElementArray)
-        mCache->BufferSubData(pos, ptr, updateSizeInBytes);
+    std::vector<IndexRange> invalids;
+    const size_t updateBegin = byteOffset;
+    const size_t updateEnd = updateBegin + byteLength;
+    for (const auto& cur : mIndexRanges) {
+        const auto& range = cur.first;
+        const auto& indexByteSize = IndexByteSizeByType(range.type);
+        const size_t rangeBegin = range.first * indexByteSize;
+        const size_t rangeEnd = rangeBegin + range.count*indexByteSize;
+        if (rangeBegin >= updateEnd || rangeEnd <= updateBegin)
+            continue;
+        invalids.push_back(range);
+    }
+
+    if (invalids.size()) {
+        mContext->GeneratePerfWarning("[%p] Invalidating %u/%u ranges.", this,
+                                      uint32_t(invalids.size()),
+                                      uint32_t(mIndexRanges.size()));
+
+        for (const auto& cur : invalids) {
+            mIndexRanges.erase(cur);
+        }
+    }
 }
 
 size_t
 WebGLBuffer::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
-    size_t sizeOfCache = mCache ? mCache->SizeOfIncludingThis(mallocSizeOf)
-                                : 0;
-    return mallocSizeOf(this) + sizeOfCache;
+    size_t size = mallocSizeOf(this);
+    if (mIndexCache) {
+        size += mByteLength;
+    }
+    return size;
 }
 
+template<typename T>
+static size_t
+MaxForRange(const void* data, size_t first, size_t count, const uint32_t ignoredVal)
+{
+    const T ignoredTVal(ignoredVal);
+    T ret = 0;
+
+    auto itr = (const T*)data + first;
+    const auto end = itr + count;
+
+    for (; itr != end; ++itr) {
+        const auto& val = *itr;
+        if (val <= ret)
+            continue;
+
+        if (val == ignoredTVal)
+            continue;
+
+        ret = val;
+    }
+
+    return size_t(ret);
+}
+
+const uint32_t kMaxIndexRanges = 256;
+
 bool
-WebGLBuffer::Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count) const
+WebGLBuffer::ValidateIndexedFetch(GLenum type, uint32_t numFetchable, size_t first,
+                                  size_t count) const
 {
-    if (mContext->IsWebGL2())
+    if (!mIndexCache)
         return true;
 
-    return mCache->Validate(type, maxAllowed, first, count);
-}
+    if (!count)
+        return true;
+
+    const IndexRange range = { type, first, count };
+    auto res = mIndexRanges.insert({ range, size_t(0) });
+    if (mIndexRanges.size() > kMaxIndexRanges) {
+        mContext->GeneratePerfWarning("[%p] Clearing mIndexRanges after exceeding %u.",
+                                      this, kMaxIndexRanges);
+        mIndexRanges.clear();
+        res = mIndexRanges.insert({ range, size_t(0) });
+    }
+
+    const auto& itr = res.first;
+    const auto& didInsert = res.second;
+
+    auto& maxFetchIndex = itr->second;
+    if (didInsert) {
+        const auto& data = mIndexCache.get();
+        const uint32_t ignoreVal = (mContext->IsWebGL2() ? UINT32_MAX : 0);
 
-bool
-WebGLBuffer::IsElementArrayUsedWithMultipleTypes() const
-{
-    if (mContext->IsWebGL2())
-        return false;
+        switch (type) {
+        case LOCAL_GL_UNSIGNED_BYTE:
+            maxFetchIndex = MaxForRange<uint8_t>(data, first, count, ignoreVal);
+            break;
+        case LOCAL_GL_UNSIGNED_SHORT:
+            maxFetchIndex = MaxForRange<uint16_t>(data, first, count, ignoreVal);
+            break;
+        case LOCAL_GL_UNSIGNED_INT:
+            maxFetchIndex = MaxForRange<uint32_t>(data, first, count, ignoreVal);
+            break;
+        default:
+            MOZ_CRASH();
+        }
 
-    return mCache->BeenUsedWithMultipleTypes();
+        mContext->GeneratePerfWarning("[%p] New range #%u: (0x%04x, %u, %u): %u", this,
+                                      uint32_t(mIndexRanges.size()), type,
+                                      uint32_t(first), uint32_t(count),
+                                      uint32_t(maxFetchIndex));
+    }
+
+    return maxFetchIndex < numFetchable;
 }
 
 ////
 
 bool
 WebGLBuffer::ValidateCanBindToTarget(const char* funcName, GLenum target)
 {
     /* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
--- a/dom/canvas/WebGLBuffer.h
+++ b/dom/canvas/WebGLBuffer.h
@@ -1,28 +1,26 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGL_BUFFER_H_
 #define WEBGL_BUFFER_H_
 
+#include <map>
+
 #include "GLDefs.h"
 #include "mozilla/LinkedList.h"
-#include "mozilla/UniquePtr.h"
 #include "nsWrapperCache.h"
-
 #include "WebGLObjectModel.h"
 #include "WebGLTypes.h"
 
 namespace mozilla {
 
-class WebGLElementArrayCache;
-
 class WebGLBuffer final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLBuffer>
     , public LinkedListElement<WebGLBuffer>
 {
     friend class WebGLContext;
     friend class WebGL2Context;
     friend class WebGLTexture;
@@ -41,34 +39,29 @@ public:
 
     void Delete();
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     GLenum Usage() const { return mUsage; }
     size_t ByteLength() const { return mByteLength; }
 
-    bool ElementArrayCacheBufferData(const void* ptr, size_t bufferSizeInBytes);
-
-    void ElementArrayCacheBufferSubData(size_t pos, const void* ptr,
-                                        size_t updateSizeInBytes);
-
-    bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count) const;
+    bool ValidateIndexedFetch(GLenum type, uint32_t max_allowed, size_t first, size_t count) const;
     bool ValidateRange(const char* funcName, size_t byteOffset, size_t byteLen) const;
 
-    bool IsElementArrayUsedWithMultipleTypes() const;
-
     WebGLContext* GetParentObject() const {
         return mContext;
     }
 
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
     bool ValidateCanBindToTarget(const char* funcName, GLenum target);
     void BufferData(GLenum target, size_t size, const void* data, GLenum usage);
+    void BufferSubData(GLenum target, size_t dstByteOffset, size_t dataLen,
+                       const void* data) const;
 
     ////
 
     static void AddBindCount(GLenum target, WebGLBuffer* buffer, int8_t addVal) {
         if (!buffer)
             return;
 
         if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) {
@@ -97,19 +90,39 @@ public:
     const GLenum mGLName;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
 
 protected:
     ~WebGLBuffer();
 
+    void InvalidateCacheRange(size_t offset, size_t length) const;
+
     Kind mContent;
     GLenum mUsage;
     size_t mByteLength;
-    UniquePtr<WebGLElementArrayCache> mCache;
     size_t mTFBindCount;
     size_t mNonTFBindCount;
+
+    struct IndexRange final {
+        GLenum type;
+        size_t first;
+        size_t count;
+
+        bool operator<(const IndexRange& x) const {
+            if (type != x.type)
+                return type < x.type;
+
+            if (first != x.first)
+                return first < x.first;
+
+            return count < x.count;
+        }
+    };
+
+    UniqueBuffer mIndexCache;
+    mutable std::map<IndexRange, size_t> mIndexRanges;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_BUFFER_H_
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -722,17 +722,18 @@ WebGLContext::CreateAndInitGL(bool force
             reason.info.Append(reason.key);
             out_failReasons->push_back(reason);
             GenerateWarning("%s", reason.info.BeginReading());
             return false;
         }
     }
 
     const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this);
-    gl::CreateContextFlags flags = gl::CreateContextFlags::NO_VALIDATION;
+    gl::CreateContextFlags flags = (gl::CreateContextFlags::NO_VALIDATION |
+                                    gl::CreateContextFlags::PREFER_ROBUSTNESS);
     bool tryNativeGL = true;
     bool tryANGLE = false;
 
     if (forceEnabled) {
         flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE;
     }
 
     if (IsWebGL2()) {
@@ -2359,17 +2360,19 @@ WebGLContext::StartVRPresentation()
 
     UniquePtr<gl::SurfaceFactory> factory =
         gl::GLScreenBuffer::CreateFactory(gl,
             caps,
             vrmc,
             vrmc->GetBackendType(),
             TextureFlags::ORIGIN_BOTTOM_LEFT);
 
-    screen->Morph(Move(factory));
+    if (factory) {
+        screen->Morph(Move(factory));
+    }
     return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 static inline size_t
 SizeOfViewElem(const dom::ArrayBufferView& view)
 {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1960,16 +1960,18 @@ protected:
 
     uint64_t mLastUseIndex;
 
     bool mNeedsFakeNoAlpha;
     bool mNeedsFakeNoDepth;
     bool mNeedsFakeNoStencil;
     bool mNeedsEmulatedLoneDepthStencil;
 
+    bool mNeedsIndexValidation;
+
     const bool mAllowFBInvalidation;
 
     bool Has64BitTimestamps() const;
 
     struct ScopedDrawCallWrapper final {
         WebGLContext& mWebGL;
         const bool mFakeNoAlpha;
         const bool mFakeNoDepth;
@@ -2107,60 +2109,16 @@ bool
 ValidateTexTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
                   GLenum rawTexTarget, TexTarget* const out_texTarget,
                   WebGLTexture** const out_tex);
 bool
 ValidateTexImageTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
                        GLenum rawTexImageTarget, TexImageTarget* const out_texImageTarget,
                        WebGLTexture** const out_tex);
 
-class UniqueBuffer
-{
-    // Like UniquePtr<>, but for void* and malloc/calloc/free.
-    void* mBuffer;
-
-public:
-    UniqueBuffer()
-        : mBuffer(nullptr)
-    { }
-
-    MOZ_IMPLICIT UniqueBuffer(void* buffer)
-        : mBuffer(buffer)
-    { }
-
-    ~UniqueBuffer() {
-        free(mBuffer);
-    }
-
-    UniqueBuffer(UniqueBuffer&& other) {
-        this->mBuffer = other.mBuffer;
-        other.mBuffer = nullptr;
-    }
-
-    UniqueBuffer& operator =(UniqueBuffer&& other) {
-        free(this->mBuffer);
-        this->mBuffer = other.mBuffer;
-        other.mBuffer = nullptr;
-        return *this;
-    }
-
-    UniqueBuffer& operator =(void* newBuffer) {
-        free(this->mBuffer);
-        this->mBuffer = newBuffer;
-        return *this;
-    }
-
-    explicit operator bool() const { return bool(mBuffer); }
-
-    void* get() const { return mBuffer; }
-
-    UniqueBuffer(const UniqueBuffer& other) = delete; // construct using Move()!
-    void operator =(const UniqueBuffer& other) = delete; // assign using Move()!
-};
-
 class ScopedUnpackReset final
     : public gl::ScopedGLWrapper<ScopedUnpackReset>
 {
     friend struct gl::ScopedGLWrapper<ScopedUnpackReset>;
 
 private:
     WebGLContext* const mWebGL;
 
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -397,36 +397,20 @@ WebGLContext::BufferSubDataImpl(GLenum t
 
     if (!ValidateNonNegative(funcName, "byteOffset", dstByteOffset))
         return;
 
     const auto& buffer = ValidateBufferSelection(funcName, target);
     if (!buffer)
         return;
 
-    if (!buffer->ValidateRange(funcName, dstByteOffset, dataLen))
-        return;
-
-    if (!CheckedInt<GLintptr>(dataLen).isValid()) {
-        ErrorOutOfMemory("%s: Size too large.", funcName);
-        return;
-    }
-    const GLintptr glDataLen(dataLen);
+    buffer->BufferSubData(target, size_t(dstByteOffset), dataLen, data);
+}
 
-    ////
-
-    MakeContextCurrent();
-    const ScopedLazyBind lazyBind(gl, target, buffer);
-
-    // Warning: Possibly shared memory.  See bug 1225033.
-    gl->fBufferSubData(target, dstByteOffset, glDataLen, data);
-
-    // Warning: Possibly shared memory.  See bug 1225033.
-    buffer->ElementArrayCacheBufferSubData(dstByteOffset, data, size_t(glDataLen));
-}
+////
 
 void
 WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
                             const dom::ArrayBuffer& src)
 {
     if (IsContextLost())
         return;
 
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -733,33 +733,24 @@ WebGLContext::DrawElements_check(const c
                               funcName);
         return false;
     }
 
     if (!ValidateBufferFetching(funcName))
         return false;
 
     if (!mMaxFetchedVertices ||
-        !elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, vertCount))
+        !elemArrayBuffer.ValidateIndexedFetch(type, mMaxFetchedVertices, first, vertCount))
     {
         ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient "
                               "size for given indices from the bound element array",
                               funcName);
         return false;
     }
 
-    // Bug 1008310 - Check if buffer has been used with a different previous type
-    if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) {
-        nsCString typeName;
-        WebGLContext::EnumName(type, &typeName);
-        GenerateWarning("%s: bound element array buffer previously used with a type other than "
-                        "%s, this will affect performance.",
-                        funcName, typeName.BeginReading());
-    }
-
     return true;
 }
 
 static void
 HandleDrawElementsErrors(WebGLContext* webgl, const char* funcName,
                          gl::GLContext::LocalErrorScope& errorScope)
 {
     const auto err = errorScope.GetError();
@@ -989,18 +980,18 @@ WebGLContext::ValidateBufferFetching(con
         }
 
         size_t availBytes = bufByteLen - vd.ByteOffset();
         if (vd.BytesPerVertex() > availBytes) {
             maxVertices = 0;
             maxInstances = 0;
             break;
         }
-        availBytes -= vd.BytesPerVertex();
-        const size_t vertCapacity = 1 + availBytes / vd.ExplicitStride();
+        availBytes -= vd.BytesPerVertex(); // Snip off the tail.
+        const size_t vertCapacity = availBytes / vd.ExplicitStride() + 1; // Add +1 for the snipped tail.
 
         if (vd.mDivisor == 0) {
             if (vertCapacity < maxVertices) {
                 maxVertices = vertCapacity;
             }
             hasPerVertex = true;
         } else {
             const auto curMaxInstances = CheckedInt<size_t>(vertCapacity) * vd.mDivisor;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -720,16 +720,21 @@ WebGLContext::InitAndValidateGL(FailureR
     std::fill_n(mGenericVertexAttribTypes.get(), mGLMaxVertexAttribs, LOCAL_GL_FLOAT);
 
     static const float kDefaultGenericVertexAttribData[4] = { 0, 0, 0, 1 };
     memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData,
            sizeof(mGenericVertexAttrib0Data));
 
     mFakeVertexAttrib0BufferObject = 0;
 
+    mNeedsIndexValidation = !gl->IsSupported(gl::GLFeature::robust_buffer_access_behavior);
+    if (gfxPrefs::WebGLForceIndexValidation()) {
+        mNeedsIndexValidation = true;
+    }
+
     return true;
 }
 
 bool
 WebGLContext::ValidateFramebufferTarget(GLenum target,
                                         const char* const info)
 {
     bool isValid = true;
deleted file mode 100644
--- a/dom/canvas/WebGLElementArrayCache.cpp
+++ /dev/null
@@ -1,622 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "WebGLElementArrayCache.h"
-
-#include <algorithm>
-#include <cstdlib>
-#include <cstring>
-#include <limits>
-#include "mozilla/Assertions.h"
-#include "mozilla/MathAlgorithms.h"
-#include "mozilla/MemoryReporting.h"
-
-namespace mozilla {
-
-/* WebGLElementArrayCacheTree contains most of the implementation of
- * WebGLElementArrayCache, which performs WebGL element array buffer validation
- * for drawElements.
- *
- * Attention: Here lie nontrivial data structures, bug-prone algorithms, and
- * non-canonical tweaks! Whence the explanatory comments, and compiled unit
- * test.
- *
- * *** What problem are we solving here? ***
- *
- * WebGL::DrawElements has to validate that the elements are in range wrt the
- * current vertex attribs. This boils down to the problem, given an array of
- * integers, of computing the maximum in an arbitrary sub-array. The naive
- * algorithm has linear complexity; this has been a major performance problem,
- * see bug 569431. In that bug, we took the approach of caching the max for the
- * whole array, which does cover most cases (DrawElements typically consumes the
- * whole element array buffer) but doesn't help in other use cases:
- *  - when doing "partial DrawElements" i.e. consuming only part of the element
- *    array buffer
- *  - when doing frequent "partial buffer updates" i.e. bufferSubData calls
- *    updating parts of the element array buffer
- *
- * *** The solution: A binary tree ***
- *
- * The solution implemented here is to use a binary tree as the cache data
- * structure. Each tree node contains the max of its two children nodes. In this
- * way, finding the maximum in any contiguous sub-array has log complexity
- * instead of linear complexity.
- *
- * Simplistically, if the element array is:
- *
- *    [1   4   3   2]
- *
- * then the corresponding tree is:
- *
- *           4
- *         _/ \_
- *       4       3
- *      / \     / \
- *     1   4   3   2
- *
- * In practice, the bottom-most levels of the tree are both the largest to store
- * (because they have more nodes), and the least useful performance-wise
- * (because each node in the bottom levels concerns only few entries in the
- * elements array buffer, it is cheap to compute).
- *
- * For this reason, we stop the tree a few levels above, so that each tree leaf
- * actually corresponds to more than one element array entry.
- *
- * The number of levels that we "drop" is |kSkippedBottomTreeLevels| and the
- * number of element array entries that each leaf corresponds to, is
- * |kElementsPerLeaf|. This being a binary tree, we have:
- *
- *   kElementsPerLeaf = 2 ^ kSkippedBottomTreeLevels.
- *
- * *** Storage layout of the binary tree ***
- *
- * We take advantage of the specifics of the situation to avoid generalist tree
- * storage and instead store the tree entries in a vector, mTreeData.
- *
- * TreeData is always a vector of length:
- *
- *    2 * (number of leaves).
- *
- * Its data layout is as follows: mTreeData[0] is unused, mTreeData[1] is the
- * root node, then at offsets 2..3 is the tree level immediately below the root
- * node, then at offsets 4..7 is the tree level below that, etc.
- *
- * The figure below illustrates this by writing at each tree node the offset
- * into mTreeData at which it is stored:
- *
- *           1
- *         _/ \_
- *       2       3
- *      / \     / \
- *     4   5   6   7
- *    ...
- *
- * Thus, under the convention that the root level is level 0, we see that level
- * N is stored at offsets:
- *
- *    [ 2^n .. 2^(n+1) - 1 ]
- *
- * in mTreeData. Likewise, all the usual tree operations have simple
- * mathematical expressions in terms of mTreeData offsets, see all the methods
- * such as ParentNode, LeftChildNode, etc.
- *
- * *** Design constraint: Element types aren't known at buffer-update time ***
- *
- * Note that a key constraint that we're operating under, is that we don't know
- * the types of the elements by the time WebGL bufferData/bufferSubData methods
- * are called. The type of elements is only specified in the drawElements call.
- * This means that we may potentially have to store caches for multiple element
- * types, for the same element array buffer. Since we don't know yet how many
- * element types we'll eventually support (extensions add more), the concern
- * about memory usage is serious. This is addressed by kSkippedBottomTreeLevels
- * as explained above. Of course, in the typical case where each element array
- * buffer is only ever used with one type, this is also addressed by having
- * WebGLElementArrayCache lazily create trees for each type only upon first use.
- *
- * Another consequence of this constraint is that when updating the trees, we
- * have to update all existing trees. So if trees for types uint8_t, uint16_t
- * and uint32_t have ever been constructed for this buffer, every subsequent
- * update will have to update all trees even if one of the types is never used
- * again. That's inefficient, but content should not put indices of different
- * types in the same element array buffer anyways. Different index types can
- * only be consumed in separate drawElements calls, so nothing particular is
- * to be achieved by lumping them in the same buffer object.
- */
-template<typename T>
-struct WebGLElementArrayCacheTree
-{
-    /* A too-high kSkippedBottomTreeLevels would harm the performance of small
-     * drawElements calls. A too-low kSkippedBottomTreeLevels would cause undue
-     * memory usage. The current value has been validated by some benchmarking.
-     * See bug 732660.
-     */
-    static const size_t kSkippedBottomTreeLevels = 3;
-    static const size_t kElementsPerLeaf = 1 << kSkippedBottomTreeLevels;
-    // Since kElementsPerLeaf is POT:
-    static const size_t kElementsPerLeafMask = kElementsPerLeaf - 1;
-
-private:
-    // The WebGLElementArrayCache that owns this tree:
-    WebGLElementArrayCache& mParent;
-
-    // The tree's internal data storage. Its length is 2 * (number of leaves)
-    // because of its data layout explained in the above class comment.
-    FallibleTArray<T> mTreeData;
-
-public:
-    // Constructor. Takes a reference to the WebGLElementArrayCache that is to be
-    // the parent. Does not initialize the tree. Should be followed by a call
-    // to Update() to attempt initializing the tree.
-    explicit WebGLElementArrayCacheTree(WebGLElementArrayCache& value)
-        : mParent(value)
-    {
-    }
-
-    T GlobalMaximum() const {
-        return mTreeData[1];
-    }
-
-    // returns the index of the parent node; if treeIndex=1 (the root node),
-    // the return value is 0.
-    static size_t ParentNode(size_t treeIndex) {
-        MOZ_ASSERT(treeIndex > 1);
-        return treeIndex >> 1;
-    }
-
-    static bool IsRightNode(size_t treeIndex) {
-        MOZ_ASSERT(treeIndex > 1);
-        return treeIndex & 1;
-    }
-
-    static bool IsLeftNode(size_t treeIndex) {
-        MOZ_ASSERT(treeIndex > 1);
-        return !IsRightNode(treeIndex);
-    }
-
-    static size_t SiblingNode(size_t treeIndex) {
-        MOZ_ASSERT(treeIndex > 1);
-        return treeIndex ^ 1;
-    }
-
-    static size_t LeftChildNode(size_t treeIndex) {
-        MOZ_ASSERT(treeIndex);
-        return treeIndex << 1;
-    }
-
-    static size_t RightChildNode(size_t treeIndex) {
-        MOZ_ASSERT(treeIndex);
-        return SiblingNode(LeftChildNode(treeIndex));
-    }
-
-    static size_t LeftNeighborNode(size_t treeIndex, size_t distance = 1) {
-        MOZ_ASSERT(treeIndex > 1);
-        return treeIndex - distance;
-    }
-
-    static size_t RightNeighborNode(size_t treeIndex, size_t distance = 1) {
-        MOZ_ASSERT(treeIndex > 1);
-        return treeIndex + distance;
-    }
-
-    size_t NumLeaves() const {
-        // See class comment for why we the tree storage size is 2 * numLeaves.
-        return mTreeData.Length() >> 1;
-    }
-
-    size_t LeafForElement(size_t element) const {
-        size_t leaf = element / kElementsPerLeaf;
-        MOZ_ASSERT(leaf < NumLeaves());
-        return leaf;
-    }
-
-    size_t LeafForByte(size_t byte) const {
-        return LeafForElement(byte / sizeof(T));
-    }
-
-    // Returns the index, into the tree storage, where a given leaf is stored.
-    size_t TreeIndexForLeaf(size_t leaf) const {
-        // See above class comment. The tree storage is an array of length
-        // 2 * numLeaves. The leaves are stored in its second half.
-        return leaf + NumLeaves();
-    }
-
-    static size_t LastElementUnderSameLeaf(size_t element) {
-        return element | kElementsPerLeafMask;
-    }
-
-    static size_t FirstElementUnderSameLeaf(size_t element) {
-        return element & ~kElementsPerLeafMask;
-    }
-
-    static size_t NextMultipleOfElementsPerLeaf(size_t numElements) {
-        MOZ_ASSERT(numElements >= 1);
-        return ((numElements - 1) | kElementsPerLeafMask) + 1;
-    }
-
-    bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf)
-    {
-        size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
-        size_t lastTreeIndex  = TreeIndexForLeaf(lastLeaf);
-
-        while (true) {
-            // Given that we tweak these values in nontrivial ways, it doesn't
-            // hurt to do this sanity check.
-            MOZ_ASSERT(firstTreeIndex <= lastTreeIndex);
-
-            // Final case where there is only one node to validate at the
-            // current tree level:
-            if (lastTreeIndex == firstTreeIndex) {
-                const T& curData = mTreeData[firstTreeIndex];
-                return curData <= maxAllowed;
-            }
-
-            // If the first node at current tree level is a right node, handle
-            // it individually and replace it with its right neighbor, which is
-            // a left node.
-            if (IsRightNode(firstTreeIndex)) {
-                const T& curData = mTreeData[firstTreeIndex];
-                if (curData > maxAllowed)
-                  return false;
-
-                firstTreeIndex = RightNeighborNode(firstTreeIndex);
-            }
-
-            // If the last node at current tree level is a left node, handle it
-            // individually and replace it with its left neighbor, which is a
-            // right node.
-            if (IsLeftNode(lastTreeIndex)) {
-                const T& curData = mTreeData[lastTreeIndex];
-                if (curData > maxAllowed)
-                    return false;
-
-                lastTreeIndex = LeftNeighborNode(lastTreeIndex);
-            }
-
-            /* At this point it can happen that firstTreeIndex and lastTreeIndex
-             * "crossed" eachother. That happens if firstTreeIndex was a right
-             * node and lastTreeIndex was its right neighor: In that case, both
-             * above tweaks happened and as a result, they ended up being
-             * swapped: LastTreeIndex is now the _left_ neighbor of
-             * firstTreeIndex. When that happens, there is nothing left to
-             * validate.
-             */
-            if (lastTreeIndex == LeftNeighborNode(firstTreeIndex))
-                return true;
-
-            // Walk up one level.
-            firstTreeIndex = ParentNode(firstTreeIndex);
-            lastTreeIndex = ParentNode(lastTreeIndex);
-        }
-    }
-
-    // Updates the tree from the parent's buffer contents. Fallible, as it
-    // may have to resize the tree storage.
-    bool Update(size_t firstByte, size_t lastByte);
-
-    size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
-    {
-        return mallocSizeOf(this) +
-               mTreeData.ShallowSizeOfExcludingThis(mallocSizeOf);
-    }
-};
-
-// TreeForType: just a template helper to select the right tree object for a given
-// element type.
-template<typename T>
-struct TreeForType {};
-
-template<>
-struct TreeForType<uint8_t>
-{
-    static UniquePtr<WebGLElementArrayCacheTree<uint8_t>>&
-    Value(WebGLElementArrayCache* b) {
-        return b->mUint8Tree;
-    }
-};
-
-template<>
-struct TreeForType<uint16_t>
-{
-    static UniquePtr<WebGLElementArrayCacheTree<uint16_t>>&
-    Value(WebGLElementArrayCache* b) {
-        return b->mUint16Tree;
-    }
-};
-
-template<>
-struct TreeForType<uint32_t>
-{
-    static UniquePtr<WebGLElementArrayCacheTree<uint32_t>>&
-    Value(WebGLElementArrayCache* b) {
-        return b->mUint32Tree;
-    }
-};
-
-// Calling this method will 1) update the leaves in this interval
-// from the raw buffer data, and 2) propagate this update up the tree.
-template<typename T>
-bool
-WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
-{
-    MOZ_ASSERT(firstByte <= lastByte);
-    MOZ_ASSERT(lastByte < mParent.mBytes.Length());
-
-    size_t numberOfElements = mParent.mBytes.Length() / sizeof(T);
-    size_t requiredNumLeaves = 0;
-    if (numberOfElements > 0) {
-        /* If we didn't require the number of leaves to be a power of two, then
-         * it would just be equal to
-         *
-         *    ceil(numberOfElements / kElementsPerLeaf)
-         *
-         * The way we implement this (division+ceil) operation in integer
-         * arithmetic
-         * is as follows:
-         */
-        size_t numLeavesNonPOT = (numberOfElements + kElementsPerLeaf - 1) / kElementsPerLeaf;
-        // It only remains to round that up to the next power of two:
-        requiredNumLeaves = RoundUpPow2(numLeavesNonPOT);
-    }
-
-    // Step #0: If needed, resize our tree data storage.
-    if (requiredNumLeaves != NumLeaves()) {
-        // See class comment for why we the tree storage size is 2 * numLeaves.
-        if (!mTreeData.SetLength(2 * requiredNumLeaves, fallible)) {
-            mTreeData.Clear();
-            return false;
-        }
-        MOZ_ASSERT(NumLeaves() == requiredNumLeaves);
-
-        if (NumLeaves()) {
-            // When resizing, update the whole tree, not just the subset
-            // corresponding to the part of the buffer being updated.
-            memset(mTreeData.Elements(), 0, mTreeData.Length() * sizeof(T));
-            firstByte = 0;
-            lastByte = mParent.mBytes.Length() - 1;
-        }
-    }
-
-    if (NumLeaves() == 0)
-        return true;
-
-    lastByte = std::min(lastByte, NumLeaves() * kElementsPerLeaf * sizeof(T) - 1);
-    if (firstByte > lastByte)
-        return true;
-
-    size_t firstLeaf = LeafForByte(firstByte);
-    size_t lastLeaf = LeafForByte(lastByte);
-
-    MOZ_ASSERT(firstLeaf <= lastLeaf && lastLeaf < NumLeaves());
-
-    size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
-    size_t lastTreeIndex = TreeIndexForLeaf(lastLeaf);
-
-    // Step #1: Initialize the tree leaves from plain buffer data.
-    // That is, each tree leaf must be set to the max of the |kElementsPerLeaf|
-    // corresponding buffer entries.
-
-    // Condition-less scope to prevent leaking this scope's variables into the
-    // code below:
-    {
-        // TreeIndex is the index of the tree leaf we're writing, i.e. the
-        // destination index.
-        size_t treeIndex = firstTreeIndex;
-        // srcIndex is the index in the source buffer.
-        size_t srcIndex = firstLeaf * kElementsPerLeaf;
-        while (treeIndex <= lastTreeIndex) {
-            T m = 0;
-            size_t a = srcIndex;
-            size_t srcIndexNextLeaf = std::min(a + kElementsPerLeaf, numberOfElements);
-            for (; srcIndex < srcIndexNextLeaf; srcIndex++) {
-                m = std::max(m, mParent.Element<T>(srcIndex));
-            }
-            mTreeData[treeIndex] = m;
-            treeIndex++;
-        }
-    }
-
-    // Step #2: Propagate the values up the tree. This is simply a matter of
-    // walking up the tree and setting each node to the max of its two children.
-    while (firstTreeIndex > 1) {
-        // Move up one level.
-        firstTreeIndex = ParentNode(firstTreeIndex);
-        lastTreeIndex = ParentNode(lastTreeIndex);
-
-        // Fast-exit case where only one node is updated at the current level.
-        if (firstTreeIndex == lastTreeIndex) {
-            mTreeData[firstTreeIndex] = std::max(mTreeData[LeftChildNode(firstTreeIndex)], mTreeData[RightChildNode(firstTreeIndex)]);
-            continue;
-        }
-
-        size_t child = LeftChildNode(firstTreeIndex);
-        size_t parent = firstTreeIndex;
-        while (parent <= lastTreeIndex) {
-            T a = mTreeData[child];
-            child = RightNeighborNode(child);
-            T b = mTreeData[child];
-            child = RightNeighborNode(child);
-            mTreeData[parent] = std::max(a, b);
-            parent = RightNeighborNode(parent);
-        }
-    }
-
-    return true;
-}
-
-WebGLElementArrayCache::WebGLElementArrayCache()
-{
-}
-
-WebGLElementArrayCache::~WebGLElementArrayCache()
-{
-}
-
-bool
-WebGLElementArrayCache::BufferData(const void* ptr, size_t byteLength)
-{
-    if (mBytes.Length() != byteLength) {
-        if (!mBytes.SetLength(byteLength, fallible)) {
-            mBytes.Clear();
-            return false;
-        }
-    }
-    MOZ_ASSERT(mBytes.Length() == byteLength);
-    return BufferSubData(0, ptr, byteLength);
-}
-
-bool
-WebGLElementArrayCache::BufferSubData(size_t pos, const void* ptr,
-                                      size_t updateByteLength)
-{
-    MOZ_ASSERT(pos + updateByteLength <= mBytes.Length());
-    if (!updateByteLength)
-        return true;
-
-    // Note, using memcpy on shared racy data is not well-defined, this
-    // will need to use safe-for-races operations when those become available.
-    // See bug 1225033.
-    if (ptr)
-        memcpy(mBytes.Elements() + pos, ptr, updateByteLength);
-    else
-        memset(mBytes.Elements() + pos, 0, updateByteLength);
-    return UpdateTrees(pos, pos + updateByteLength - 1);
-}
-
-bool
-WebGLElementArrayCache::UpdateTrees(size_t firstByte, size_t lastByte)
-{
-    bool result = true;
-    if (mUint8Tree)
-        result &= mUint8Tree->Update(firstByte, lastByte);
-    if (mUint16Tree)
-        result &= mUint16Tree->Update(firstByte, lastByte);
-    if (mUint32Tree)
-        result &= mUint32Tree->Update(firstByte, lastByte);
-    return result;
-}
-
-template<typename T>
-bool
-WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
-                                 size_t countElements)
-{
-    // If maxAllowed is >= the max T value, then there is no way that a T index
-    // could be invalid.
-    uint32_t maxTSize = std::numeric_limits<T>::max();
-    if (maxAllowed >= maxTSize)
-        return true;
-
-    T maxAllowedT(maxAllowed);
-
-    // Integer overflow must have been handled earlier, so we assert that
-    // maxAllowedT is exactly the max allowed value.
-    MOZ_ASSERT(uint32_t(maxAllowedT) == maxAllowed);
-
-    if (!mBytes.Length() || !countElements)
-      return true;
-
-    UniquePtr<WebGLElementArrayCacheTree<T>>& tree = TreeForType<T>::Value(this);
-    if (!tree) {
-        tree = MakeUnique<WebGLElementArrayCacheTree<T>>(*this);
-        if (mBytes.Length()) {
-            bool valid = tree->Update(0, mBytes.Length() - 1);
-            if (!valid) {
-                // Do not assert here. This case would happen if an allocation
-                // failed. We've already settled on fallible allocations around
-                // here.
-                tree = nullptr;
-                return false;
-            }
-        }
-    }
-
-    size_t lastElement = firstElement + countElements - 1;
-
-    // Fast-exit path when the global maximum for the whole element array buffer
-    // falls in the allowed range:
-    T globalMax = tree->GlobalMaximum();
-    if (globalMax <= maxAllowedT)
-        return true;
-
-    const T* elements = Elements<T>();
-
-    // Before calling tree->Validate, we have to validate ourselves the
-    // boundaries of the elements span, to round them to the nearest multiple of
-    // kElementsPerLeaf.
-    size_t firstElementAdjustmentEnd = std::min(lastElement,
-                                                tree->LastElementUnderSameLeaf(firstElement));
-    while (firstElement <= firstElementAdjustmentEnd) {
-        const T& curData = elements[firstElement];
-        if (curData > maxAllowedT)
-            return false;
-
-        firstElement++;
-    }
-    size_t lastElementAdjustmentEnd = std::max(firstElement,
-                                               tree->FirstElementUnderSameLeaf(lastElement));
-    while (lastElement >= lastElementAdjustmentEnd) {
-        const T& curData = elements[lastElement];
-        if (curData > maxAllowedT)
-            return false;
-
-        lastElement--;
-    }
-
-    // at this point, for many tiny validations, we're already done.
-    if (firstElement > lastElement)
-        return true;
-
-    // general case
-    return tree->Validate(maxAllowedT, tree->LeafForElement(firstElement),
-                          tree->LeafForElement(lastElement));
-}
-
-bool
-WebGLElementArrayCache::Validate(GLenum type, uint32_t maxAllowed,
-                                 size_t firstElement, size_t countElements)
-{
-    if (type == LOCAL_GL_UNSIGNED_BYTE)
-        return Validate<uint8_t>(maxAllowed, firstElement, countElements);
-    if (type == LOCAL_GL_UNSIGNED_SHORT)
-        return Validate<uint16_t>(maxAllowed, firstElement, countElements);
-    if (type == LOCAL_GL_UNSIGNED_INT)
-        return Validate<uint32_t>(maxAllowed, firstElement, countElements);
-
-    MOZ_ASSERT(false, "Invalid type.");
-    return false;
-}
-
-template<typename T>
-static size_t
-SizeOfNullable(mozilla::MallocSizeOf mallocSizeOf, const T& obj)
-{
-    if (!obj)
-        return 0;
-    return obj->SizeOfIncludingThis(mallocSizeOf);
-}
-
-size_t
-WebGLElementArrayCache::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
-{
-    return mallocSizeOf(this) +
-           mBytes.ShallowSizeOfExcludingThis(mallocSizeOf) +
-           SizeOfNullable(mallocSizeOf, mUint8Tree) +
-           SizeOfNullable(mallocSizeOf, mUint16Tree) +
-           SizeOfNullable(mallocSizeOf, mUint32Tree);
-}
-
-bool
-WebGLElementArrayCache::BeenUsedWithMultipleTypes() const
-{
-  // C++ Standard ($4.7)
-  // "If the source type is bool, the value false is converted to zero and
-  //  the value true is converted to one."
-  const int num_types_used = (mUint8Tree  != nullptr) +
-                             (mUint16Tree != nullptr) +
-                             (mUint32Tree != nullptr);
-  return num_types_used > 1;
-}
-
-} // end namespace mozilla
deleted file mode 100644
--- a/dom/canvas/WebGLElementArrayCache.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef WEBGL_ELEMENT_ARRAY_CACHE_H
-#define WEBGL_ELEMENT_ARRAY_CACHE_H
-
-#include "GLDefs.h"
-#include "mozilla/MemoryReporting.h"
-#include "mozilla/UniquePtr.h"
-#include "nscore.h"
-#include "nsTArray.h"
-#include <stdint.h>
-
-namespace mozilla {
-
-template<typename T>
-struct WebGLElementArrayCacheTree;
-
-/* WebGLElementArrayCache implements WebGL element array buffer validation for
- * drawElements.
- *
- * Its exposes methods meant to be called by WebGL method implementations:
- *
- * - Validate, to be called by WebGLContext::DrawElements, is where we use the
- *   cache.
- *
- * - BufferData and BufferSubData, to be called by eponymous WebGL methods, are
- *   how data is fed into the cache.
- *
- * Most of the implementation is hidden in the auxilary class template,
- * WebGLElementArrayCacheTree. Refer to its code for design comments.
- */
-class WebGLElementArrayCache {
-public:
-    bool BufferData(const void* ptr, size_t byteLength);
-    bool BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
-
-    bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count);
-
-    template<typename T>
-    T Element(size_t i) const { return Elements<T>()[i]; }
-
-    WebGLElementArrayCache();
-    ~WebGLElementArrayCache();
-
-    size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
-    bool BeenUsedWithMultipleTypes() const;
-
-private:
-    /* Returns true if a drawElements call with the given parameters should
-     * succeed, false otherwise.
-     *
-     * In other words, this returns true if all entries in the element array at
-     * positions:
-     *
-     *    first .. first+count-1
-     *
-     * are less than or equal to maxAllowed.
-     *
-     * Input parameters:
-     *   maxAllowed: Maximum value to be allowed in the specificied portion of
-     *               the element array.
-     *   first: Start of the portion of the element array to consume.
-     *   count: Number of entries from the element array to consume.
-     *
-     * Output parameter:
-     *   out_upperBound: Upon success, is set to the actual maximum value in the
-     *                   specified range, which is then guaranteed to be less
-     *                   than or equal to maxAllowed. upon failure, is set to
-     *                   the first value in the specified range, that is greater
-     *                   than maxAllowed.
-     */
-    template<typename T>
-    bool Validate(uint32_t maxAllowed, size_t first, size_t count);
-
-    template<typename T>
-    const T* Elements() const {
-        return reinterpret_cast<const T*>(mBytes.Elements());
-    }
-
-    template<typename T>
-    T* Elements() { return reinterpret_cast<T*>(mBytes.Elements()); }
-
-    bool UpdateTrees(size_t firstByte, size_t lastByte);
-
-    template<typename T>
-    friend struct WebGLElementArrayCacheTree;
-    template<typename T>
-    friend struct TreeForType;
-
-    FallibleTArray<uint8_t> mBytes;
-    UniquePtr<WebGLElementArrayCacheTree<uint8_t>> mUint8Tree;
-    UniquePtr<WebGLElementArrayCacheTree<uint16_t>> mUint16Tree;
-    UniquePtr<WebGLElementArrayCacheTree<uint32_t>> mUint32Tree;
-};
-
-} // end namespace mozilla
-
-#endif // WEBGL_ELEMENT_ARRAY_CACHE_H
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -168,11 +168,55 @@ enum class WebGLExtensionID : uint8_t {
     WEBGL_debug_shaders,
     WEBGL_depth_texture,
     WEBGL_draw_buffers,
     WEBGL_lose_context,
     Max,
     Unknown
 };
 
+class UniqueBuffer
+{
+    // Like UniquePtr<>, but for void* and malloc/calloc/free.
+    void* mBuffer;
+
+public:
+    UniqueBuffer()
+        : mBuffer(nullptr)
+    { }
+
+    MOZ_IMPLICIT UniqueBuffer(void* buffer)
+        : mBuffer(buffer)
+    { }
+
+    ~UniqueBuffer() {
+        free(mBuffer);
+    }
+
+    UniqueBuffer(UniqueBuffer&& other) {
+        this->mBuffer = other.mBuffer;
+        other.mBuffer = nullptr;
+    }
+
+    UniqueBuffer& operator =(UniqueBuffer&& other) {
+        free(this->mBuffer);
+        this->mBuffer = other.mBuffer;
+        other.mBuffer = nullptr;
+        return *this;
+    }
+
+    UniqueBuffer& operator =(void* newBuffer) {
+        free(this->mBuffer);
+        this->mBuffer = newBuffer;
+        return *this;
+    }
+
+    explicit operator bool() const { return bool(mBuffer); }
+
+    void* get() const { return mBuffer; }
+
+    UniqueBuffer(const UniqueBuffer& other) = delete; // construct using Move()!
+    void operator =(const UniqueBuffer& other) = delete; // assign using Move()!
+};
+
 } // namespace mozilla
 
 #endif
deleted file mode 100644
--- a/dom/canvas/gtest/TestWebGLElementArrayCache.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/Assertions.h"
-
-#include "WebGLElementArrayCache.h"
-
-#include <cstdio>
-#include <cstdlib>
-#include "nscore.h"
-#include "nsTArray.h"
-
-void
-MakeRandomVector(nsTArray<uint8_t>& a, size_t size)
-{
-  a.SetLength(size);
-  // only the most-significant bits of rand() are reasonably random.
-  // RAND_MAX can be as low as 0x7fff, and we need 8 bits for the result, so we can only
-  // ignore the 7 least significant bits.
-  for (size_t i = 0; i < size; i++)
-    a[i] = static_cast<uint8_t>((unsigned int)(rand()) >> 7);
-}
-
-template<typename T>
-T
-RandomInteger(T a, T b)
-{
-  T result(a + rand() % (b - a + 1));
-  return result;
-}
-
-template<typename T>
-GLenum
-GLType()
-{
-  switch (sizeof(T)) {
-  case 4:  return LOCAL_GL_UNSIGNED_INT;
-  case 2:  return LOCAL_GL_UNSIGNED_SHORT;
-  case 1:  return LOCAL_GL_UNSIGNED_BYTE;
-  default:
-    MOZ_RELEASE_ASSERT(false);
-    return 0;
-  }
-}
-
-void
-CheckValidate(bool expectSuccess, mozilla::WebGLElementArrayCache& c, GLenum type,
-              uint32_t maxAllowed, size_t first, size_t count)
-{
-  const bool success = c.Validate(type, maxAllowed, first, count);
-  ASSERT_TRUE(success == expectSuccess);
-}
-
-template<typename T>
-void
-CheckValidateOneTypeVariousBounds(mozilla::WebGLElementArrayCache& c, size_t firstByte,
-                                  size_t countBytes)
-{
-  size_t first = firstByte / sizeof(T);
-  size_t count = countBytes / sizeof(T);
-
-  GLenum type = GLType<T>();
-
-  T max = 0;
-  for (size_t i = 0; i < count; i++)
-    if (c.Element<T>(first + i) > max)
-      max = c.Element<T>(first + i);
-
-  CheckValidate(true, c, type, max, first, count);
-  CheckValidate(true, c, type, T(-1), first, count);
-  if (T(max + 1)) CheckValidate(true, c, type, T(max + 1), first, count);
-  if (max > 0) {
-    CheckValidate(false, c, type, max - 1, first, count);
-    CheckValidate(false, c, type, 0, first, count);
-  }
-}
-
-void CheckValidateAllTypes(mozilla::WebGLElementArrayCache& c, size_t firstByte,
-                           size_t countBytes)
-{
-  CheckValidateOneTypeVariousBounds<uint8_t>(c, firstByte, countBytes);
-  CheckValidateOneTypeVariousBounds<uint16_t>(c, firstByte, countBytes);
-  CheckValidateOneTypeVariousBounds<uint32_t>(c, firstByte, countBytes);
-}
-
-template<typename T>
-void
-CheckSanity()
-{
-  const size_t numElems = 64; // should be significantly larger than tree leaf size to
-                        // ensure we exercise some nontrivial tree-walking
-  T data[numElems] = {1,0,3,1,2,6,5,4}; // intentionally specify only 8 elements for now
-  size_t numBytes = numElems * sizeof(T);
-  ASSERT_TRUE(numBytes == sizeof(data));
-
-  GLenum type = GLType<T>();
-
-  mozilla::WebGLElementArrayCache c;
-  c.BufferData(data, numBytes);
-  CheckValidate(true,  c, type, 6, 0, 8);
-  CheckValidate(false, c, type, 5, 0, 8);
-  CheckValidate(true,  c, type, 3, 0, 3);
-  CheckValidate(false, c, type, 2, 0, 3);
-  CheckValidate(true,  c, type, 6, 2, 4);
-  CheckValidate(false, c, type, 5, 2, 4);
-
-  c.BufferSubData(5*sizeof(T), data, sizeof(T));
-  CheckValidate(true,  c, type, 5, 0, 8);
-  CheckValidate(false, c, type, 4, 0, 8);
-
-  // now test a somewhat larger size to ensure we exceed the size of a tree leaf
-  for(size_t i = 0; i < numElems; i++)
-    data[i] = numElems - i;
-  c.BufferData(data, numBytes);
-  CheckValidate(true,  c, type, numElems,     0, numElems);
-  CheckValidate(false, c, type, numElems - 1, 0, numElems);
-
-  ASSERT_TRUE(numElems > 10);
-  CheckValidate(true,  c, type, numElems - 10, 10, numElems - 10);
-  CheckValidate(false, c, type, numElems - 11, 10, numElems - 10);
-}
-
-template<typename T>
-void
-CheckUintOverflow()
-{
-  // This test is only for integer types smaller than uint32_t
-  static_assert(sizeof(T) < sizeof(uint32_t), "This test is only for integer types \
-                smaller than uint32_t");
-
-  const size_t numElems = 64; // should be significantly larger than tree leaf size to
-                              // ensure we exercise some nontrivial tree-walking
-  T data[numElems];
-  size_t numBytes = numElems * sizeof(T);
-  ASSERT_TRUE(numBytes == sizeof(data));
-
-  GLenum type = GLType<T>();
-
-  mozilla::WebGLElementArrayCache c;
-
-  for(size_t i = 0; i < numElems; i++)
-    data[i] = numElems - i;
-  c.BufferData(data, numBytes);
-
-  // bug 825205
-  uint32_t bigValWrappingToZero = uint32_t(T(-1)) + 1;
-  CheckValidate(true,  c, type, bigValWrappingToZero,     0, numElems);
-  CheckValidate(true,  c, type, bigValWrappingToZero - 1, 0, numElems);
-  CheckValidate(false, c, type,                        0, 0, numElems);
-}
-
-TEST(WebGLElementArrayCache, Test)
-{
-  srand(0); // do not want a random seed here.
-
-  CheckSanity<uint8_t>();
-  CheckSanity<uint16_t>();
-  CheckSanity<uint32_t>();
-
-  CheckUintOverflow<uint8_t>();
-  CheckUintOverflow<uint16_t>();
-
-  nsTArray<uint8_t> v, vsub;
-  mozilla::WebGLElementArrayCache b;
-
-  for (int maxBufferSize = 1; maxBufferSize <= 4096; maxBufferSize *= 2) {
-    // See bug 800612. We originally had | repeat = min(maxBufferSize, 20) |
-    // and a real bug was only caught on Windows and not on Linux due to rand()
-    // producing different values. In that case, the minimum value by which to replace
-    // this 20 to reproduce the bug on Linux, was 25. Replacing it with 64 should give
-    // us some comfort margin.
-    int repeat = std::min(maxBufferSize, 64);
-    for (int i = 0; i < repeat; i++) {
-      size_t size = RandomInteger<size_t>(0, maxBufferSize);
-      MakeRandomVector(v, size);
-      b.BufferData(v.Elements(), size);
-      CheckValidateAllTypes(b, 0, size);
-
-      for (int j = 0; j < 16; j++) {
-        for (int bufferSubDataCalls = 1; bufferSubDataCalls <= 8; bufferSubDataCalls *= 2) {
-          for (int validateCalls = 1; validateCalls <= 8; validateCalls *= 2) {
-
-            size_t offset = 0, subsize = 0;
-
-            for (int k = 0; k < bufferSubDataCalls; k++) {
-              offset = RandomInteger<size_t>(0, size);
-              subsize = RandomInteger<size_t>(0, size - offset);
-              MakeRandomVector(vsub, subsize);
-              b.BufferSubData(offset, vsub.Elements(), subsize);
-            }
-
-            for (int k = 0; k < validateCalls; k++) {
-              offset = RandomInteger<size_t>(0, size);
-              subsize = RandomInteger<size_t>(0, size - offset);
-              CheckValidateAllTypes(b, offset, subsize);
-            }
-          } // validateCalls
-        } // bufferSubDataCalls
-      } // j
-    } // i
-  } // maxBufferSize
-}
-
--- a/dom/canvas/gtest/moz.build
+++ b/dom/canvas/gtest/moz.build
@@ -2,22 +2,18 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Canvas: 2D')
 
-with Files('*WebGL*'):
-    BUG_COMPONENT = ('Core', 'Canvas: WebGL')
-
 UNIFIED_SOURCES += [
     'TestImageBitmapColorUtils.cpp',
-    'TestWebGLElementArrayCache.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/canvas',
     '/media/libyuv/libyuv/include'
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -120,17 +120,16 @@ UNIFIED_SOURCES += [
     'WebGLContextLossHandler.cpp',
     'WebGLContextState.cpp',
     'WebGLContextTextures.cpp',
     'WebGLContextUnchecked.cpp',
     'WebGLContextUtils.cpp',
     'WebGLContextValidate.cpp',
     'WebGLContextVertexArray.cpp',
     'WebGLContextVertices.cpp',
-    'WebGLElementArrayCache.cpp',
     'WebGLExtensionBase.cpp',
     'WebGLExtensionBlendMinMax.cpp',
     'WebGLExtensionColorBufferFloat.cpp',
     'WebGLExtensionColorBufferHalfFloat.cpp',
     'WebGLExtensionCompressedTextureASTC.cpp',
     'WebGLExtensionCompressedTextureATC.cpp',
     'WebGLExtensionCompressedTextureES3.cpp',
     'WebGLExtensionCompressedTextureETC1.cpp',
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -4953,17 +4953,16 @@ fail-if = (os == 'mac') || (os == 'win')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__rendering__clear-srgb-color-buffer.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__rendering__clipping-wide-points.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__rendering__draw-buffers.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__rendering__element-index-uint.html]
-fail-if = (os != 'win')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__rendering__framebuffer-completeness-unaffected.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__rendering__framebuffer-unsupported.html]
 fail-if = (os == 'mac')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__rendering__fs-color-type-mismatch-color-buffer-type.html]
 fail-if = (os == 'mac') || (os == 'win')
@@ -6120,29 +6119,26 @@ skip-if = (os == 'android' || os == 'lin
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__buffer-data-array-buffer-delete.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__buffer-uninitialized.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__element-array-buffer-delete-recreate.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__index-validation-copies-indices.html]
-fail-if = (os != 'win')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__index-validation-crash-with-buffer-sub-data.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__index-validation-large-buffer.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__index-validation-verifies-too-many-indices.html]
-fail-if = (os != 'win')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__index-validation-with-resized-buffer.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__buffers__index-validation.html]
-fail-if = (os != 'win')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__canvas__buffer-offscreen-test.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__canvas__buffer-preserve-test.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__canvas__canvas-test.html]
 skip-if = (os == 'win') || (os == 'android' || os == 'linux')
 [generated/test_2_conformance__canvas__canvas-zero-size.html]
@@ -7254,17 +7250,16 @@ skip-if = (os == 'android' || os == 'lin
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__rendering__culling.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__rendering__default-texture-draw-bug.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__rendering__draw-arrays-out-of-bounds.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__rendering__draw-elements-out-of-bounds.html]
-fail-if = (os != 'win')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__rendering__draw-with-changing-start-vertex-bug.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__rendering__framebuffer-switch.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__rendering__framebuffer-texture-switch.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__rendering__gl-clear.html]
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -66,30 +66,16 @@ skip-if = 1
 # Timing out
 [generated/test_conformance__uniforms__uniform-default-values.html]
 # Timeout on Windows, crash on Android/Linux.
 skip-if = (os == 'android') || (os == 'linux') || (os == 'win')
 [generated/test_conformance__ogles__GL__mat3__mat3_001_to_006.html]
 # Timeout on D3D11
 skip-if = (os == 'win')
 
-####################
-# Tests expect conservative index validation, which we skip on WebGL 2.
-# ANGLE still provides it though, so they pass on windows.
-[generated/test_2_conformance__rendering__draw-elements-out-of-bounds.html]
-fail-if = (os != 'win')
-[generated/test_2_conformance__buffers__index-validation-copies-indices.html]
-fail-if = (os != 'win')
-[generated/test_2_conformance__buffers__index-validation.html]
-fail-if = (os != 'win')
-[generated/test_2_conformance__buffers__index-validation-verifies-too-many-indices.html]
-fail-if = (os != 'win')
-[generated/test_2_conformance2__rendering__element-index-uint.html]
-fail-if = (os != 'win')
-
 ########################################################################
 # Complicated
 
 [generated/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html]
 fail-if = (os == 'mac' && os_version == '10.6')
 # Asserts on 'B2G ICS Emulator Debug' and linux debug. Crashes on Android.
 skip-if = (os == 'b2g') || (os == 'linux') || (os == 'android')
 
--- a/dom/events/MessageEvent.cpp
+++ b/dom/events/MessageEvent.cpp
@@ -3,36 +3,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
+#include "mozilla/dom/workers/bindings/ServiceWorker.h"
 
 #include "mozilla/HoldDropJSObjects.h"
 #include "jsapi.h"
 #include "nsGlobalWindow.h" // So we can assign an nsGlobalWindow* to mWindowSource
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(MessageEvent)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessageEvent, Event)
   tmp->mData.setUndefined();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowSource)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPortSource)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorkerSource)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessageEvent, Event)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowSource)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPortSource)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerSource)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MessageEvent, Event)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessageEvent)
@@ -79,95 +82,100 @@ MessageEvent::GetOrigin(nsAString& aOrig
 
 void
 MessageEvent::GetLastEventId(nsAString& aLastEventId) const
 {
   aLastEventId = mLastEventId;
 }
 
 void
-MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const
+MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePortOrServiceWorker>& aValue) const
 {
   if (mWindowSource) {
-    aValue.SetValue().SetAsWindowProxy() = mWindowSource->GetOuterWindow();
+    aValue.SetValue().SetAsWindowProxy() = mWindowSource;
   } else if (mPortSource) {
     aValue.SetValue().SetAsMessagePort() = mPortSource;
+  } else if (mServiceWorkerSource) {
+    aValue.SetValue().SetAsServiceWorker() = mServiceWorkerSource;
   }
 }
 
 /* static */ already_AddRefed<MessageEvent>
 MessageEvent::Constructor(const GlobalObject& aGlobal,
                           const nsAString& aType,
                           const MessageEventInit& aParam,
                           ErrorResult& aRv)
 {
   nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
-  return Constructor(t, aType, aParam, aRv);
+  return Constructor(t, aType, aParam);
 }
 
 /* static */ already_AddRefed<MessageEvent>
 MessageEvent::Constructor(EventTarget* aEventTarget,
                           const nsAString& aType,
-                          const MessageEventInit& aParam,
-                          ErrorResult& aRv)
+                          const MessageEventInit& aParam)
 {
   RefPtr<MessageEvent> event = new MessageEvent(aEventTarget, nullptr, nullptr);
 
   event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
   bool trusted = event->Init(aEventTarget);
   event->SetTrusted(trusted);
 
   event->mData = aParam.mData;
 
   mozilla::HoldJSObjects(event.get());
 
   event->mOrigin = aParam.mOrigin;
   event->mLastEventId = aParam.mLastEventId;
 
   if (!aParam.mSource.IsNull()) {
-    if (aParam.mSource.Value().IsWindow()) {
-      event->mWindowSource = aParam.mSource.Value().GetAsWindow()->AsInner();
+    if (aParam.mSource.Value().IsWindowProxy()) {
+      event->mWindowSource = aParam.mSource.Value().GetAsWindowProxy();
+    } else if (aParam.mSource.Value().IsMessagePort()) {
+      event->mPortSource = aParam.mSource.Value().GetAsMessagePort();
     } else {
-      event->mPortSource = aParam.mSource.Value().GetAsMessagePort();
+      event->mServiceWorkerSource = aParam.mSource.Value().GetAsServiceWorker();
     }
 
-    MOZ_ASSERT(event->mWindowSource || event->mPortSource);
+    MOZ_ASSERT(event->mWindowSource || event->mPortSource || event->mServiceWorkerSource);
   }
 
   event->mPorts.AppendElements(aParam.mPorts);
 
   return event.forget();
 }
 
 void
 MessageEvent::InitMessageEvent(JSContext* aCx, const nsAString& aType,
                                bool aCanBubble, bool aCancelable,
                                JS::Handle<JS::Value> aData,
                                const nsAString& aOrigin,
                                const nsAString& aLastEventId,
-                               const Nullable<WindowProxyOrMessagePort>& aSource,
+                               const Nullable<WindowProxyOrMessagePortOrServiceWorker>& aSource,
                                const Sequence<OwningNonNull<MessagePort>>& aPorts)
 {
   NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
 
   Event::InitEvent(aType, aCanBubble, aCancelable);
   mData = aData;
   mozilla::HoldJSObjects(this);
   mOrigin = aOrigin;
   mLastEventId = aLastEventId;
 
   mWindowSource = nullptr;
   mPortSource = nullptr;
+  mServiceWorkerSource = nullptr;
 
   if (!aSource.IsNull()) {
     if (aSource.Value().IsWindowProxy()) {
-      auto* windowProxy = aSource.Value().GetAsWindowProxy();
-      mWindowSource = windowProxy ? windowProxy->GetCurrentInnerWindow() : nullptr;
+      mWindowSource = aSource.Value().GetAsWindowProxy();
+    } else if (aSource.Value().IsMessagePort()) {
+      mPortSource = &aSource.Value().GetAsMessagePort();
     } else {
-      mPortSource = &aSource.Value().GetAsMessagePort();
+      mServiceWorkerSource = &aSource.Value().GetAsServiceWorker();
     }
   }
 
   mPorts.Clear();
   mPorts.AppendElements(aPorts);
   MessageEventBinding::ClearCachedPortsValue(this);
 }
 
--- a/dom/events/MessageEvent.h
+++ b/dom/events/MessageEvent.h
@@ -11,18 +11,22 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
 namespace dom {
 
 struct MessageEventInit;
 class MessagePort;
-class OwningWindowProxyOrMessagePort;
-class WindowProxyOrMessagePort;
+class OwningWindowProxyOrMessagePortOrServiceWorker;
+class WindowProxyOrMessagePortOrServiceWorker;
+
+namespace workers {
+class ServiceWorker;
+}
 
 /**
  * Implements the MessageEvent event, used for cross-document messaging and
  * server-sent events.
  *
  * See http://www.whatwg.org/specs/web-apps/current-work/#messageevent for
  * further details.
  */
@@ -40,47 +44,47 @@ public:
   NS_FORWARD_TO_EVENT
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
                ErrorResult& aRv);
   void GetOrigin(nsAString&) const;
   void GetLastEventId(nsAString&) const;
-  void GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const;
+  void GetSource(Nullable<OwningWindowProxyOrMessagePortOrServiceWorker>& aValue) const;
 
   void GetPorts(nsTArray<RefPtr<MessagePort>>& aPorts);
 
   static already_AddRefed<MessageEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const MessageEventInit& aEventInit,
               ErrorResult& aRv);
 
   static already_AddRefed<MessageEvent>
   Constructor(EventTarget* aEventTarget,
               const nsAString& aType,
-              const MessageEventInit& aEventInit,
-              ErrorResult& aRv);
+              const MessageEventInit& aEventInit);
 
   void InitMessageEvent(JSContext* aCx, const nsAString& aType, bool aCanBubble,
                         bool aCancelable, JS::Handle<JS::Value> aData,
                         const nsAString& aOrigin, const nsAString& aLastEventId,
-                        const Nullable<WindowProxyOrMessagePort>& aSource,
+                        const Nullable<WindowProxyOrMessagePortOrServiceWorker>& aSource,
                         const Sequence<OwningNonNull<MessagePort>>& aPorts);
 
 protected:
   ~MessageEvent();
 
 private:
   JS::Heap<JS::Value> mData;
   nsString mOrigin;
   nsString mLastEventId;
-  RefPtr<nsPIDOMWindowInner> mWindowSource;
+  RefPtr<nsPIDOMWindowOuter> mWindowSource;
   RefPtr<MessagePort> mPortSource;
+  RefPtr<workers::ServiceWorker> mServiceWorkerSource;
 
   nsTArray<RefPtr<MessagePort>> mPorts;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_MessageEvent_h_
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -325,23 +325,16 @@ const kEventConstructors = {
                                                          var e = document.createEvent("scrollareaevent");
                                                          e.initScrollAreaEvent(aName, aProps.bubbles, aProps.cancelable,
                                                                                aProps.view, aProps.details,
                                                                                aProps.x || 0.0, aProps.y || 0.0,
                                                                                aProps.width || 0.0, aProps.height || 0.0);
                                                          return e;
                                                        },
                                              },
-  ServiceWorkerMessageEvent:                 { create: function (aName, aProps) {
-                                                         var e = new ServiceWorkerMessageEvent("serviceworkermessageevent", { bubbles: aProps.bubbles,
-                                                             cancelable: aProps.cancelable, data: aProps.data, origin: aProps.origin,
-                                                             lastEventId: aProps.lastEventId, source: aProps.source });
-                                                         return e;
-                                                       },
-                                             },
   SimpleGestureEvent:                        { create: function (aName, aProps) {
                                                          var e = document.createEvent("simplegestureevent");
                                                          e.initSimpleGestureEvent(aName, aProps.bubbles, aProps.cancelable,
                                                                                   aProps.view, aProps.detail,
                                                                                   aProps.screenX, aProps.screenY,
                                                                                   aProps.clientX, aProps.clientY,
                                                                                   aProps.ctrlKey, aProps.altKey, aProps.shiftKey, aProps.metaKey,
                                                                                   aProps.button, aProps.relatedTarget,
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -830,18 +830,16 @@ var interfaceNamesInGlobalScope =
     "ScrollAreaEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Selection",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorker",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorkerContainer",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "ServiceWorkerMessageEvent",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorkerRegistration",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "ScopedCredential", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "ScopedCredentialInfo", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ShadowRoot", // Bogus, but the test harness forces it on.  See bug 1159768.
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/MessageEvent.webidl
+++ b/dom/webidl/MessageEvent.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * For more information on this interface, please see
- * http://www.whatwg.org/specs/web-apps/current-work/#messageevent
+ * https://html.spec.whatwg.org/#messageevent
  */
 
 [Constructor(DOMString type, optional MessageEventInit eventInitDict),
  Exposed=(Window,Worker,System)]
 interface MessageEvent : Event {
   /**
    * Custom data associated with this event.
    */
@@ -17,42 +17,44 @@ interface MessageEvent : Event {
   readonly attribute any data;
 
   /**
    * The origin of the site from which this event originated, which is the
    * scheme, ":", and if the URI has a host, "//" followed by the
    * host, and if the port is not the default for the given scheme,
    * ":" followed by that port.  This value does not have a trailing slash.
    */
-  readonly attribute DOMString origin;
+  readonly attribute USVString origin;
 
   /**
    * The last event ID string of the event source, for server-sent DOM events; this
    * value is the empty string for cross-origin messaging.
    */
   readonly attribute DOMString lastEventId;
 
   /**
    * The window or port which originated this event.
    */
-  readonly attribute (WindowProxy or MessagePort)? source;
+  readonly attribute MessageEventSource? source;
 
   /**
    * Initializes this event with the given data, in a manner analogous to
    * the similarly-named method on the nsIDOMEvent interface, also setting the
    * data, origin, source, and lastEventId attributes of this appropriately.
    */
   [Pure, Cached, Frozen]
   readonly attribute sequence<MessagePort> ports;
 
   void initMessageEvent(DOMString type, boolean bubbles, boolean cancelable,
                         any data, DOMString origin, DOMString lastEventId,
-                        (WindowProxy or MessagePort)? source,
+                        MessageEventSource? source,
                         sequence<MessagePort> ports);
 };
 
 dictionary MessageEventInit : EventInit {
   any data = null;
   DOMString origin = "";
   DOMString lastEventId = "";
-  (Window or MessagePort)? source = null;
+  MessageEventSource? source = null;
   sequence<MessagePort> ports = [];
 };
+
+typedef (WindowProxy or MessagePort or ServiceWorker) MessageEventSource;
deleted file mode 100644
--- a/dom/webidl/ServiceWorkerMessageEvent.webidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * The origin of this IDL file is
- * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
- *
- */
-
-[Pref="dom.serviceWorkers.enabled",
- Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict),
- Exposed=Window]
-interface ServiceWorkerMessageEvent : Event {
-  /**
-   * Custom data associated with this event.
-   */
-  readonly attribute any data;
-
-  /**
-   * The origin of the site from which this event originated.
-   */
-  readonly attribute DOMString origin;
-
-  /**
-   * The last event ID string of the event source.
-   */
-  readonly attribute DOMString lastEventId;
-
-  /**
-   * The service worker or port which originated this event.
-   * FIXME: Use SameOject after IDL spec is updated
-   * https://bugzilla.mozilla.org/show_bug.cgi?id=1196097
-   */
-  [Constant] readonly attribute (ServiceWorker or MessagePort)? source;
-
-  [Constant, Cached, Frozen]
-  readonly attribute sequence<MessagePort> ports;
-};
-
-dictionary ServiceWorkerMessageEventInit : EventInit
-{
-  any data = null;
-  DOMString origin = "";
-  DOMString lastEventId = "";
-  (ServiceWorker or MessagePort)? source = null;
-  sequence<MessagePort> ports = [];
-};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -1082,17 +1082,16 @@ GENERATED_EVENTS_WEBIDL_FILES = [
     'PluginCrashedEvent.webidl',
     'PopStateEvent.webidl',
     'PopupBlockedEvent.webidl',
     'PresentationConnectionAvailableEvent.webidl',
     'PresentationConnectionCloseEvent.webidl',
     'ProgressEvent.webidl',
     'RecordErrorEvent.webidl',
     'ScrollViewChangeEvent.webidl',
-    'ServiceWorkerMessageEvent.webidl',
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
     'TCPServerSocketEvent.webidl',
     'TCPSocketErrorEvent.webidl',
     'TCPSocketEvent.webidl',
     'TrackEvent.webidl',
     'UDPMessageEvent.webidl',
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -5,18 +5,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 #include "ServiceWorkerClient.h"
 #include "ServiceWorkerContainer.h"
 
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/Navigator.h"
-#include "mozilla/dom/ServiceWorkerMessageEvent.h"
-#include "mozilla/dom/ServiceWorkerMessageEventBinding.h"
 #include "nsGlobalWindow.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIDocument.h"
 #include "ServiceWorker.h"
 #include "ServiceWorkerPrivate.h"
 #include "WorkerPrivate.h"
 
 using namespace mozilla;
@@ -177,17 +175,17 @@ private:
     JS::Rooted<JS::Value> messageData(aCx);
     ErrorResult rv;
     Read(aTargetContainer->GetParentObject(), aCx, &messageData, rv);
     if (NS_WARN_IF(rv.Failed())) {
       xpc::Throw(aCx, rv.StealNSResult());
       return NS_ERROR_FAILURE;
     }
 
-    RootedDictionary<ServiceWorkerMessageEventInit> init(aCx);
+    RootedDictionary<MessageEventInit> init(aCx);
 
     nsCOMPtr<nsIPrincipal> principal = aTargetContainer->GetParentObject()->PrincipalOrNull();
     NS_WARNING_ASSERTION(principal, "Why is the principal null here?");
 
     bool isNullPrincipal = false;
     bool isSystemPrincipal = false;
     if (principal) {
       isNullPrincipal = principal->GetIsNullPrincipal();
@@ -207,20 +205,19 @@ private:
     if (serviceWorker) {
       init.mSource.SetValue().SetAsServiceWorker() = serviceWorker;
     }
 
     if (!TakeTransferredPortsAsSequence(init.mPorts)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    RefPtr<ServiceWorkerMessageEvent> event =
-      ServiceWorkerMessageEvent::Constructor(aTargetContainer,
-                                             NS_LITERAL_STRING("message"),
-                                             init);
+    RefPtr<MessageEvent> event =
+      MessageEvent::Constructor(aTargetContainer, NS_LITERAL_STRING("message"),
+                                init);
 
     event->SetTrusted(true);
     bool status = false;
     aTargetContainer->DispatchEvent(static_cast<dom::Event*>(event.get()),
                                     &status);
 
     if (!status) {
       return NS_ERROR_FAILURE;
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -98,16 +98,17 @@ static const char* const sExtensionNames
     "GL_ARB_geometry_shader4",
     "GL_ARB_half_float_pixel",
     "GL_ARB_instanced_arrays",
     "GL_ARB_internalformat_query",
     "GL_ARB_invalidate_subdata",
     "GL_ARB_map_buffer_range",
     "GL_ARB_occlusion_query2",
     "GL_ARB_pixel_buffer_object",
+    "GL_ARB_robust_buffer_access_behavior",
     "GL_ARB_robustness",
     "GL_ARB_sampler_objects",
     "GL_ARB_seamless_cube_map",
     "GL_ARB_shader_texture_lod",
     "GL_ARB_sync",
     "GL_ARB_texture_compression",
     "GL_ARB_texture_float",
     "GL_ARB_texture_non_power_of_two",
@@ -152,16 +153,18 @@ static const char* const sExtensionNames
     "GL_EXT_texture_storage",
     "GL_EXT_timer_query",
     "GL_EXT_transform_feedback",
     "GL_EXT_unpack_subimage",
     "GL_IMG_read_format",
     "GL_IMG_texture_compression_pvrtc",
     "GL_IMG_texture_npot",
     "GL_KHR_debug",
+    "GL_KHR_robust_buffer_access_behavior",
+    "GL_KHR_robustness",
     "GL_KHR_texture_compression_astc_hdr",
     "GL_KHR_texture_compression_astc_ldr",
     "GL_NV_draw_instanced",
     "GL_NV_fence",
     "GL_NV_framebuffer_blit",
     "GL_NV_geometry_program4",
     "GL_NV_half_float",
     "GL_NV_instanced_arrays",
@@ -1001,16 +1004,21 @@ GLContext::InitWithPrefixImpl(const char
     {
         NS_ERROR("GLContext requires support for framebuffer objects.");
         return false;
     }
     MOZ_RELEASE_ASSERT(mSymbols.fBindFramebuffer, "GFX: mSymbols.fBindFramebuffer zero or not set.");
 
     ////////////////
 
+    const auto err = mSymbols.fGetError();
+    MOZ_RELEASE_ASSERT(!err);
+    if (err)
+        return false;
+
     LoadMoreSymbols(prefix, trygl);
 
     ////////////////////////////////////////////////////////////////////////////
 
     raw_fGetIntegerv(LOCAL_GL_VIEWPORT, mViewportRect);
     raw_fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mScissorRect);
     raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize);
@@ -1138,40 +1146,43 @@ GLContext::LoadMoreSymbols(const char* p
                                                               GLFeature feature)
     {
         const bool useCore = this->IsFeatureProvidedByCoreSymbols(feature);
         const auto list = useCore ? coreList : extList;
         return fnLoadForFeature(list, feature);
     };
 
     if (IsSupported(GLFeature::robustness)) {
-        bool hasRobustness = false;
-
-        if (!hasRobustness && IsExtensionSupported(ARB_robustness)) {
-            const SymLoadStruct symbols[] = {
-                { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusARB", nullptr } },
-                END_SYMBOLS
-            };
-            if (fnLoadForExt(symbols, ARB_robustness)) {
-                hasRobustness = true;
+        const auto resetStrategy = GetIntAs<GLuint>(LOCAL_GL_RESET_NOTIFICATION_STRATEGY);
+        if (resetStrategy != LOCAL_GL_LOSE_CONTEXT_ON_RESET) {
+            NS_WARNING("Robustness supported, strategy is not LOSE_CONTEXT_ON_RESET!");
+            if (ShouldSpew()) {
+                const bool isDisabled = (resetStrategy == LOCAL_GL_NO_RESET_NOTIFICATION);
+                printf_stderr("Strategy: %s (0x%04x)",
+                              (isDisabled ? "disabled" : "unrecognized"),
+                              resetStrategy);
             }
+            MarkUnsupported(GLFeature::robustness);
         }
-
-        if (!hasRobustness && IsExtensionSupported(EXT_robustness)) {
-            const SymLoadStruct symbols[] = {
-                { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusEXT", nullptr } },
-                END_SYMBOLS
-            };
-            if (fnLoadForExt(symbols, EXT_robustness)) {
-                hasRobustness = true;
-            }
-        }
-
-        if (!hasRobustness) {
-            MarkUnsupported(GLFeature::robustness);
+    }
+    if (IsSupported(GLFeature::robustness)) {
+        const SymLoadStruct symbols[] = {
+            { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatus",
+                                                                "GetGraphicsResetStatusARB",
+                                                                "GetGraphicsResetStatusKHR",
+                                                                "GetGraphicsResetStatusEXT",
+                                                                nullptr } },
+            END_SYMBOLS
+        };
+        if (fnLoadForFeature(symbols, GLFeature::robustness)) {
+            const auto status = mSymbols.fGetGraphicsResetStatus();
+            MOZ_ALWAYS_TRUE(!status);
+
+            const auto err = mSymbols.fGetError();
+            MOZ_ALWAYS_TRUE(!err);
         }
     }
 
     if (IsSupported(GLFeature::sync)) {
         const SymLoadStruct symbols[] = {
             { (PRFuncPtr*) &mSymbols.fFenceSync,      { "FenceSync",      nullptr } },
             { (PRFuncPtr*) &mSymbols.fIsSync,         { "IsSync",         nullptr } },
             { (PRFuncPtr*) &mSymbols.fDeleteSync,     { "DeleteSync",     nullptr } },
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -116,16 +116,17 @@ enum class GLFeature {
     prim_restart,
     prim_restart_fixed,
     query_counter,
     query_objects,
     query_time_elapsed,
     read_buffer,
     renderbuffer_color_float,
     renderbuffer_color_half_float,
+    robust_buffer_access_behavior,
     robustness,
     sRGB_framebuffer,
     sRGB_texture,
     sampler_objects,
     seamless_cube_map_opt_in,
     shader_texture_lod,
     split_framebuffer,
     standard_derivatives,
@@ -195,20 +196,16 @@ class GLContext
     : public GLLibraryLoader
     , public GenericAtomicRefCounted
     , public SupportsWeakPtr<GLContext>
 {
 public:
     MOZ_DECLARE_WEAKREFERENCE_TYPENAME(GLContext)
 
 // -----------------------------------------------------------------------------
-// basic enums
-public:
-
-// -----------------------------------------------------------------------------
 // basic getters
 public:
 
     /**
      * Returns true if the context is using ANGLE. This should only be overridden
      * for an ANGLE implementation.
      */
     virtual bool IsANGLE() const {
@@ -429,16 +426,17 @@ public:
         ARB_geometry_shader4,
         ARB_half_float_pixel,
         ARB_instanced_arrays,
         ARB_internalformat_query,
         ARB_invalidate_subdata,
         ARB_map_buffer_range,
         ARB_occlusion_query2,
         ARB_pixel_buffer_object,
+        ARB_robust_buffer_access_behavior,
         ARB_robustness,
         ARB_sampler_objects,
         ARB_seamless_cube_map,
         ARB_shader_texture_lod,
         ARB_sync,
         ARB_texture_compression,
         ARB_texture_float,
         ARB_texture_non_power_of_two,
@@ -483,16 +481,18 @@ public:
         EXT_texture_storage,
         EXT_timer_query,
         EXT_transform_feedback,
         EXT_unpack_subimage,
         IMG_read_format,
         IMG_texture_compression_pvrtc,
         IMG_texture_npot,
         KHR_debug,
+        KHR_robust_buffer_access_behavior,
+        KHR_robustness,
         KHR_texture_compression_astc_hdr,
         KHR_texture_compression_astc_ldr,
         NV_draw_instanced,
         NV_fence,
         NV_framebuffer_blit,
         NV_geometry_program4,
         NV_half_float,
         NV_instanced_arrays,
@@ -566,25 +566,16 @@ private:
      */
     void MarkUnsupported(GLFeature feature);
 
     /**
      * Is this feature supported using the core (unsuffixed) symbols?
      */
     bool IsFeatureProvidedByCoreSymbols(GLFeature feature);
 
-// -----------------------------------------------------------------------------
-// Robustness handling
-private:
-    /**
-     * The derived class is expected to provide information on whether or not it
-     * supports robustness.
-     */
-    virtual bool SupportsRobustness() const = 0;
-
 public:
 // -----------------------------------------------------------------------------
 // Error handling
     static const char* GLErrorToString(GLenum aError) {
         switch (aError) {
             case LOCAL_GL_INVALID_ENUM:
                 return "GL_INVALID_ENUM";
             case LOCAL_GL_INVALID_VALUE:
--- a/gfx/gl/GLContextCGL.h
+++ b/gfx/gl/GLContextCGL.h
@@ -50,18 +50,16 @@ public:
     virtual bool IsCurrent() override;
 
     virtual GLenum GetPreferredARGB32Format() const override;
 
     virtual bool SetupLookupFunction() override;
 
     virtual bool IsDoubleBuffered() const override;
 
-    virtual bool SupportsRobustness() const override { return false; }
-
     virtual bool SwapBuffers() override;
 
     virtual void GetWSIInfo(nsCString* const out) const override;
 };
 
 } // namespace gl
 } // namespace mozilla
 
--- a/gfx/gl/GLContextEAGL.h
+++ b/gfx/gl/GLContextEAGL.h
@@ -46,18 +46,16 @@ public:
     virtual bool MakeCurrentImpl(bool aForce) override;
 
     virtual bool IsCurrent() override;
 
     virtual bool SetupLookupFunction() override;
 
     virtual bool IsDoubleBuffered() const override;
 
-    virtual bool SupportsRobustness() const override { return false; }
-
     virtual bool SwapBuffers() override;
 
     virtual void GetWSIInfo(nsCString* const out) const override;
 
     virtual GLuint GetDefaultFramebuffer() override {
         return mBackbufferFB;
     }
 
--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -53,20 +53,16 @@ public:
     virtual bool IsDoubleBuffered() const override {
         return mIsDoubleBuffered;
     }
 
     void SetIsDoubleBuffered(bool aIsDB) {
         mIsDoubleBuffered = aIsDB;
     }
 
-    virtual bool SupportsRobustness() const override {
-        return sEGLLibrary.HasRobustness();
-    }
-
     virtual bool IsANGLE() const override {
         return sEGLLibrary.IsANGLE();
     }
 
     virtual bool IsWARP() const override {
         return sEGLLibrary.IsWARP();
     }
 
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -528,23 +528,35 @@ static const FeatureInfo sFeatureInfoArr
         {
             GLContext::ARB_texture_float,
             GLContext::EXT_color_buffer_float,
             GLContext::EXT_color_buffer_half_float,
             GLContext::Extensions_End
         }
     },
     {
+        "robust_buffer_access_behavior",
+        GLVersion::NONE,
+        GLESVersion::NONE,
+        GLContext::Extension_None,
+        {
+            GLContext::ARB_robust_buffer_access_behavior,
+            GLContext::KHR_robust_buffer_access_behavior,
+            GLContext::Extensions_End
+        }
+    },
+    {
         "robustness",
         GLVersion::NONE,
         GLESVersion::NONE,
         GLContext::Extension_None,
         {
             GLContext::ARB_robustness,
             GLContext::EXT_robustness,
+            GLContext::KHR_robustness,
             GLContext::Extensions_End
         }
     },
     {
         "sRGB_framebuffer",
         GLVersion::GL3,
         GLESVersion::ES3,
         GLContext::ARB_framebuffer_sRGB,
--- a/gfx/gl/GLContextGLX.h
+++ b/gfx/gl/GLContextGLX.h
@@ -51,18 +51,16 @@ public:
     virtual bool MakeCurrentImpl(bool aForce) override;
 
     virtual bool IsCurrent() override;
 
     virtual bool SetupLookupFunction() override;
 
     virtual bool IsDoubleBuffered() const override;
 
-    virtual bool SupportsRobustness() const override;
-
     virtual bool SwapBuffers() override;
 
     virtual void GetWSIInfo(nsCString* const out) const override;
 
     // Overrides the current GLXDrawable backing the context and makes the
     // context current.
     bool OverrideDrawable(GLXDrawable drawable);
 
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -79,17 +79,17 @@ static bool
 CreateConfig(EGLConfig* aConfig);
 
 // append three zeros at the end of attribs list to work around
 // EGL implementation bugs that iterate until they find 0, instead of
 // EGL_NONE. See bug 948406.
 #define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
      LOCAL_EGL_NONE, 0, 0, 0
 
-static EGLint gTerminationAttribs[] = {
+static EGLint kTerminationAttribs[] = {
     EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
 };
 
 static int
 next_power_of_two(int v)
 {
     v--;
     v |= v >> 1;
@@ -477,41 +477,50 @@ GLContextEGL::CreateGLContext(CreateCont
         *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_ES");
         NS_WARNING("Failed to bind API to GLES!");
         return nullptr;
     }
 
     EGLContext eglShareContext = shareContext ? shareContext->mContext
                                               : EGL_NO_CONTEXT;
 
-    nsTArray<EGLint> contextAttribs;
+    std::vector<EGLint> contextAttribs;
 
-    contextAttribs.AppendElement(LOCAL_EGL_CONTEXT_CLIENT_VERSION);
+    contextAttribs.push_back(LOCAL_EGL_CONTEXT_CLIENT_VERSION);
     if (flags & CreateContextFlags::PREFER_ES3)
-        contextAttribs.AppendElement(3);
+        contextAttribs.push_back(3);
     else
-        contextAttribs.AppendElement(2);
+        contextAttribs.push_back(2);
 
-    if (sEGLLibrary.HasRobustness()) {
-//    contextAttribs.AppendElement(LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT);
-//    contextAttribs.AppendElement(LOCAL_EGL_TRUE);
+    if (flags & CreateContextFlags::PREFER_ROBUSTNESS) {
+        if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_create_context)) {
+            contextAttribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
+            contextAttribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
+            contextAttribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR);
+            contextAttribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
+        } else if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::EXT_create_context_robustness)) {
+            contextAttribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
+            contextAttribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT);
+            contextAttribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
+            contextAttribs.push_back(LOCAL_EGL_TRUE);
+        }
     }
 
-    for (size_t i = 0; i < MOZ_ARRAY_LENGTH(gTerminationAttribs); i++) {
-      contextAttribs.AppendElement(gTerminationAttribs[i]);
+    for (const auto& cur : kTerminationAttribs) {
+        contextAttribs.push_back(cur);
     }
 
     EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
                                                     config,
                                                     eglShareContext,
-                                                    contextAttribs.Elements());
+                                                    contextAttribs.data());
     if (!context && shareContext) {
         shareContext = nullptr;
         context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), config, EGL_NO_CONTEXT,
-                                             contextAttribs.Elements());
+                                             contextAttribs.data());
     }
     if (!context) {
         *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_CREATE");
         NS_WARNING("Failed to create EGLContext!");
         return nullptr;
     }
 
     RefPtr<GLContextEGL> glContext = new GLContextEGL(flags, caps, shareContext,
@@ -542,18 +551,18 @@ TRY_AGAIN_POWER_OF_TWO:
     if (bindToTextureFormat != LOCAL_EGL_NONE) {
         pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
         pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
 
         pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
         pbattrs.AppendElement(bindToTextureFormat);
     }
 
-    for (size_t i = 0; i < MOZ_ARRAY_LENGTH(gTerminationAttribs); i++) {
-      pbattrs.AppendElement(gTerminationAttribs[i]);
+    for (const auto& cur : kTerminationAttribs) {
+        pbattrs.AppendElement(cur);
     }
 
     surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]);
     if (!surface) {
         if (!is_power_of_two(pbsize.width) ||
             !is_power_of_two(pbsize.height))
         {
             if (!is_power_of_two(pbsize.width))
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -506,19 +506,21 @@ GLContextGLX::CreateGLContext(CreateCont
 
     do {
         error = false;
 
         GLXContext glxContext = shareContext ? shareContext->mContext : nullptr;
         if (glx.HasCreateContextAttribs()) {
             AutoTArray<int, 11> attrib_list;
             if (glx.HasRobustness()) {
-                int robust_attribs[] = {
-                    LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
-                    LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB,
+                const int robust_attribs[] = {
+                    LOCAL_GLX_CONTEXT_FLAGS_ARB,
+                    LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
+                    LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
+                    LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB,
                 };
                 attrib_list.AppendElements(robust_attribs, MOZ_ARRAY_LENGTH(robust_attribs));
             }
             if (profile == ContextProfile::OpenGLCore) {
                 int core_attribs[] = {
                     LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
                     LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB, 2,
                     LOCAL_GLX_CONTEXT_FLAGS_ARB, LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
@@ -658,22 +660,16 @@ GLContextGLX::SetupLookupFunction()
 
 bool
 GLContextGLX::IsDoubleBuffered() const
 {
     return mDoubleBuffered;
 }
 
 bool
-GLContextGLX::SupportsRobustness() const
-{
-    return mGLX->HasRobustness();
-}
-
-bool
 GLContextGLX::SwapBuffers()
 {
     if (!mDoubleBuffered)
         return false;
     mGLX->fSwapBuffers(mDisplay, mDrawable);
     return true;
 }
 
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -357,22 +357,16 @@ GLContextWGL::SetIsDoubleBuffered(bool a
 
 bool
 GLContextWGL::IsDoubleBuffered() const
 {
     return mIsDoubleBuffered;
 }
 
 bool
-GLContextWGL::SupportsRobustness() const
-{
-    return sWGLLib.HasRobustness();
-}
-
-bool
 GLContextWGL::SwapBuffers() {
     if (!mIsDoubleBuffered)
         return false;
     return ::SwapBuffers(mDC);
 }
 
 void
 GLContextWGL::GetWSIInfo(nsCString* const out) const
--- a/gfx/gl/GLContextTypes.h
+++ b/gfx/gl/GLContextTypes.h
@@ -51,15 +51,16 @@ enum class CreateContextFlags : int8_t {
     // Force the use of hardware backed GL, don't allow software implementations.
     FORCE_ENABLE_HARDWARE = 1 << 1,
     /* Don't force discrete GPU to be used (if applicable) */
     ALLOW_OFFLINE_RENDERER =  1 << 2,
     // Ask for ES3 if possible
     PREFER_ES3 = 1 << 3,
 
     NO_VALIDATION = 1 << 4,
+    PREFER_ROBUSTNESS = 1 << 5,
 };
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags)
 
 } /* namespace gl */
 } /* namespace mozilla */
 
 #endif /* GLCONTEXT_TYPES_H_ */
--- a/gfx/gl/GLContextWGL.h
+++ b/gfx/gl/GLContextWGL.h
@@ -48,18 +48,16 @@ public:
     virtual bool MakeCurrentImpl(bool aForce) override;
 
     virtual bool IsCurrent() override;
 
     void SetIsDoubleBuffered(bool aIsDB);
 
     virtual bool IsDoubleBuffered() const override;
 
-    virtual bool SupportsRobustness() const override;
-
     virtual bool SwapBuffers() override;
 
     virtual bool SetupLookupFunction() override;
 
     virtual void GetWSIInfo(nsCString* const out) const override;
 
     HGLRC Context() { return mContext; }
 
--- a/gfx/gl/GLDefs.h
+++ b/gfx/gl/GLDefs.h
@@ -70,19 +70,24 @@
 #define LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE         ((EGLNativeDisplayType)-2)
 #define LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE              ((EGLNativeDisplayType)-3)
 
 // WGL_NV_DX_interop
 #define LOCAL_WGL_ACCESS_READ_ONLY                      0x0000
 #define LOCAL_WGL_ACCESS_READ_WRITE                     0x0001
 #define LOCAL_WGL_ACCESS_WRITE_DISCARD                  0x0002
 
+// GL_KHR_robustness
+#define LOCAL_GL_CONTEXT_ROBUST_ACCESS                  0x90F3
+
 // Others
 #define LOCAL_EGL_PRESERVED_RESOURCES                   0x3030
 #define LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
-#define LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
+#define LOCAL_GL_RESET_NOTIFICATION_STRATEGY            0x8256
+#define LOCAL_GL_LOSE_CONTEXT_ON_RESET                  0x8252
+#define LOCAL_GL_NO_RESET_NOTIFICATION                  0x8261
 #define LOCAL_GL_CONTEXT_LOST                           0x9242
 #define LOCAL_GL_CONTEXT_FLAGS_ARB                      0x2094
 #define LOCAL_GL_CONTEXT_CORE_PROFILE_BIT_ARB           0x00000001
 #define LOCAL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB  0x00000002
 #define LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB          0x00000004
 
 #endif
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -47,17 +47,18 @@ static const char* sEGLExtensionNames[] 
     "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
     "EGL_EXT_create_context_robustness",
     "EGL_KHR_image",
     "EGL_KHR_fence_sync",
     "EGL_ANDROID_native_fence_sync",
     "EGL_ANDROID_image_crop",
     "EGL_ANGLE_platform_angle",
     "EGL_ANGLE_platform_angle_d3d",
-    "EGL_ANGLE_d3d_share_handle_client_buffer"
+    "EGL_ANGLE_d3d_share_handle_client_buffer",
+    "EGL_KHR_create_context",
 };
 
 #if defined(ANDROID)
 
 static PRLibrary* LoadApitraceLibrary()
 {
     // Initialization of gfx prefs here is only needed during the unit tests...
     gfxPrefs::GetSingleton();
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -100,16 +100,17 @@ public:
         EXT_create_context_robustness,
         KHR_image,
         KHR_fence_sync,
         ANDROID_native_fence_sync,
         EGL_ANDROID_image_crop,
         ANGLE_platform_angle,
         ANGLE_platform_angle_d3d,
         ANGLE_d3d_share_handle_client_buffer,
+        KHR_create_context,
         Extensions_Max
     };
 
     bool IsExtensionSupported(EGLExtensions aKnownExtension) const {
         return mAvailableExtensions[aKnownExtension];
     }
 
     void MarkExtensionUnsupported(EGLExtensions aKnownExtension) {
@@ -322,20 +323,16 @@ public:
     bool HasKHRImageTexture2D() {
         return IsExtensionSupported(KHR_gl_texture_2D_image);
     }
 
     bool HasANGLESurfaceD3DTexture2DShareHandle() {
         return IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle);
     }
 
-    bool HasRobustness() const {
-        return IsExtensionSupported(EXT_create_context_robustness);
-    }
-
     bool ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface);
 
     bool EnsureInitialized(bool forceAccel, nsACString* const out_failureId);
 
     void DumpEGLConfig(EGLConfig cfg);
     void DumpEGLConfigs();
 
 private:
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -467,17 +467,17 @@ GLScreenBuffer::AssureBlitted()
     }
 
     mNeedsBlit = false;
 }
 
 void
 GLScreenBuffer::Morph(UniquePtr<SurfaceFactory> newFactory)
 {
-    MOZ_ASSERT(newFactory);
+    MOZ_RELEASE_ASSERT(newFactory, "newFactory must not be null");
     mFactory = Move(newFactory);
 }
 
 bool
 GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size)
 {
     ScopedBindFramebuffer autoFB(mGL);
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -461,16 +461,17 @@ private:
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.border-layers",         LayersAllowBorderLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.text-layers",           LayersAllowTextLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.bullet-layers",         LayersAllowBulletLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.caret-layers",          LayersAllowCaretLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.boxshadow-inset-layers", LayersAllowInsetBoxShadow, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.outline-layers",        LayersAllowOutlineLayers, bool, false);
+  DECL_GFX_PREF(Live, "layers.advanced.image-layers",          LayersAllowImageLayers, bool, false);
   DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled",     LayersAMDSwitchableGfxEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled",         AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
   DECL_GFX_PREF(Live, "layers.bench.enabled",                  LayersBenchEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.bufferrotation.enabled",         BufferRotationEnabled, bool, true);
   DECL_GFX_PREF(Live, "layers.child-process-shutdown",         ChildProcessShutdown, bool, true);
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
   // If MOZ_GFX_OPTIMIZE_MOBILE is defined, we force component alpha off
@@ -623,16 +624,17 @@ private:
 
   DECL_GFX_PREF(Live, "webgl.disabled",                        WebGLDisabled, bool, false);
 
   DECL_GFX_PREF(Live, "webgl.enable-draft-extensions",         WebGLDraftExtensionsEnabled, bool, false);
   DECL_GFX_PREF(Live, "webgl.enable-privileged-extensions",    WebGLPrivilegedExtensionsEnabled, bool, false);
   DECL_GFX_PREF(Live, "webgl.enable-webgl2",                   WebGL2Enabled, bool, true);
   DECL_GFX_PREF(Live, "webgl.force-enabled",                   WebGLForceEnabled, bool, false);
   DECL_GFX_PREF(Once, "webgl.force-layers-readback",           WebGLForceLayersReadback, bool, false);
+  DECL_GFX_PREF(Live, "webgl.force-index-validation",          WebGLForceIndexValidation, bool, false);
   DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false);
   DECL_GFX_PREF(Live, "webgl.max-warnings-per-context",        WebGLMaxWarningsPerContext, uint32_t, 32);
   DECL_GFX_PREF(Live, "webgl.min_capability_mode",             WebGLMinCapabilityMode, bool, false);
   DECL_GFX_PREF(Live, "webgl.msaa-force",                      WebGLForceMSAA, bool, false);
   DECL_GFX_PREF(Live, "webgl.prefer-16bpp",                    WebGLPrefer16bpp, bool, false);
   DECL_GFX_PREF(Live, "webgl.restore-context-when-visible",    WebGLRestoreWhenVisible, bool, true);
   DECL_GFX_PREF(Live, "webgl.allow-immediate-queries",         WebGLImmediateQueries, bool, false);
   DECL_GFX_PREF(Live, "webgl.allow-fb-invalidation",           WebGLFBInvalidation, bool, false);
--- a/gfx/vr/ipc/PVRManager.ipdl
+++ b/gfx/vr/ipc/PVRManager.ipdl
@@ -54,19 +54,16 @@ parent:
   async ResetSensor(uint32_t aDisplayID);
 
   sync GetSensorState(uint32_t aDisplayID) returns(VRHMDSensorState aState);
   sync GetImmediateSensorState(uint32_t aDisplayID) returns(VRHMDSensorState aState);
   sync SetHaveEventListener(bool aHaveEventListener);
 
   async ControllerListenerAdded();
   async ControllerListenerRemoved();
-  // GetControllers synchronously returns the VR controllers that have already been
-  // enumerated by RefreshVRControllers() but does not enumerate new ones.
-  sync GetControllers() returns(VRControllerInfo[] aControllerInfo);
   async CreateVRTestSystem();
   async CreateVRServiceTestDisplay(nsCString aID, uint32_t aPromiseID);
   async CreateVRServiceTestController(nsCString aID, uint32_t aPromiseID);
   async SetDisplayInfoToMockDisplay(uint32_t aDeviceID, VRDisplayInfo aDisplayInfo);
   async SetSensorStateToMockDisplay(uint32_t aDeviceID, VRHMDSensorState aSensorState);
   async NewButtonEventToMockController(uint32_t aDeviceID, long aButton,
                                        bool aPressed);
   async NewAxisMoveEventToMockController(uint32_t aDeviceID, long aAxis,
--- a/gfx/vr/ipc/VRManagerParent.cpp
+++ b/gfx/vr/ipc/VRManagerParent.cpp
@@ -317,24 +317,16 @@ VRManagerParent::RecvControllerListenerR
 {
   VRManager* vm = VRManager::Get();
   mHaveControllerListener = false;
   vm->RemoveControllers();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-VRManagerParent::RecvGetControllers(nsTArray<VRControllerInfo> *aControllers)
-{
-  VRManager* vm = VRManager::Get();
-  vm->GetVRControllerInfo(*aControllers);
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 VRManagerParent::RecvCreateVRTestSystem()
 {
   VRManager* vm = VRManager::Get();
   vm->CreateVRTestSystem();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
--- a/gfx/vr/ipc/VRManagerParent.h
+++ b/gfx/vr/ipc/VRManagerParent.h
@@ -88,17 +88,16 @@ protected:
   virtual mozilla::ipc::IPCResult RecvRefreshDisplays() override;
   virtual mozilla::ipc::IPCResult RecvGetDisplays(nsTArray<VRDisplayInfo> *aDisplays) override;
   virtual mozilla::ipc::IPCResult RecvResetSensor(const uint32_t& aDisplayID) override;
   virtual mozilla::ipc::IPCResult RecvGetSensorState(const uint32_t& aDisplayID, VRHMDSensorState* aState) override;
   virtual mozilla::ipc::IPCResult RecvGetImmediateSensorState(const uint32_t& aDisplayID, VRHMDSensorState* aState) override;
   virtual mozilla::ipc::IPCResult RecvSetHaveEventListener(const bool& aHaveEventListener) override;
   virtual mozilla::ipc::IPCResult RecvControllerListenerAdded() override;
   virtual mozilla::ipc::IPCResult RecvControllerListenerRemoved() override;
-  virtual mozilla::ipc::IPCResult RecvGetControllers(nsTArray<VRControllerInfo> *aControllers) override;
   virtual mozilla::ipc::IPCResult RecvCreateVRTestSystem() override;
   virtual mozilla::ipc::IPCResult RecvCreateVRServiceTestDisplay(const nsCString& aID, const uint32_t& aPromiseID) override;
   virtual mozilla::ipc::IPCResult RecvCreateVRServiceTestController(const nsCString& aID, const uint32_t& aPromiseID) override;
   virtual mozilla::ipc::IPCResult RecvSetDisplayInfoToMockDisplay(const uint32_t& aDeviceID,
                                                                   const VRDisplayInfo& aDisplayInfo) override;
   virtual mozilla::ipc::IPCResult RecvSetSensorStateToMockDisplay(const uint32_t& aDeviceID,
                                                                   const VRHMDSensorState& aSensorState) override;
   virtual mozilla::ipc::IPCResult RecvNewButtonEventToMockController(const uint32_t& aDeviceID, const long& aButton,
--- a/intl/locale/DateTimeFormat.h
+++ b/intl/locale/DateTimeFormat.h
@@ -7,17 +7,19 @@
 #ifndef mozilla_DateTimeFormat_h
 #define mozilla_DateTimeFormat_h
 
 #include <time.h>
 #include "gtest/MozGtestFriend.h"
 #include "nsIScriptableDateFormat.h"
 #include "nsStringGlue.h"
 #include "prtime.h"
+#ifdef ENABLE_INTL_API
 #include "unicode/udat.h"
+#endif
 
 namespace mozilla {
 
 class DateTimeFormat {
 public:
   // performs a locale sensitive date formatting operation on the time_t parameter
   static nsresult FormatTime(const nsDateFormatSelector aDateFormatSelector,
                              const nsTimeFormatSelector aTimeFormatSelector,
@@ -41,21 +43,23 @@ public:
 private:
   DateTimeFormat() = delete;
 
   static nsresult Initialize();
 
   FRIEND_TEST(DateTimeFormat, FormatPRExplodedTime);
   FRIEND_TEST(DateTimeFormat, DateFormatSelectors);
 
+#ifdef ENABLE_INTL_API
   // performs a locale sensitive date formatting operation on the UDate parameter
   static nsresult FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
                                   const nsTimeFormatSelector aTimeFormatSelector,
                                   const UDate aUDateTime,
                                   const PRTimeParameters* aTimeParameters,
                                   nsAString& aStringOut);
+#endif
 
   static nsCString* mLocale;
 };
 
 }
 
 #endif  /* mozilla_DateTimeFormat_h */
new file mode 100644
--- /dev/null
+++ b/intl/locale/DateTimeFormatAndroid.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DateTimeFormat.h"
+#include "prtime.h"
+
+#include <time.h>
+
+#define NSDATETIME_FORMAT_BUFFER_LEN 80
+
+namespace mozilla {
+
+nsCString* DateTimeFormat::mLocale = nullptr;
+
+// performs a locale sensitive date formatting operation on the struct tm
+// parameter
+
+static nsresult
+FormatTMTime(const nsDateFormatSelector aDateFormatSelector,
+             const nsTimeFormatSelector aTimeFormatSelector,
+             const struct tm* aTmTime,
+             nsAString& aStringOut)
+{
+  // set date format
+  nsAutoCString format;
+  if (aDateFormatSelector == kDateFormatLong &&
+      aTimeFormatSelector == kTimeFormatSeconds) {
+    format.AssignLiteral("%c");
+  } else {
+    switch (aDateFormatSelector) {
+      case kDateFormatLong:
+      case kDateFormatShort:
+        format.AssignLiteral("%x");
+        break;
+      case kDateFormatWeekday:
+        format.AssignLiteral("%a");
+        break;
+      case kDateFormatMonthLong:
+        format.AssignLiteral("%B");
+        break;
+      case kDateFormatYearMonth:
+        format.AssignLiteral("%m/%Y");
+        break;
+      case kDateFormatYearMonthLong:
+        format.AssignLiteral("%B %Y");
+        break;
+      case kDateFormatNone:
+      default:
+        break;
+    }
+
+    // set time format
+    switch (aTimeFormatSelector) {
+      case kTimeFormatSeconds:
+        if (!format.IsEmpty()) {
+          format.AppendLiteral(" ");
+        }
+        format.AppendLiteral("%X");
+        break;
+      case kTimeFormatNoSeconds:
+        if (!format.IsEmpty()) {
+          format.AppendLiteral(" ");
+        }
+        format.AppendLiteral("%H:%M");
+        break;
+      case kTimeFormatNone:
+      default:
+        break;
+    }
+  }
+
+  // generate date/time string
+  char strOut[NSDATETIME_FORMAT_BUFFER_LEN];
+  if (!format.IsEmpty()) {
+    strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, format.get(), aTmTime);
+    CopyUTF8toUTF16(strOut, aStringOut);
+  } else {
+    aStringOut.Truncate();
+  }
+
+  return NS_OK;
+}
+
+/*static*/ nsresult
+DateTimeFormat::FormatTime(const nsDateFormatSelector aDateFormatSelector,
+                           const nsTimeFormatSelector aTimeFormatSelector,
+                           const time_t aTimetTime,
+                           nsAString& aStringOut)
+{
+  struct tm tmTime;
+  memcpy(&tmTime, localtime(&aTimetTime), sizeof(struct tm));
+  return FormatTMTime(
+    aDateFormatSelector, aTimeFormatSelector, &tmTime, aStringOut);
+}
+
+// performs a locale sensitive date formatting operation on the PRTime parameter
+
+// static
+nsresult
+DateTimeFormat::FormatPRTime(const nsDateFormatSelector aDateFormatSelector,
+                             const nsTimeFormatSelector aTimeFormatSelector,
+                             const PRTime aPrTime,
+                             nsAString& aStringOut)
+{
+  PRExplodedTime explodedTime;
+  PR_ExplodeTime(aPrTime, PR_LocalTimeParameters, &explodedTime);
+
+  return FormatPRExplodedTime(
+    aDateFormatSelector, aTimeFormatSelector, &explodedTime, aStringOut);
+}
+
+// performs a locale sensitive date formatting operation on the PRExplodedTime
+// parameter
+// static
+nsresult
+DateTimeFormat::FormatPRExplodedTime(
+  const nsDateFormatSelector aDateFormatSelector,
+  const nsTimeFormatSelector aTimeFormatSelector,
+  const PRExplodedTime* aExplodedTime,
+  nsAString& aStringOut)
+{
+  struct tm tmTime;
+  /* be safe and set all members of struct tm to zero
+   *
+   * there are other fields in the tm struct that we aren't setting
+   * (tm_isdst, tm_gmtoff, tm_zone, should we set these?) and since
+   * tmTime is on the stack, it may be filled with garbage, but
+   * the garbage may vary.  (this may explain why some saw bug #10412, and
+   * others did not.
+   *
+   * when tmTime is passed to strftime() with garbage bad things may happen.
+   * see bug #10412
+   */
+  memset(&tmTime, 0, sizeof(tmTime));
+
+  tmTime.tm_yday = aExplodedTime->tm_yday;
+  tmTime.tm_wday = aExplodedTime->tm_wday;
+  tmTime.tm_year = aExplodedTime->tm_year;
+  tmTime.tm_year -= 1900;
+  tmTime.tm_mon = aExplodedTime->tm_month;
+  tmTime.tm_mday = aExplodedTime->tm_mday;
+  tmTime.tm_hour = aExplodedTime->tm_hour;
+  tmTime.tm_min = aExplodedTime->tm_min;
+  tmTime.tm_sec = aExplodedTime->tm_sec;
+
+  return FormatTMTime(
+    aDateFormatSelector, aTimeFormatSelector, &tmTime, aStringOut);
+}
+
+// static
+void
+DateTimeFormat::Shutdown()
+{
+}
+
+} // namespace mozilla
--- a/intl/locale/moz.build
+++ b/intl/locale/moz.build
@@ -40,27 +40,35 @@ EXPORTS += [
 ]
 
 EXPORTS.mozilla.intl += [
     'LocaleService.h',
     'OSPreferences.h',
 ]
 
 UNIFIED_SOURCES += [
-    'DateTimeFormat.cpp',
     'LocaleService.cpp',
     'nsCollation.cpp',
     'nsLanguageAtomService.cpp',
     'nsLocale.cpp',
     'nsLocaleService.cpp',
     'nsScriptableDateFormat.cpp',
     'nsUConvPropertySearch.cpp',
     'OSPreferences.cpp',
 ]
 
+if CONFIG['ENABLE_INTL_API']:
+    UNIFIED_SOURCES += [
+        'DateTimeFormat.cpp',
+    ]
+else:
+    UNIFIED_SOURCES += [
+        'DateTimeFormatAndroid.cpp',
+    ]
+
 EXTRA_JS_MODULES += [
     'PluralForm.jsm',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/intl/uconv',
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -954,18 +954,16 @@ description =
 [PVRManager::GetDisplays]
 description =
 [PVRManager::GetSensorState]
 description =
 [PVRManager::GetImmediateSensorState]
 description =
 [PVRManager::SetHaveEventListener]
 description =
-[PVRManager::GetControllers]
-description =
 [PHal::GetCurrentBatteryInformation]
 description =
 [PHal::GetCurrentNetworkInformation]
 description =
 [PHal::GetScreenEnabled]
 description =
 [PHal::GetKeyLightEnabled]
 description =
--- a/js/src/devtools/automation/autospider.py
+++ b/js/src/devtools/automation/autospider.py
@@ -279,23 +279,37 @@ def run_command(command, check=False, **
 for k, v in variant.get('env', {}).items():
     env[k] = v.format(
         DIR=DIR.scripts,
         TOOLTOOL_CHECKOUT=DIR.tooltool,
         MOZ_UPLOAD_DIR=env['MOZ_UPLOAD_DIR'],
         OUTDIR=OUTDIR,
     )
 
+def need_updating_configure(configure):
+    if not os.path.exists(configure):
+        return True
+
+    dep_files = [
+        os.path.join(DIR.js_src, 'configure.in'),
+        os.path.join(DIR.js_src, 'old-configure.in'),
+    ]
+    for file in dep_files:
+        if os.path.getmtime(file) > os.path.getmtime(configure):
+            return True
+
+    return False
+
 if not args.nobuild:
     CONFIGURE_ARGS += ' --enable-nspr-build'
     CONFIGURE_ARGS += ' --prefix={OBJDIR}/dist'.format(OBJDIR=POBJDIR)
 
     # Generate a configure script from configure.in.
     configure = os.path.join(DIR.js_src, 'configure')
-    if not os.path.exists(configure):
+    if need_updating_configure(configure):
         shutil.copyfile(configure + ".in", configure)
         os.chmod(configure, 0755)
 
     # Run configure
     if not args.noconf:
         run_command(['sh', '-c', posixpath.join(PDIR.js_src, 'configure') + ' ' + CONFIGURE_ARGS], check=True)
 
     # Run make
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -509,18 +509,16 @@ class BytecodeEmitter::EmitterScope : pu
         return frameSlotEnd() - frameSlotStart();
     }
 
     EmitterScope* enclosingInFrame() const {
         return Nestable<EmitterScope>::enclosing();
     }
 
     NameLocation lookup(BytecodeEmitter* bce, JSAtom* name) {
-        AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx),
-                              TraceLogger_FrontendNameAnalysis);
         if (Maybe<NameLocation> loc = lookupInCache(bce, name))
             return *loc;
         return searchAndCache(bce, name);
     }
 
     Maybe<NameLocation> locationBoundInScope(BytecodeEmitter* bce, JSAtom* name,
                                              EmitterScope* target);
 };
@@ -797,18 +795,16 @@ BytecodeEmitter::EmitterScope::searchAnd
 
     return *loc;
 }
 
 Maybe<NameLocation>
 BytecodeEmitter::EmitterScope::locationBoundInScope(BytecodeEmitter* bce, JSAtom* name,
                                                     EmitterScope* target)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     // The target scope must be an intra-frame enclosing scope of this
     // one. Count the number of extra hops to reach it.
     uint8_t extraHops = 0;
     for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
         if (es->hasEnvironment())
             extraHops++;
     }
 
@@ -856,18 +852,16 @@ BytecodeEmitter::EmitterScope::deadZoneF
 {
     return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
 }
 
 bool
 BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
                                             Handle<LexicalScope::Data*> bindings)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
     MOZ_ASSERT(this == bce->innermostEmitterScope);
 
     if (!ensureCache(bce))
         return false;
 
     // Marks all names as closed over if the the context requires it. This
     // cannot be done in the Parser as we may not know if the context requires
@@ -928,18 +922,16 @@ BytecodeEmitter::EmitterScope::enterLexi
         return false;
 
     return checkEnvironmentChainLength(bce);
 }
 
 bool
 BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     MOZ_ASSERT(this == bce->innermostEmitterScope);
     MOZ_ASSERT(funbox->namedLambdaBindings());
 
     if (!ensureCache(bce))
         return false;
 
     // See comment in enterLexical about allBindingsClosedOver.
     if (funbox->allBindingsClosedOver())
@@ -997,18 +989,16 @@ BytecodeEmitter::EmitterScope::enterComp
         return false;
 
     return true;
 }
 
 bool
 BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     MOZ_ASSERT(this == bce->innermostEmitterScope);
 
     if (!ensureCache(bce))
         return false;
 
     // Parameter expressions var scopes have no pre-set bindings and are
     // always extensible, as they are needed for eval.
     fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
@@ -1120,18 +1110,16 @@ BytecodeEmitter::EmitterScope::enterFunc
         return false;
 
     return checkEnvironmentChainLength(bce);
 }
 
 bool
 BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     MOZ_ASSERT(funbox->hasParameterExprs);
     MOZ_ASSERT(funbox->extraVarScopeBindings() ||
                funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
     MOZ_ASSERT(this == bce->innermostEmitterScope);
 
     // The extra var scope is never popped once it's entered. It replaces the
     // function scope as the var emitter scope.
     bce->setVarEmitterScope(this);
@@ -1211,18 +1199,16 @@ class DynamicBindingIter : public Bindin
             MOZ_CRASH("Bad BindingKind");
         }
     }
 };
 
 bool
 BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     MOZ_ASSERT(this == bce->innermostEmitterScope);
 
     bce->setVarEmitterScope(this);
 
     if (!ensureCache(bce))
         return false;
 
     if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
@@ -1273,18 +1259,16 @@ BytecodeEmitter::EmitterScope::enterGlob
         return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
     };
     return internBodyScope(bce, createScope);
 }
 
 bool
 BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     MOZ_ASSERT(this == bce->innermostEmitterScope);
 
     bce->setVarEmitterScope(this);
 
     if (!ensureCache(bce))
         return false;
 
     // For simplicity, treat all free name lookups in eval scripts as dynamic.
@@ -1330,18 +1314,16 @@ BytecodeEmitter::EmitterScope::enterEval
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     MOZ_ASSERT(this == bce->innermostEmitterScope);
 
     bce->setVarEmitterScope(this);
 
     if (!ensureCache(bce))
         return false;
 
     // Resolve body-level bindings, if there are any.
@@ -1389,18 +1371,16 @@ BytecodeEmitter::EmitterScope::enterModu
         return false;
 
     return checkEnvironmentChainLength(bce);
 }
 
 bool
 BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     MOZ_ASSERT(this == bce->innermostEmitterScope);
 
     if (!ensureCache(bce))
         return false;
 
     // 'with' make all accesses dynamic and unanalyzable.
     fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
 
@@ -1417,18 +1397,16 @@ BytecodeEmitter::EmitterScope::enterWith
         return false;
 
     return checkEnvironmentChainLength(bce);
 }
 
 bool
 BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendNameAnalysis);
-
     // If we aren't leaving the scope due to a non-local jump (e.g., break),
     // we must be the innermost scope.
     MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope);
 
     ScopeKind kind = scope(bce)->kind();
     switch (kind) {
       case ScopeKind::Lexical:
       case ScopeKind::SimpleCatch:
@@ -1476,18 +1454,16 @@ BytecodeEmitter::EmitterScope::leave(Byt
     }
 
     return true;
 }
 
 Maybe<MaybeCheckTDZ>
 BytecodeEmitter::TDZCheckCache::needsTDZCheck(BytecodeEmitter* bce, JSAtom* name)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendTDZAnalysis);
-
     if (!ensureCache(bce))
         return Nothing();
 
     CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
     if (p)
         return Some(p->value().wrapped);
 
     MaybeCheckTDZ rv = CheckTDZ;
@@ -1507,18 +1483,16 @@ BytecodeEmitter::TDZCheckCache::needsTDZ
 
     return Some(rv);
 }
 
 bool
 BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
                                              MaybeCheckTDZ check)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(bce->cx), TraceLogger_FrontendTDZAnalysis);
-
     if (!ensureCache(bce))
         return false;
 
     CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
     if (p) {
         MOZ_ASSERT(!check, "TDZ only needs to be checked once per binding per basic block.");
         p->value() = check;
     } else {
@@ -2092,19 +2066,17 @@ class ForOfLoopControl : public LoopCont
         return bce->emitIteratorClose(completionKind, allowSelfHosted_);
     }
 
     bool emitPrepareForNonLocalJump(BytecodeEmitter* bce, bool isTarget) {
         // Pop unnecessary values from the stack.  Effectively this means
         // leaving try-catch block.  However, the performing IteratorClose can
         // reach the depth for try-catch, and effectively re-enter the
         // try-catch block.
-        if (!bce->emit1(JSOP_POP))                        // ITER RESULT
-            return false;
-        if (!bce->emit1(JSOP_POP))                        // ITER
+        if (!bce->emitPopN(2))                            // ITER
             return false;
 
         // Clear ITER slot on the stack to tell catch block to avoid performing
         // IteratorClose again.
         if (!bce->emit1(JSOP_UNDEFINED))                  // ITER UNDEF
             return false;
         if (!bce->emit1(JSOP_SWAP))                       // UNDEF ITER
             return false;
@@ -2477,16 +2449,31 @@ BytecodeEmitter::emitDupAt(unsigned slot
         return false;
 
     jsbytecode* pc = code(off);
     SET_UINT24(pc, slotFromTop);
     return true;
 }
 
 bool
+BytecodeEmitter::emitPopN(unsigned n)
+{
+    MOZ_ASSERT(n != 0);
+
+    if (n == 1)
+        return emit1(JSOP_POP);
+
+    // 2 JSOP_POPs (2 bytes) are shorter than JSOP_POPN (3 bytes).
+    if (n == 2)
+        return emit1(JSOP_POP) && emit1(JSOP_POP);
+
+    return emitUint16Operand(JSOP_POPN, n);
+}
+
+bool
 BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind)
 {
     return emit2(JSOP_CHECKISOBJ, uint8_t(kind));
 }
 
 bool
 BytecodeEmitter::emitCheckIsCallable(CheckIsCallableKind kind)
 {
@@ -2636,18 +2623,17 @@ BytecodeEmitter::emitUint32Operand(JSOp 
     SET_UINT32(code(off), operand);
     checkTypeSet(op);
     return true;
 }
 
 bool
 BytecodeEmitter::flushPops(int* npops)
 {
-    MOZ_ASSERT(*npops != 0);
-    if (!emitUint16Operand(JSOP_POPN, *npops))
+    if (!emitPopN(*npops))
         return false;
 
     *npops = 0;
     return true;
 }
 
 namespace {
 
@@ -5351,19 +5337,17 @@ BytecodeEmitter::emitIteratorClose(Compl
             return false;
 
         if (!tryCatch->emitEnd())                         // ... RET ITER RESULT
             return false;
 
         // Restore stack.
         if (!emit2(JSOP_UNPICK, 2))                       // ... RESULT RET ITER
             return false;
-        if (!emit1(JSOP_POP))                             // ... RESULT RET
-            return false;
-        if (!emit1(JSOP_POP))                             // ... RESULT
+        if (!emitPopN(2))                                 // ... RESULT
             return false;
     } else {
         if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ... RESULT
             return false;
     }
 
     if (!ifReturnMethodIsDefined.emitElse())
         return false;
@@ -6842,17 +6826,17 @@ BytecodeEmitter::emitSpread(bool allowSe
     MOZ_ASSERT(loopInfo.continues.offset == -1);
 
     if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
         return false;
 
     if (!emit2(JSOP_PICK, 3))                             // ARR FINAL_INDEX RESULT ITER
         return false;
 
-    return emitUint16Operand(JSOP_POPN, 2);               // ARR FINAL_INDEX
+    return emitPopN(2);                                   // ARR FINAL_INDEX
 }
 
 bool
 BytecodeEmitter::emitInitializeForInOrOfTarget(ParseNode* forHead)
 {
     MOZ_ASSERT(forHead->isKind(PNK_FORIN) || forHead->isKind(PNK_FOROF));
     MOZ_ASSERT(forHead->isArity(PN_TERNARY));
 
@@ -7065,17 +7049,17 @@ BytecodeEmitter::emitForOf(ParseNode* fo
         return false;
 
     if (!loopInfo.patchBreaksAndContinues(this))
         return false;
 
     if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
         return false;
 
-    return emitUint16Operand(JSOP_POPN, 3);               //
+    return emitPopN(3);                                   //
 }
 
 bool
 BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitterScope)
 {
     MOZ_ASSERT(forInLoop->isKind(PNK_FOR));
     MOZ_ASSERT(forInLoop->isArity(PN_BINARY));
     MOZ_ASSERT(forInLoop->isOp(JSOP_ITER));
@@ -7588,17 +7572,17 @@ BytecodeEmitter::emitComprehensionForOf(
 
     if (emitterScope) {
         if (!emitterScope->leave(this))
             return false;
         emitterScope.reset();
     }
 
     // Pop the result and the iter.
-    return emitUint16Operand(JSOP_POPN, 3);               //
+    return emitPopN(3);                                   //
 }
 
 bool
 BytecodeEmitter::emitComprehensionForIn(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(PNK_COMPREHENSIONFOR));
 
     ParseNode* forHead = pn->pn_left;
@@ -8562,34 +8546,32 @@ BytecodeEmitter::emitYieldStar(ParseNode
         return false;
     if (!emit1(JSOP_SETRVAL))                             // ITER OLDRESULT FTYPE FVALUE
         return false;
     savedDepthTemp = this->stackDepth;
     if (!ifReturnDone.emitElse())                         // ITER OLDRESULT FTYPE FVALUE RESULT
         return false;
     if (!emit2(JSOP_UNPICK, 3))                           // ITER RESULT OLDRESULT FTYPE FVALUE
         return false;
-    if (!emitUint16Operand(JSOP_POPN, 3))                 // ITER RESULT
+    if (!emitPopN(3))                                     // ITER RESULT
         return false;
     {
         // goto tryStart;
         JumpList beq;
         JumpTarget breakTarget{ -1 };
         if (!emitBackwardJump(JSOP_GOTO, tryStart, &beq, &breakTarget)) // ITER RESULT
             return false;
     }
     this->stackDepth = savedDepthTemp;
     if (!ifReturnDone.emitEnd())
         return false;
 
     if (!ifReturnMethodIsDefined.emitElse())              // ITER RESULT FTYPE FVALUE ITER RET
         return false;
-    if (!emit1(JSOP_POP))                                 // ITER RESULT FTYPE FVALUE ITER
-        return false;
-    if (!emit1(JSOP_POP))                                 // ITER RESULT FTYPE FVALUE
+    if (!emitPopN(2))                                     // ITER RESULT FTYPE FVALUE
         return false;
     if (!ifReturnMethodIsDefined.emitEnd())
         return false;
 
     if (!ifGeneratorClosing.emitEnd())
         return false;
 
     if (!tryCatch.emitEnd())
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -465,16 +465,19 @@ struct MOZ_STACK_CLASS BytecodeEmitter
 
     // Emit three bytecodes, an opcode with two bytes of immediate operands.
     MOZ_MUST_USE bool emit3(JSOp op, jsbytecode op1, jsbytecode op2);
 
     // Helper to emit JSOP_DUPAT. The argument is the value's depth on the
     // JS stack, as measured from the top.
     MOZ_MUST_USE bool emitDupAt(unsigned slotFromTop);
 
+    // Helper to emit JSOP_POP or JSOP_POPN.
+    MOZ_MUST_USE bool emitPopN(unsigned n);
+
     // Helper to emit JSOP_CHECKISOBJ.
     MOZ_MUST_USE bool emitCheckIsObj(CheckIsObjectKind kind);
 
     // Helper to emit JSOP_CHECKISCALLABLE.
     MOZ_MUST_USE bool emitCheckIsCallable(CheckIsCallableKind kind);
 
     // Emit a bytecode followed by an uint16 immediate operand stored in
     // big-endian order.
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1084,18 +1084,16 @@ Parser<ParseHandler>::reportRedeclaratio
 // forbid duplicates.)
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName name,
                                                     uint32_t beginPos,
                                                     bool disallowDuplicateParams,
                                                     bool* duplicatedParam)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(context), TraceLogger_FrontendNameAnalysis);
-
     if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) {
         if (disallowDuplicateParams) {
             error(JSMSG_BAD_DUP_ARGS);
             return false;
         }
 
         // Strict-mode disallows duplicate args. We may not know whether we are
         // in strict mode or not (since the function body hasn't been parsed).
@@ -1317,18 +1315,16 @@ Parser<ParseHandler>::tryDeclareVar(Hand
     return true;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name,
                                                             uint32_t beginPos, bool* tryAnnexB)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(context), TraceLogger_FrontendNameAnalysis);
-
     Maybe<DeclarationKind> redeclaredKind;
     uint32_t unused;
     if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, beginPos,
                        &redeclaredKind, &unused))
     {
         return false;
     }
 
@@ -1387,18 +1383,16 @@ Parser<ParseHandler>::checkLexicalDeclar
     return true;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind kind,
                                        TokenPos pos)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(context), TraceLogger_FrontendNameAnalysis);
-
     // The asm.js validator does all its own symbol-table management so, as an
     // optimization, avoid doing any work here.
     if (pc->useAsmOrInsideUseAsm())
         return true;
 
     switch (kind) {
       case DeclarationKind::Var:
       case DeclarationKind::BodyLevelFunction:
@@ -1560,18 +1554,16 @@ Parser<ParseHandler>::noteDeclaredName(H
 
     return true;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::noteUsedName(HandlePropertyName name)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(context), TraceLogger_FrontendNameAnalysis);
-
     // If the we are delazifying, the LazyScript already has all the
     // closed-over info for bindings and there's no need to track used names.
     if (handler.canSkipLazyClosedOverBindings())
         return true;
 
     // The asm.js validator does all its own symbol-table management so, as an
     // optimization, avoid doing any work here.
     if (pc->useAsmOrInsideUseAsm())
@@ -1587,29 +1579,25 @@ Parser<ParseHandler>::noteUsedName(Handl
 
     return usedNames.noteUse(context, name, pc->scriptId(), scope->id());
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::hasUsedName(HandlePropertyName name)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(context), TraceLogger_FrontendNameAnalysis);
-
     if (UsedNamePtr p = usedNames.lookup(name))
         return p->value().isUsedInScript(pc->scriptId());
     return false;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope)
 {
-    AutoTraceLog traceLog(TraceLoggerForCurrentThread(context), TraceLogger_FrontendNameAnalysis);
-
     if (handler.canSkipLazyClosedOverBindings()) {
         // Scopes are nullptr-delimited in the LazyScript closed over bindings
         // array.
         while (JSAtom* name = handler.nextLazyClosedOverBinding())
             scope.lookupDeclaredName(name)->value()->setClosedOver();
         return true;
     }
 
@@ -9296,24 +9284,39 @@ Parser<ParseHandler>::propertyName(Yield
     bool isAsync = false;
     if (ltok == TOK_MUL) {
         isGenerator = true;
         if (!tokenStream.getToken(&ltok))
             return null();
     }
 
     if (ltok == TOK_ASYNC) {
-        TokenKind tt;
-        if (!tokenStream.getToken(&tt))
-            return null();
-        if (tt != TOK_LP && tt != TOK_COLON && tt != TOK_RC && tt != TOK_ASSIGN) {
+        // AsyncMethod[Yield, Await]:
+        //   async [no LineTerminator here] PropertyName[?Yield, ?Await] ...
+        //
+        // PropertyName:
+        //   LiteralPropertyName
+        //   ComputedPropertyName[?Yield, ?Await]
+        //
+        // LiteralPropertyName:
+        //   IdentifierName
+        //   StringLiteral
+        //   NumericLiteral
+        //
+        // ComputedPropertyName[Yield, Await]:
+        //   [ ...
+        TokenKind tt = TOK_EOF;
+        if (!tokenStream.peekTokenSameLine(&tt))
+            return null();
+        if (tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_LB ||
+            TokenKindIsPossibleIdentifierName(tt))
+        {
             isAsync = true;
+            tokenStream.consumeKnownToken(tt);
             ltok = tt;
-        } else {
-            tokenStream.ungetToken();
         }
     }
 
     if (isAsync && isGenerator) {
         error(JSMSG_ASYNC_GENERATOR);
         return null();
     }
 
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1297,20 +1297,16 @@ static const uint8_t firstCharKinds[] = 
 #undef _______
 
 static_assert(LastCharKind < (1 << (sizeof(firstCharKinds[0]) * 8)),
               "Elements of firstCharKinds[] are too small");
 
 bool
 TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
 {
-    // The assumption is that the cost of other tokenizer code is dwarfed by
-    // this one.
-    AutoTraceLog tokenizerLog(TraceLoggerForCurrentThread(cx), TraceLogger_Tokenizing);
-
     int c;
     uint32_t qc;
     Token* tp;
     FirstCharKind c1kind;
     const char16_t* numStart;
     bool hasExp;
     DecimalPoint decimalPoint;
     const char16_t* identStart;
--- a/js/src/tests/ecma_2017/AsyncFunctions/property.js
+++ b/js/src/tests/ecma_2017/AsyncFunctions/property.js
@@ -30,10 +30,20 @@ print(BUGNUMBER + ": " + summary);
   assertEq(async, 13);
 }
 
 {
   let { async: a = 14 } = {};
   assertEq(a, 14);
 }
 
+{
+  let { async, other } = { async: 15, other: 16 };
+  assertEq(async, 15);
+  assertEq(other, 16);
+
+  let a = { async, other };
+  assertEq(a.async, 15);
+  assertEq(a.other, 16);
+}
+
 if (typeof reportCompare === "function")
     reportCompare(true, true);
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -826,21 +826,18 @@ TraceLoggerThreadState::init()
         enabledTextIds[TraceLogger_RegisterAllocation] = true;
         enabledTextIds[TraceLogger_GenerateCode] = true;
         enabledTextIds[TraceLogger_Scripts] = true;
         enabledTextIds[TraceLogger_IonBuilderRestartLoop] = true;
     }
 
     if (ContainsFlag(env, "Frontend")) {
         enabledTextIds[TraceLogger_Frontend] = true;
-        enabledTextIds[TraceLogger_FrontendNameAnalysis] = true;
-        enabledTextIds[TraceLogger_FrontendTDZAnalysis] = true;
         enabledTextIds[TraceLogger_ParsingFull] = true;
         enabledTextIds[TraceLogger_ParsingSyntax] = true;
-        enabledTextIds[TraceLogger_Tokenizing] = true;
         enabledTextIds[TraceLogger_BytecodeEmission] = true;
         enabledTextIds[TraceLogger_BytecodeFoldConstants] = true;
         enabledTextIds[TraceLogger_BytecodeNameFunctions] = true;
     }
 
     enabledTextIds[TraceLogger_Interpreter] = enabledTextIds[TraceLogger_Engine];
     enabledTextIds[TraceLogger_Baseline] = enabledTextIds[TraceLogger_Engine];
     enabledTextIds[TraceLogger_IonMonkey] = enabledTextIds[TraceLogger_Engine];
--- a/js/src/vm/TraceLoggingTypes.h
+++ b/js/src/vm/TraceLoggingTypes.h
@@ -25,21 +25,18 @@
     _(IonCompilation)                                 \
     _(IonCompilationPaused)                           \
     _(IonLinking)                                     \
     _(IonMonkey)                                      \
     _(IrregexpCompile)                                \
     _(IrregexpExecute)                                \
     _(MinorGC)                                        \
     _(Frontend)                                       \
-    _(FrontendNameAnalysis)                           \
-    _(FrontendTDZAnalysis)                            \
     _(ParsingFull)                                    \
     _(ParsingSyntax)                                  \
-    _(Tokenizing)                                     \
     _(BytecodeEmission)                               \
     _(BytecodeFoldConstants)                          \
     _(BytecodeNameFunctions)                          \
     _(DecodeScript)                                   \
     _(DecodeFunction)                                 \
     _(EncodeScript)                                   \
     _(EncodeFunction)                                 \
     _(Scripts)                                        \
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1570,17 +1570,17 @@ nsDisplayImage::GetDestRect()
   return imageFrame->PredictedDestRect(frameContentBox);
 }
 
 LayerState
 nsDisplayImage::GetLayerState(nsDisplayListBuilder* aBuilder,
                               LayerManager* aManager,
                               const ContainerLayerParameters& aParameters)
 {
-  if (!nsDisplayItem::ForceActiveLayers()) {
+  if (!nsDisplayItem::ForceActiveLayers() && !gfxPrefs::LayersAllowImageLayers()) {
     bool animated = false;
     if (!nsLayoutUtils::AnimatedImageLayersEnabled() ||
         mImage->GetType() != imgIContainer::TYPE_RASTER ||
         NS_FAILED(mImage->GetAnimated(&animated)) ||
         !animated) {
       if (!aManager->IsCompositingCheap() ||
           !nsLayoutUtils::GPUImageScalingEnabled()) {
         return LAYER_NONE;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4532,16 +4532,17 @@ pref("webgl.disabled", false);
 pref("webgl.disable-angle", false);
 pref("webgl.disable-wgl", false);
 pref("webgl.min_capability_mode", false);
 pref("webgl.disable-extensions", false);
 pref("webgl.msaa-force", false);
 pref("webgl.prefer-16bpp", false);
 pref("webgl.default-no-alpha", false);
 pref("webgl.force-layers-readback", false);
+pref("webgl.force-index-validation", false);
 pref("webgl.lose-context-on-memory-pressure", false);
 pref("webgl.can-lose-context-in-foreground", true);
 pref("webgl.restore-context-when-visible", true);
 pref("webgl.max-warnings-per-context", 32);
 pref("webgl.enable-draft-extensions", false);
 pref("webgl.enable-privileged-extensions", false);
 pref("webgl.bypass-shader-validation", false);
 pref("webgl.disable-fail-if-major-performance-caveat", false);
deleted file mode 100644
--- a/testing/web-platform/meta/html/webappapis/scripting/events/messageevent-constructor.https.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[messageevent-constructor.https.html]
-  type: testharness
-  [Passing ServiceWorker for source member]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/service-workers/service-worker/postmessage-to-client.https.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[postmessage-to-client.https.html]
-  type: testharness
-  [postMessage from ServiceWorker to Client]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/service-workers/service-worker/serviceworker-message-event-historical.https.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[serviceworker-message-event-historical.https.html]
-  type: testharness
-  [Test MessageEvent supplants ServiceWorkerMessageEvent.]
-    expected: FAIL
-