Backed out 20 changesets (bug 1320892, bug 1318507, bug 1321450, bug 1305832, bug 1320030, bug 1310247) for build bustage
authorPhil Ringnalda <philringnalda@gmail.com>
Thu, 15 Dec 2016 17:59:34 -0800
changeset 353009 0da2d0158f98743c85d3ed279c3a4db691c2d4f5
parent 353008 51de65f3f8399f44a7b5b84beaa0d501e6e22c30
child 353010 40bbf975f4096ea72bf1677aa398b037abd7df41
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1320892, 1318507, 1321450, 1305832, 1320030, 1310247
milestone52.0a2
backs out51de65f3f8399f44a7b5b84beaa0d501e6e22c30
88c9d76d46abebc32f795b418d06a8359b2e8b88
4e602c1e307ef31394b4d9058cbeea7050cc0a8f
10ea91ee54bd6602ab2956bcbf900775a92fa580
fe0a30186fcc65c67dacd0928b1ca30394bb6616
b810c31221c50838b2a8309030761a281b8bd838
ae0f7b513fa3c00ab62cfd3bbc01f5bc83a06104
e6d85e47e7bbeb7a9b7024c05a9ab420fe0c8388
39379507d2d85068070dd2076ccdb0b68ab26449
ba7fef973cf40fa8687f87a2aa4fa155a6efe9b1
4b6ee2eadeacd5b4bc83320cbe2f6345ee6ac9d3
0a3c283c19881716a44050b15a0da560b9977370
776295ca0f6452579385b6320e381857e98e46e9
e4bf2c365c82bd505034ffb4c3fed5be471a5e86
4058aa1d98319713dc5b6394406a5685c5c68dd0
df953d508c81b3063b006a8543d375e04a9cc7ba
3f1441255bca982628cd3250927fa6bb7eaefd8b
b5d390d820b03c007954bd627a4d84f2deb6728f
11dc44b794665b2417acc5463b9e790af9b4cdea
b2aaaf37994ec64a8de15f0637fd8b856af02df9
Backed out 20 changesets (bug 1320892, bug 1318507, bug 1321450, bug 1305832, bug 1320030, bug 1310247) for build bustage Backed out changeset 51de65f3f839 (bug 1305832) Backed out changeset 88c9d76d46ab (bug 1305832) Backed out changeset 4e602c1e307e (bug 1305832) Backed out changeset 10ea91ee54bd (bug 1305832) Backed out changeset fe0a30186fcc (bug 1305832) Backed out changeset b810c31221c5 (bug 1320030) Backed out changeset ae0f7b513fa3 (bug 1320030) Backed out changeset e6d85e47e7bb (bug 1320030) Backed out changeset 39379507d2d8 (bug 1320030) Backed out changeset ba7fef973cf4 (bug 1321450) Backed out changeset 4b6ee2eadeac (bug 1321450) Backed out changeset 0a3c283c1988 (bug 1321450) Backed out changeset 776295ca0f64 (bug 1320892) Backed out changeset e4bf2c365c82 (bug 1310247) Backed out changeset 4058aa1d9831 (bug 1310247) Backed out changeset df953d508c81 (bug 1310247) Backed out changeset 3f1441255bca (bug 1318507) Backed out changeset b5d390d820b0 (bug 1318507) Backed out changeset 11dc44b79466 (bug 1318507) Backed out changeset b2aaaf37994e (bug 1318507)
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextBuffers.cpp
dom/canvas/WebGL2ContextFramebuffers.cpp
dom/canvas/WebGL2ContextPrograms.cpp
dom/canvas/WebGL2ContextQueries.cpp
dom/canvas/WebGL2ContextSamplers.cpp
dom/canvas/WebGL2ContextSync.cpp
dom/canvas/WebGL2ContextTransformFeedback.cpp
dom/canvas/WebGL2ContextUniforms.cpp
dom/canvas/WebGLBuffer.cpp
dom/canvas/WebGLBuffer.h
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextBuffers.cpp
dom/canvas/WebGLContextDraw.cpp
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextTextures.cpp
dom/canvas/WebGLContextUnchecked.cpp
dom/canvas/WebGLContextUnchecked.h
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLContextVertexArray.cpp
dom/canvas/WebGLExtensionDebugShaders.cpp
dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
dom/canvas/WebGLExtensionVertexArray.cpp
dom/canvas/WebGLExtensions.h
dom/canvas/WebGLFramebuffer.cpp
dom/canvas/WebGLFramebuffer.h
dom/canvas/WebGLObjectModel.h
dom/canvas/WebGLProgram.cpp
dom/canvas/WebGLProgram.h
dom/canvas/WebGLQuery.cpp
dom/canvas/WebGLQuery.h
dom/canvas/WebGLRenderbuffer.cpp
dom/canvas/WebGLRenderbuffer.h
dom/canvas/WebGLSampler.cpp
dom/canvas/WebGLSampler.h
dom/canvas/WebGLShader.cpp
dom/canvas/WebGLShader.h
dom/canvas/WebGLSync.cpp
dom/canvas/WebGLSync.h
dom/canvas/WebGLTexture.cpp
dom/canvas/WebGLTexture.h
dom/canvas/WebGLTextureUpload.cpp
dom/canvas/WebGLTransformFeedback.cpp
dom/canvas/WebGLTransformFeedback.h
dom/canvas/WebGLUniformLocation.cpp
dom/canvas/WebGLUniformLocation.h
dom/canvas/WebGLVertexArray.cpp
dom/canvas/WebGLVertexArray.h
dom/canvas/WebGLVertexArrayFake.cpp
dom/canvas/WebGLVertexArrayFake.h
dom/canvas/WebGLVertexArrayGL.cpp
dom/canvas/WebGLVertexArrayGL.h
dom/canvas/moz.build
dom/canvas/test/webgl-conf/checkout/conformance/buffers/buffer-data-and-buffer-sub-data.html
dom/canvas/test/webgl-conf/checkout/conformance/context/context-lost.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html
dom/canvas/test/webgl-conf/checkout/conformance/misc/error-reporting.html
dom/canvas/test/webgl-conf/checkout/conformance/misc/null-object-behaviour.html
dom/canvas/test/webgl-conf/checkout/conformance/programs/get-active-test.html
dom/canvas/test/webgl-conf/checkout/conformance2/buffers/bound-buffer-size-change-test.html
dom/canvas/test/webgl-conf/checkout/conformance2/buffers/buffer-type-restrictions.html
dom/canvas/test/webgl-conf/checkout/conformance2/context/constants-and-properties-2.html
dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/invalidate-framebuffer.html
dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js
dom/canvas/test/webgl-conf/generated-mochitest.ini
dom/canvas/test/webgl-conf/mochitest-errata.ini
dom/canvas/test/webgl-mochitest/test_sab_with_webgl.html
gfx/thebes/gfxPrefs.h
modules/libpref/init/all.js
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -116,31 +116,31 @@ public:
     template<typename T>
     void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
                               GLsizei width, GLsizei height, GLsizei depth, GLint border,
                               const T& anySrc, GLuint viewElemOffset = 0,
                               GLuint viewElemLengthOverride = 0)
     {
         const char funcName[] = "compressedTexImage3D";
         const uint8_t funcDims = 3;
-        const TexImageSourceAdapter src(&anySrc, viewElemOffset, viewElemLengthOverride);
+        const TexImageSourceAdapter src(anySrc, viewElemOffset, viewElemLengthOverride);
         CompressedTexImage(funcName, funcDims, target, level, internalFormat, width,
                            height, depth, border, src);
     }
 
     template<typename T>
     void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                                  GLint zOffset, GLsizei width, GLsizei height,
                                  GLsizei depth, GLenum unpackFormat, const T& anySrc,
                                  GLuint viewElemOffset = 0,
                                  GLuint viewElemLengthOverride = 0)
     {
         const char funcName[] = "compressedTexSubImage3D";
         const uint8_t funcDims = 3;
-        const TexImageSourceAdapter src(&anySrc, viewElemOffset, viewElemLengthOverride);
+        const TexImageSourceAdapter src(anySrc, viewElemOffset, viewElemLengthOverride);
         CompressedTexSubImage(funcName, funcDims, target, level, xOffset, yOffset,
                               zOffset, width, height, depth, unpackFormat, src);
     }
 
     ////////////////////////////////////
 
     void CopyTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                            GLint zOffset, GLint x, GLint y, GLsizei width,
@@ -154,27 +154,27 @@ public:
 
     ////////////////////////////////////
 
     template<typename T>
     void TexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLsizei depth, GLint border, GLenum unpackFormat,
                     GLenum unpackType, const T& anySrc, ErrorResult& out_error)
     {
-        const TexImageSourceAdapter src(&anySrc, &out_error);
+        const TexImageSourceAdapter src(anySrc, &out_error);
         TexImage3D(target, level, internalFormat, width, height, depth, border,
                    unpackFormat, unpackType, src);
     }
 
     void TexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLsizei depth, GLint border, GLenum unpackFormat,
                     GLenum unpackType, const dom::ArrayBufferView& view,
                     GLuint viewElemOffset, ErrorResult&)
     {
-        const TexImageSourceAdapter src(&view, viewElemOffset);
+        const TexImageSourceAdapter src(view, viewElemOffset);
         TexImage3D(target, level, internalFormat, width, height, depth, border,
                    unpackFormat, unpackType, src);
     }
 
 protected:
     void TexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLsizei depth, GLint border, GLenum unpackFormat,
                     GLenum unpackType, const TexImageSource& src)
@@ -189,35 +189,28 @@ protected:
 
 public:
     template<typename T>
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum unpackFormat, GLenum unpackType, const T& anySrc,
                        ErrorResult& out_error)
     {
-        const TexImageSourceAdapter src(&anySrc, &out_error);
+        const TexImageSourceAdapter src(anySrc, &out_error);
         TexSubImage3D(target, level, xOffset, yOffset, zOffset, width, height, depth,
                       unpackFormat, unpackType, src);
     }
 
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum unpackFormat, GLenum unpackType,
-                       const dom::Nullable<dom::ArrayBufferView>& maybeSrcView,
-                       GLuint srcElemOffset, ErrorResult&)
+                       const dom::ArrayBufferView& srcView, GLuint srcElemOffset,
+                       ErrorResult&)
     {
-        if (IsContextLost())
-            return;
-
-        if (!ValidateNonNull("texSubImage3D", maybeSrcView))
-            return;
-        const auto& srcView = maybeSrcView.Value();
-
-        const TexImageSourceAdapter src(&srcView, srcElemOffset);
+        const TexImageSourceAdapter src(srcView, srcElemOffset);
         TexSubImage3D(target, level, xOffset, yOffset, zOffset, width, height, depth,
                       unpackFormat, unpackType, src);
     }
 
 protected:
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum unpackFormat, GLenum unpackType, const TexImageSource& src)
@@ -226,17 +219,17 @@ protected:
         const uint8_t funcDims = 3;
         TexSubImage(funcName, funcDims, target, level, xOffset, yOffset, zOffset, width,
                     height, depth, unpackFormat, unpackType, src);
     }
 
 public:
     // -------------------------------------------------------------------------
     // Programs and shaders - WebGL2ContextPrograms.cpp
-    GLint GetFragDataLocation(const WebGLProgram& program, const nsAString& name);
+    GLint GetFragDataLocation(WebGLProgram* program, const nsAString& name);
 
 
     // -------------------------------------------------------------------------
     // Uniforms and attributes - WebGL2ContextUniforms.cpp
     void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
 
     ////////////////
 
@@ -309,79 +302,80 @@ public:
 
     void ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth, GLint stencil);
 
     // -------------------------------------------------------------------------
     // Sampler Objects - WebGL2ContextSamplers.cpp
 
     already_AddRefed<WebGLSampler> CreateSampler();
     void DeleteSampler(WebGLSampler* sampler);
-    bool IsSampler(const WebGLSampler* sampler);
+    bool IsSampler(WebGLSampler* sampler);
     void BindSampler(GLuint unit, WebGLSampler* sampler);
-    void SamplerParameteri(WebGLSampler& sampler, GLenum pname, GLint param);
-    void SamplerParameterf(WebGLSampler& sampler, GLenum pname, GLfloat param);
-    void GetSamplerParameter(JSContext*, const WebGLSampler& sampler, GLenum pname,
-                             JS::MutableHandleValue retval);
+    void SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param);
+    void SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Int32Array& param);
+    void SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLint>& param);
+    void SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param);
+    void SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Float32Array& param);
+    void SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLfloat>& param);
+    void GetSamplerParameter(JSContext*, WebGLSampler* sampler, GLenum pname, JS::MutableHandleValue retval);
 
 
     // -------------------------------------------------------------------------
     // Sync objects - WebGL2ContextSync.cpp
 
     already_AddRefed<WebGLSync> FenceSync(GLenum condition, GLbitfield flags);
-    bool IsSync(const WebGLSync* sync);
+    bool IsSync(WebGLSync* sync);
     void DeleteSync(WebGLSync* sync);
-    GLenum ClientWaitSync(const WebGLSync& sync, GLbitfield flags, GLuint64 timeout);
-    void WaitSync(const WebGLSync& sync, GLbitfield flags, GLint64 timeout);
-    void GetSyncParameter(JSContext*, const WebGLSync& sync, GLenum pname,
-                          JS::MutableHandleValue retval);
+    GLenum ClientWaitSync(WebGLSync* sync, GLbitfield flags, GLuint64 timeout);
+    void WaitSync(WebGLSync* sync, GLbitfield flags, GLuint64 timeout);
+    void GetSyncParameter(JSContext*, WebGLSync* sync, GLenum pname, JS::MutableHandleValue retval);
 
 
     // -------------------------------------------------------------------------
     // Transform Feedback - WebGL2ContextTransformFeedback.cpp
 
     already_AddRefed<WebGLTransformFeedback> CreateTransformFeedback();
     void DeleteTransformFeedback(WebGLTransformFeedback* tf);
-    bool IsTransformFeedback(const WebGLTransformFeedback* tf);
+    bool IsTransformFeedback(WebGLTransformFeedback* tf);
     void BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf);
     void BeginTransformFeedback(GLenum primitiveMode);
     void EndTransformFeedback();
     void PauseTransformFeedback();
     void ResumeTransformFeedback();
-    void TransformFeedbackVaryings(WebGLProgram& program,
-                                   const dom::Sequence<nsString>& varyings,
-                                   GLenum bufferMode);
-    already_AddRefed<WebGLActiveInfo>
-    GetTransformFeedbackVarying(const WebGLProgram& program, GLuint index);
+    void TransformFeedbackVaryings(WebGLProgram* program, const dom::Sequence<nsString>& varyings, GLenum bufferMode);
+    already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(WebGLProgram* program, GLuint index);
 
 
     // -------------------------------------------------------------------------
     // Uniform Buffer Objects and Transform Feedback Buffers - WebGL2ContextUniforms.cpp
     // TODO(djg): Implemented in WebGLContext
 /*
     void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
     void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, GLintptr offset, GLsizeiptr size);
 */
     virtual JS::Value GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) override;
     void GetIndexedParameter(JSContext* cx, GLenum target, GLuint index,
                              JS::MutableHandleValue retval, ErrorResult& rv);
-    void GetUniformIndices(const WebGLProgram& program,
+    void GetUniformIndices(WebGLProgram* program,
                            const dom::Sequence<nsString>& uniformNames,
                            dom::Nullable< nsTArray<GLuint> >& retval);
-    void GetActiveUniforms(JSContext* cx, const WebGLProgram& program,
-                           const dom::Sequence<GLuint>& uniformIndices, GLenum pname,
+    void GetActiveUniforms(JSContext* cx,
+                           WebGLProgram* program,
+                           const dom::Sequence<GLuint>& uniformIndices,
+                           GLenum pname,
                            JS::MutableHandleValue retval);
 
-    GLuint GetUniformBlockIndex(const WebGLProgram& program,
-                                const nsAString& uniformBlockName);
-    void GetActiveUniformBlockParameter(JSContext*, const WebGLProgram& program,
+    GLuint GetUniformBlockIndex(WebGLProgram* program, const nsAString& uniformBlockName);
+    void GetActiveUniformBlockParameter(JSContext*, WebGLProgram* program,
                                         GLuint uniformBlockIndex, GLenum pname,
-                                        JS::MutableHandleValue retval, ErrorResult& rv);
-    void GetActiveUniformBlockName(const WebGLProgram& program, GLuint uniformBlockIndex,
+                                        JS::MutableHandleValue retval,
+                                        ErrorResult& rv);
+    void GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex,
                                    nsAString& retval);
-    void UniformBlockBinding(WebGLProgram& program, GLuint uniformBlockIndex,
+    void UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex,
                              GLuint uniformBlockBinding);
 
 
     // -------------------------------------------------------------------------
     // Vertex Array Object - WebGL2ContextVAOs.cpp
     // TODO(djg): Implemented in WebGLContext
 /*
     already_AddRefed<WebGLVertexArrayObject> CreateVertexArray();
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -26,16 +26,25 @@ WebGL2Context::CopyBufferSubData(GLenum 
     const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
     if (!readBuffer)
         return;
 
     const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
     if (!writeBuffer)
         return;
 
+    if (readBuffer->mNumActiveTFOs ||
+        writeBuffer->mNumActiveTFOs)
+    {
+        ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+                              " object.",
+                              funcName);
+        return;
+    }
+
     if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
         !ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
         !ValidateNonNegative(funcName, "size", size))
     {
         return;
     }
 
     const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
@@ -115,16 +124,31 @@ WebGL2Context::GetBufferSubData(GLenum t
     if (!buffer)
         return;
 
     if (!buffer->ValidateRange(funcName, srcByteOffset, byteLen))
         return;
 
     ////
 
+    if (buffer->mNumActiveTFOs) {
+        ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+                              " object.",
+                              funcName);
+        return;
+    }
+
+    if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
+        mBoundTransformFeedback->mIsActive)
+    {
+        ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
+                              funcName);
+        return;
+    }
+
     if (!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
         ErrorOutOfMemory("%s: Size too large.", funcName);
         return;
     }
     const GLsizeiptr glByteLen(byteLen);
 
     ////
 
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -100,73 +100,60 @@ WebGL2Context::GetFramebufferAttachmentP
                                                  GLenum attachment,
                                                  GLenum pname,
                                                  ErrorResult& out_error)
 {
     return WebGLContext::GetFramebufferAttachmentParameter(cx, target, attachment, pname,
                                                            out_error);
 }
 
-////
-
+// Map attachments intended for the default buffer, to attachments for a non-
+// default buffer.
 static bool
-ValidateBackbufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
-                                 GLenum attachment)
+TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenum>* out)
 {
-    switch (attachment) {
-    case LOCAL_GL_COLOR:
-    case LOCAL_GL_DEPTH:
-    case LOCAL_GL_STENCIL:
-        return true;
+    for (size_t i = 0; i < in.Length(); i++) {
+        switch (in[i]) {
+            case LOCAL_GL_COLOR:
+                if (!out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0, fallible)) {
+                    return false;
+                }
+                break;
 
-    default:
-        webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
-                                funcName, attachment);
-        return false;
-    }
-}
+            case LOCAL_GL_DEPTH:
+                if (!out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT, fallible)) {
+                    return false;
+                }
+                break;
 
-static bool
-ValidateFramebufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
-                                  GLenum attachment)
-{
-    if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
-        attachment <= webgl->LastColorAttachmentEnum())
-    {
-        return true;
+            case LOCAL_GL_STENCIL:
+                if (!out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT, fallible)) {
+                    return false;
+                }
+                break;
+        }
     }
 
-    switch (attachment) {
-    case LOCAL_GL_DEPTH_ATTACHMENT:
-    case LOCAL_GL_STENCIL_ATTACHMENT:
-    case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
-        return true;
-
-    default:
-        webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
-                                funcName, attachment);
-        return false;
-    }
+    return true;
 }
 
-bool
-WebGLContext::ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
-                                            const dom::Sequence<GLenum>& attachments,
-                                            ErrorResult* const out_rv,
-                                            std::vector<GLenum>* const scopedVector,
-                                            GLsizei* const out_glNumAttachments,
-                                            const GLenum** const out_glAttachments)
+void
+WebGL2Context::InvalidateFramebuffer(GLenum target,
+                                     const dom::Sequence<GLenum>& attachments,
+                                     ErrorResult& rv)
 {
+    const char funcName[] = "invalidateSubFramebuffer";
+
     if (IsContextLost())
-        return false;
+        return;
 
-    gl->MakeCurrent();
+    MakeContextCurrent();
 
     if (!ValidateFramebufferTarget(target, funcName))
-        return false;
+        return;
 
     const WebGLFramebuffer* fb;
     bool isDefaultFB;
     switch (target) {
     case LOCAL_GL_FRAMEBUFFER:
     case LOCAL_GL_DRAW_FRAMEBUFFER:
         fb = mBoundDrawFramebuffer;
         isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
@@ -176,124 +163,111 @@ WebGLContext::ValidateInvalidateFramebuf
         fb = mBoundReadFramebuffer;
         isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
         break;
 
     default:
         MOZ_CRASH("GFX: Bad target.");
     }
 
-    *out_glNumAttachments = attachments.Length();
-    *out_glAttachments = attachments.Elements();
-
-    if (fb) {
-        for (const auto& attachment : attachments) {
-            if (!ValidateFramebufferAttachmentEnum(this, funcName, attachment))
-                return false;
-        }
-    } else {
-        for (const auto& attachment : attachments) {
-            if (!ValidateBackbufferAttachmentEnum(this, funcName, attachment))
-                return false;
-        }
-
-        if (!isDefaultFB) {
-            MOZ_ASSERT(scopedVector->empty());
-            scopedVector->reserve(attachments.Length());
-            for (const auto& attachment : attachments) {
-                switch (attachment) {
-                case LOCAL_GL_COLOR:
-                    scopedVector->push_back(LOCAL_GL_COLOR_ATTACHMENT0);
-                    break;
-
-                case LOCAL_GL_DEPTH:
-                    scopedVector->push_back(LOCAL_GL_DEPTH_ATTACHMENT);
-                    break;
-
-                case LOCAL_GL_STENCIL:
-                    scopedVector->push_back(LOCAL_GL_STENCIL_ATTACHMENT);
-                    break;
-
-                default:
-                    MOZ_CRASH();
-                }
-            }
-            *out_glNumAttachments = scopedVector->size();
-            *out_glAttachments = scopedVector->data();
+    const bool badColorAttachmentIsInvalidOp = true;
+    for (size_t i = 0; i < attachments.Length(); i++) {
+        if (!ValidateFramebufferAttachment(fb, attachments[i], funcName,
+                                           badColorAttachmentIsInvalidOp))
+        {
+            return;
         }
     }
 
-    return true;
-}
-
-void
-WebGL2Context::InvalidateFramebuffer(GLenum target,
-                                     const dom::Sequence<GLenum>& attachments,
-                                     ErrorResult& rv)
-{
-    const char funcName[] = "invalidateSubFramebuffer";
+    // InvalidateFramebuffer is a hint to the driver. Should be OK to
+    // skip calls if not supported, for example by OSX 10.9 GL
+    // drivers.
+    if (!gl->IsSupported(gl::GLFeature::invalidate_framebuffer))
+        return;
 
-    std::vector<GLenum> scopedVector;
-    GLsizei glNumAttachments;
-    const GLenum* glAttachments;
-    if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
-                                       &glNumAttachments, &glAttachments))
-    {
-        return;
-    }
-
-    ////
+    if (!fb && !isDefaultFB) {
+        dom::Sequence<GLenum> tmpAttachments;
+        if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
+            rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+            return;
+        }
 
-    // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
-    const bool useFBInvalidation = (mAllowFBInvalidation &&
-                                    gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
-    if (useFBInvalidation) {
-        gl->fInvalidateFramebuffer(target, glNumAttachments, glAttachments);
-        return;
+        gl->fInvalidateFramebuffer(target, tmpAttachments.Length(),
+                                   tmpAttachments.Elements());
+    } else {
+        gl->fInvalidateFramebuffer(target, attachments.Length(), attachments.Elements());
     }
-
-    // Use clear instead?
-    // No-op for now.
 }
 
 void
 WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
                                         GLint x, GLint y, GLsizei width, GLsizei height,
                                         ErrorResult& rv)
 {
     const char funcName[] = "invalidateSubFramebuffer";
 
-    std::vector<GLenum> scopedVector;
-    GLsizei glNumAttachments;
-    const GLenum* glAttachments;
-    if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
-                                       &glNumAttachments, &glAttachments))
-    {
+    if (IsContextLost())
+        return;
+
+    MakeContextCurrent();
+
+    if (!ValidateFramebufferTarget(target, funcName))
+        return;
+
+    if (width < 0 || height < 0) {
+        ErrorInvalidValue("%s: width and height must be >= 0.", funcName);
         return;
     }
 
-    if (!ValidateNonNegative(funcName, "width", width) ||
-        !ValidateNonNegative(funcName, "height", height))
-    {
-        return;
+    const WebGLFramebuffer* fb;
+    bool isDefaultFB;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        fb = mBoundDrawFramebuffer;
+        isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
+        break;
+
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        fb = mBoundReadFramebuffer;
+        isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
+        break;
+
+    default:
+        MOZ_CRASH("GFX: Bad target.");
     }
 
-    ////
-
-    // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
-    const bool useFBInvalidation = (mAllowFBInvalidation &&
-                                    gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
-    if (useFBInvalidation) {
-        gl->fInvalidateSubFramebuffer(target, glNumAttachments, glAttachments, x, y,
-                                      width, height);
-        return;
+    const bool badColorAttachmentIsInvalidOp = true;
+    for (size_t i = 0; i < attachments.Length(); i++) {
+        if (!ValidateFramebufferAttachment(fb, attachments[i], funcName,
+                                           badColorAttachmentIsInvalidOp))
+        {
+            return;
+        }
     }
 
-    // Use clear instead?
-    // No-op for now.
+    // InvalidateFramebuffer is a hint to the driver. Should be OK to
+    // skip calls if not supported, for example by OSX 10.9 GL
+    // drivers.
+    if (!gl->IsSupported(gl::GLFeature::invalidate_framebuffer))
+        return;
+
+    if (!fb && !isDefaultFB) {
+        dom::Sequence<GLenum> tmpAttachments;
+        if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
+            rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+            return;
+        }
+
+        gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(),
+                                      tmpAttachments.Elements(), x, y, width, height);
+    } else {
+        gl->fInvalidateSubFramebuffer(target, attachments.Length(),
+                                      attachments.Elements(), x, y, width, height);
+    }
 }
 
 void
 WebGL2Context::ReadBuffer(GLenum mode)
 {
     const char funcName[] = "readBuffer";
     if (IsContextLost())
         return;
--- a/dom/canvas/WebGL2ContextPrograms.cpp
+++ b/dom/canvas/WebGL2ContextPrograms.cpp
@@ -9,20 +9,20 @@
 #include "WebGLProgram.h"
 
 namespace mozilla {
 
 // -------------------------------------------------------------------------
 // Programs and shaders
 
 GLint
-WebGL2Context::GetFragDataLocation(const WebGLProgram& prog, const nsAString& name)
+WebGL2Context::GetFragDataLocation(WebGLProgram* prog, const nsAString& name)
 {
     if (IsContextLost())
         return -1;
 
     if (!ValidateObject("getFragDataLocation: program", prog))
         return -1;
 
-    return prog.GetFragDataLocation(name);
+    return prog->GetFragDataLocation(name);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGL2ContextQueries.cpp
+++ b/dom/canvas/WebGL2ContextQueries.cpp
@@ -73,58 +73,73 @@ WebGLContext::CreateQuery(const char* fu
 
 void
 WebGLContext::DeleteQuery(WebGLQuery* query, const char* funcName)
 {
     if (!funcName) {
         funcName = "deleteQuery";
     }
 
-    if (!ValidateDeleteObject(funcName, query))
+    if (IsContextLost())
+        return;
+
+    if (!query)
+        return;
+
+    if (!ValidateObjectAllowDeleted(funcName, query))
         return;
 
     query->DeleteQuery();
 }
 
 bool
 WebGLContext::IsQuery(const WebGLQuery* query, const char* funcName)
 {
     if (!funcName) {
         funcName = "isQuery";
     }
 
-    if (!ValidateIsObject(funcName, query))
+    if (IsContextLost())
+        return false;
+
+    if (!query)
+        return false;
+
+    if (!ValidateObjectAllowDeleted("isQuery", query))
         return false;
 
     return query->IsQuery();
 }
 
 void
-WebGLContext::BeginQuery(GLenum target, WebGLQuery& query, const char* funcName)
+WebGLContext::BeginQuery(GLenum target, WebGLQuery* query, const char* funcName)
 {
     if (!funcName) {
         funcName = "beginQuery";
     }
 
     if (IsContextLost())
         return;
 
-    if (!ValidateObject(funcName, query))
+    if (!ValidateObjectAllowDeleted(funcName, query))
         return;
 
+    if (query->IsDeleted())
+        return ErrorInvalidOperation("%s: Cannot begin a deleted query.", funcName);
+
     const auto& slot = ValidateQuerySlotByTarget(funcName, target);
     if (!slot)
         return;
 
     if (*slot)
         return ErrorInvalidOperation("%s: Query target already active.", funcName);
 
     ////
 
-    query.BeginQuery(target, *slot);
+    query->BeginQuery(target, *slot);
 }
 
 void
 WebGLContext::EndQuery(GLenum target, const char* funcName)
 {
     if (!funcName) {
         funcName = "endQuery";
     }
@@ -207,26 +222,29 @@ WebGLContext::GetQuery(JSContext* cx, GL
         break;
     }
 
     ErrorInvalidEnum("%s: Bad pname.", funcName);
     return;
 }
 
 void
-WebGLContext::GetQueryParameter(JSContext*, const WebGLQuery& query, GLenum pname,
+WebGLContext::GetQueryParameter(JSContext*, const WebGLQuery* query, GLenum pname,
                                 JS::MutableHandleValue retval, const char* funcName)
 {
     if (!funcName) {
         funcName = "getQueryParameter";
     }
 
     retval.setNull();
     if (IsContextLost())
         return;
 
-    if (!ValidateObject(funcName, query))
+    if (!ValidateObjectAllowDeleted(funcName, query))
         return;
 
-    query.GetQueryParameter(pname, retval);
+    if (query->IsDeleted())
+        return ErrorInvalidOperation("%s: Query must not be deleted.", funcName);
+
+    query->GetQueryParameter(pname, retval);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGL2ContextSamplers.cpp
+++ b/dom/canvas/WebGL2ContextSamplers.cpp
@@ -21,127 +21,217 @@ WebGL2Context::CreateSampler()
 
     RefPtr<WebGLSampler> globj = new WebGLSampler(this, sampler);
     return globj.forget();
 }
 
 void
 WebGL2Context::DeleteSampler(WebGLSampler* sampler)
 {
-    if (!ValidateDeleteObject("deleteSampler", sampler))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteSampler", sampler))
+        return;
+
+    if (!sampler || sampler->IsDeleted())
         return;
 
     for (int n = 0; n < mGLMaxTextureUnits; n++) {
         if (mBoundSamplers[n] == sampler) {
             mBoundSamplers[n] = nullptr;
 
             InvalidateResolveCacheForTextureWithTexUnit(n);
         }
     }
 
     sampler->RequestDelete();
 }
 
 bool
-WebGL2Context::IsSampler(const WebGLSampler* sampler)
+WebGL2Context::IsSampler(WebGLSampler* sampler)
 {
-    if (!ValidateIsObject("isSampler", sampler))
+    if (IsContextLost())
+        return false;
+
+    if (!sampler)
+        return false;
+
+    if (!ValidateObjectAllowDeleted("isSampler", sampler))
+        return false;
+
+    if (sampler->IsDeleted())
         return false;
 
     MakeContextCurrent();
     return gl->fIsSampler(sampler->mGLName);
 }
 
 void
 WebGL2Context::BindSampler(GLuint unit, WebGLSampler* sampler)
 {
     if (IsContextLost())
         return;
 
-    if (sampler && !ValidateObject("bindSampler", *sampler))
+    if (!ValidateObjectAllowDeletedOrNull("bindSampler", sampler))
         return;
 
     if (GLint(unit) >= mGLMaxTextureUnits)
         return ErrorInvalidValue("bindSampler: unit must be < %d", mGLMaxTextureUnits);
 
-    ////
+    if (sampler && sampler->IsDeleted())
+        return ErrorInvalidOperation("bindSampler: binding deleted sampler");
 
-    gl->MakeCurrent();
-    gl->fBindSampler(unit, sampler ? sampler->mGLName : 0);
+    WebGLContextUnchecked::BindSampler(unit, sampler);
+    InvalidateResolveCacheForTextureWithTexUnit(unit);
 
-    InvalidateResolveCacheForTextureWithTexUnit(unit);
     mBoundSamplers[unit] = sampler;
 }
 
 void
-WebGL2Context::SamplerParameteri(WebGLSampler& sampler, GLenum pname, GLint paramInt)
+WebGL2Context::SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param)
 {
-    const char funcName[] = "samplerParameteri";
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameteri: invalid sampler");
+
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameteri"))
+        return;
+
+    sampler->SamplerParameter1i(pname, param);
+    WebGLContextUnchecked::SamplerParameteri(sampler, pname, param);
+}
+
+void
+WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Int32Array& param)
+{
     if (IsContextLost())
         return;
 
-    if (!ValidateObject(funcName, sampler))
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameteriv: invalid sampler");
+
+    param.ComputeLengthAndData();
+    if (param.Length() < 1)
+        return /* TODO(djg): Error message */;
+
+    /* TODO(djg): All of these calls in ES3 only take 1 param */
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameteriv"))
         return;
 
-    sampler.SamplerParameter(funcName, pname, paramInt);
+    sampler->SamplerParameter1i(pname, param.Data()[0]);
+    WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Data());
+}
+
+void
+WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLint>& param)
+{
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameteriv: invalid sampler");
+
+    if (param.Length() < 1)
+        return /* TODO(djg): Error message */;
+
+    /* TODO(djg): All of these calls in ES3 only take 1 param */
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameteriv"))
+        return;
+
+    sampler->SamplerParameter1i(pname, param[0]);
+    WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Elements());
 }
 
 void
-WebGL2Context::SamplerParameterf(WebGLSampler& sampler, GLenum pname, GLfloat paramFloat)
+WebGL2Context::SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param)
 {
-    const char funcName[] = "samplerParameterf";
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameterf: invalid sampler");
+
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameterf"))
+        return;
+
+    sampler->SamplerParameter1f(pname, param);
+    WebGLContextUnchecked::SamplerParameterf(sampler, pname, param);
+}
+
+void
+WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Float32Array& param)
+{
     if (IsContextLost())
         return;
 
-    if (!ValidateObject(funcName, sampler))
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameterfv: invalid sampler");
+
+    param.ComputeLengthAndData();
+    if (param.Length() < 1)
+        return /* TODO(djg): Error message */;
+
+    /* TODO(djg): All of these calls in ES3 only take 1 param */
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameterfv"))
         return;
 
-    sampler.SamplerParameter(funcName, pname, WebGLIntOrFloat(paramFloat).AsInt());
+    sampler->SamplerParameter1f(pname, param.Data()[0]);
+    WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Data());
 }
 
 void
-WebGL2Context::GetSamplerParameter(JSContext*, const WebGLSampler& sampler, GLenum pname,
-                                   JS::MutableHandleValue retval)
+WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLfloat>& param)
 {
-    const char funcName[] = "getSamplerParameter";
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameterfv: invalid sampler");
+
+    if (param.Length() < 1)
+        return /* TODO(djg): Error message */;
+
+    /* TODO(djg): All of these calls in ES3 only take 1 param */
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameterfv"))
+        return;
+
+    sampler->SamplerParameter1f(pname, param[0]);
+    WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Elements());
+}
+
+void
+WebGL2Context::GetSamplerParameter(JSContext*, WebGLSampler* sampler, GLenum pname, JS::MutableHandleValue retval)
+{
     retval.setNull();
 
     if (IsContextLost())
         return;
 
-    if (!ValidateObject(funcName, sampler))
-        return;
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("getSamplerParameter: invalid sampler");
 
-    ////
-
-    gl->MakeCurrent();
+    if (!ValidateSamplerParameterName(pname, "getSamplerParameter"))
+        return;
 
     switch (pname) {
     case LOCAL_GL_TEXTURE_MIN_FILTER:
     case LOCAL_GL_TEXTURE_MAG_FILTER:
     case LOCAL_GL_TEXTURE_WRAP_S:
     case LOCAL_GL_TEXTURE_WRAP_T:
     case LOCAL_GL_TEXTURE_WRAP_R:
     case LOCAL_GL_TEXTURE_COMPARE_MODE:
     case LOCAL_GL_TEXTURE_COMPARE_FUNC:
-        {
-            GLint param = 0;
-            gl->fGetSamplerParameteriv(sampler.mGLName, pname, &param);
-            retval.set(JS::Int32Value(param));
-        }
+        retval.set(JS::Int32Value(
+            WebGLContextUnchecked::GetSamplerParameteriv(sampler, pname)));
         return;
 
     case LOCAL_GL_TEXTURE_MIN_LOD:
     case LOCAL_GL_TEXTURE_MAX_LOD:
-        {
-            GLfloat param = 0;
-            gl->fGetSamplerParameterfv(sampler.mGLName, pname, &param);
-            retval.set(JS::Float32Value(param));
-        }
-        return;
-
-    default:
-        ErrorInvalidEnum("%s: invalid pname: %s", funcName, EnumName(pname));
+        retval.set(JS::Float32Value(
+            WebGLContextUnchecked::GetSamplerParameterfv(sampler, pname)));
         return;
     }
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGL2ContextSync.cpp
+++ b/dom/canvas/WebGL2ContextSync.cpp
@@ -11,120 +11,124 @@
 namespace mozilla {
 
 // -------------------------------------------------------------------------
 // Sync objects
 
 already_AddRefed<WebGLSync>
 WebGL2Context::FenceSync(GLenum condition, GLbitfield flags)
 {
-    if (IsContextLost())
-        return nullptr;
+   if (IsContextLost())
+       return nullptr;
 
-    if (condition != LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE) {
-        ErrorInvalidEnum("fenceSync: condition must be SYNC_GPU_COMMANDS_COMPLETE");
-        return nullptr;
-    }
+   if (condition != LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE) {
+       ErrorInvalidEnum("fenceSync: condition must be SYNC_GPU_COMMANDS_COMPLETE");
+       return nullptr;
+   }
 
-    if (flags != 0) {
-        ErrorInvalidValue("fenceSync: flags must be 0");
-        return nullptr;
-    }
+   if (flags != 0) {
+       ErrorInvalidValue("fenceSync: flags must be 0");
+       return nullptr;
+   }
 
-    MakeContextCurrent();
-    RefPtr<WebGLSync> globj = new WebGLSync(this, condition, flags);
-    return globj.forget();
+   MakeContextCurrent();
+   RefPtr<WebGLSync> globj = new WebGLSync(this, condition, flags);
+   return globj.forget();
 }
 
 bool
-WebGL2Context::IsSync(const WebGLSync* sync)
+WebGL2Context::IsSync(WebGLSync* sync)
 {
-    if (!ValidateIsObject("isSync", sync))
-        return false;
+   if (IsContextLost())
+       return false;
 
-    return true;
+   return ValidateObjectAllowDeleted("isSync", sync) && !sync->IsDeleted();
 }
 
 void
 WebGL2Context::DeleteSync(WebGLSync* sync)
 {
-    if (!ValidateDeleteObject("deleteSync", sync))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteSync", sync))
+        return;
+
+    if (!sync || sync->IsDeleted())
         return;
 
     sync->RequestDelete();
 }
 
 GLenum
-WebGL2Context::ClientWaitSync(const WebGLSync& sync, GLbitfield flags, GLuint64 timeout)
+WebGL2Context::ClientWaitSync(WebGLSync* sync, GLbitfield flags, GLuint64 timeout)
 {
-    const char funcName[] = "clientWaitSync";
     if (IsContextLost())
         return LOCAL_GL_WAIT_FAILED;
 
-    if (!ValidateObject(funcName, sync))
+    if (!sync || sync->IsDeleted()) {
+        ErrorInvalidValue("clientWaitSync: sync is not a sync object.");
         return LOCAL_GL_WAIT_FAILED;
+    }
 
     if (flags != 0 && flags != LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT) {
-        ErrorInvalidValue("%s: `flags` must be SYNC_FLUSH_COMMANDS_BIT or 0.", funcName);
+        ErrorInvalidValue("clientWaitSync: flag must be SYNC_FLUSH_COMMANDS_BIT or 0");
         return LOCAL_GL_WAIT_FAILED;
     }
 
     MakeContextCurrent();
-    return gl->fClientWaitSync(sync.mGLName, flags, timeout);
+    return gl->fClientWaitSync(sync->mGLName, flags, timeout);
 }
 
 void
-WebGL2Context::WaitSync(const WebGLSync& sync, GLbitfield flags, GLint64 timeout)
+WebGL2Context::WaitSync(WebGLSync* sync, GLbitfield flags, GLuint64 timeout)
 {
-    const char funcName[] = "waitSync";
     if (IsContextLost())
         return;
 
-    if (!ValidateObject(funcName, sync))
-        return;
-
-    if (flags != 0) {
-        ErrorInvalidValue("%s: `flags` must be 0.", funcName);
+    if (!sync || sync->IsDeleted()) {
+        ErrorInvalidValue("waitSync: sync is not a sync object.");
         return;
     }
 
-    if (timeout != -1) {
-        ErrorInvalidValue("%s: `timeout` must be TIMEOUT_IGNORED.", funcName);
+    if (flags != 0) {
+        ErrorInvalidValue("waitSync: flags must be 0");
+        return;
+    }
+
+    if (timeout != LOCAL_GL_TIMEOUT_IGNORED) {
+        ErrorInvalidValue("waitSync: timeout must be TIMEOUT_IGNORED");
         return;
     }
 
     MakeContextCurrent();
-    gl->fWaitSync(sync.mGLName, flags, LOCAL_GL_TIMEOUT_IGNORED);
+    gl->fWaitSync(sync->mGLName, flags, timeout);
 }
 
 void
-WebGL2Context::GetSyncParameter(JSContext*, const WebGLSync& sync, GLenum pname,
-                                JS::MutableHandleValue retval)
+WebGL2Context::GetSyncParameter(JSContext*, WebGLSync* sync, GLenum pname, JS::MutableHandleValue retval)
 {
-    const char funcName[] = "getSyncParameter";
-    retval.setNull();
     if (IsContextLost())
         return;
 
-    if (!ValidateObject(funcName, sync))
+    if (!sync || sync->IsDeleted()) {
+        ErrorInvalidValue("getSyncParameter: sync is not a sync object.");
         return;
+    }
 
-    ////
-
-    gl->MakeCurrent();
+    retval.set(JS::NullValue());
 
     GLint result = 0;
     switch (pname) {
     case LOCAL_GL_OBJECT_TYPE:
     case LOCAL_GL_SYNC_STATUS:
     case LOCAL_GL_SYNC_CONDITION:
     case LOCAL_GL_SYNC_FLAGS:
-        gl->fGetSynciv(sync.mGLName, pname, 1, nullptr, &result);
+        MakeContextCurrent();
+        gl->fGetSynciv(sync->mGLName, pname, 1, nullptr, &result);
         retval.set(JS::Int32Value(result));
         return;
+    }
 
-    default:
-        ErrorInvalidEnum("%s: Invalid pname 0x%04x", funcName, pname);
-        return;
-    }
+    ErrorInvalidEnum("getSyncParameter: Invalid pname 0x%04x", pname);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGL2ContextTransformFeedback.cpp
+++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp
@@ -27,54 +27,66 @@ WebGL2Context::CreateTransformFeedback()
     RefPtr<WebGLTransformFeedback> ret = new WebGLTransformFeedback(this, tf);
     return ret.forget();
 }
 
 void
 WebGL2Context::DeleteTransformFeedback(WebGLTransformFeedback* tf)
 {
     const char funcName[] = "deleteTransformFeedback";
-    if (!ValidateDeleteObject(funcName, tf))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObject(funcName, tf))
         return;
 
     if (tf->mIsActive) {
         ErrorInvalidOperation("%s: Cannot delete active transform feedbacks.", funcName);
         return;
     }
 
     if (mBoundTransformFeedback == tf) {
         BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr);
     }
 
     tf->RequestDelete();
 }
 
 bool
-WebGL2Context::IsTransformFeedback(const WebGLTransformFeedback* tf)
+WebGL2Context::IsTransformFeedback(WebGLTransformFeedback* tf)
 {
-    if (!ValidateIsObject("isTransformFeedback", tf))
+    if (IsContextLost())
+        return false;
+
+    if (!ValidateObjectAllowDeletedOrNull("isTransformFeedback", tf))
+        return false;
+
+    if (!tf || tf->IsDeleted())
         return false;
 
     MakeContextCurrent();
     return gl->fIsTransformFeedback(tf->mGLName);
 }
 
 void
 WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf)
 {
     const char funcName[] = "bindTransformFeedback";
     if (IsContextLost())
         return;
 
     if (target != LOCAL_GL_TRANSFORM_FEEDBACK)
         return ErrorInvalidEnum("%s: `target` must be TRANSFORM_FEEDBACK.", funcName);
 
-    if (tf && !ValidateObject(funcName, *tf))
+    if (!ValidateObjectAllowDeletedOrNull(funcName, tf))
         return;
 
+    if (tf && tf->IsDeleted())
+        return ErrorInvalidOperation("%s: TFO already deleted.", funcName);
+
     if (mBoundTransformFeedback->mIsActive &&
         !mBoundTransformFeedback->mIsPaused)
     {
         ErrorInvalidOperation("%s: Currently bound transform feedback is active and not"
                               " paused.",
                               funcName);
         return;
     }
@@ -119,34 +131,34 @@ WebGL2Context::ResumeTransformFeedback()
 {
     if (IsContextLost())
         return;
 
     mBoundTransformFeedback->ResumeTransformFeedback();
 }
 
 void
-WebGL2Context::TransformFeedbackVaryings(WebGLProgram& program,
+WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program,
                                          const dom::Sequence<nsString>& varyings,
                                          GLenum bufferMode)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("transformFeedbackVaryings: program", program))
         return;
 
-    program.TransformFeedbackVaryings(varyings, bufferMode);
+    program->TransformFeedbackVaryings(varyings, bufferMode);
 }
 
 already_AddRefed<WebGLActiveInfo>
-WebGL2Context::GetTransformFeedbackVarying(const WebGLProgram& program, GLuint index)
+WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getTransformFeedbackVarying: program", program))
         return nullptr;
 
-    return program.GetTransformFeedbackVarying(index);
+    return program->GetTransformFeedbackVarying(index);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGL2ContextUniforms.cpp
+++ b/dom/canvas/WebGL2ContextUniforms.cpp
@@ -125,31 +125,31 @@ WebGL2Context::GetIndexedParameter(JSCon
         ret = JS::NumberValue(binding.mRangeSize);
         break;
     }
 
     retval.set(ret);
 }
 
 void
-WebGL2Context::GetUniformIndices(const WebGLProgram& program,
+WebGL2Context::GetUniformIndices(WebGLProgram* program,
                                  const dom::Sequence<nsString>& uniformNames,
                                  dom::Nullable< nsTArray<GLuint> >& retval)
 {
     retval.SetNull();
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getUniformIndices: program", program))
         return;
 
     if (!uniformNames.Length())
         return;
 
-    program.GetUniformIndices(uniformNames, retval);
+    program->GetUniformIndices(uniformNames, retval);
 }
 
 static bool
 ValidateUniformEnum(WebGLContext* webgl, GLenum pname, const char* info)
 {
     switch (pname) {
     case LOCAL_GL_UNIFORM_TYPE:
     case LOCAL_GL_UNIFORM_SIZE:
@@ -162,139 +162,149 @@ ValidateUniformEnum(WebGLContext* webgl,
 
     default:
         webgl->ErrorInvalidEnum("%s: invalid pname: %s", info, webgl->EnumName(pname));
         return false;
     }
 }
 
 void
-WebGL2Context::GetActiveUniforms(JSContext* cx, const WebGLProgram& program,
+WebGL2Context::GetActiveUniforms(JSContext* cx,
+                                 WebGLProgram* program,
                                  const dom::Sequence<GLuint>& uniformIndices,
-                                 GLenum pname, JS::MutableHandleValue retval)
+                                 GLenum pname,
+                                 JS::MutableHandleValue retval)
 {
-    const char funcName[] = "getActiveUniforms";
-    retval.setNull();
+    retval.set(JS::NullValue());
     if (IsContextLost())
         return;
 
-    if (!ValidateUniformEnum(this, pname, funcName))
+    if (!ValidateUniformEnum(this, pname, "getActiveUniforms"))
         return;
 
     if (!ValidateObject("getActiveUniforms: program", program))
         return;
 
-    const auto& count = uniformIndices.Length();
+    size_t count = uniformIndices.Length();
+    if (!count)
+        return;
+
+    GLuint progname = program->mGLName;
+    Vector<GLint> samples;
+    if (!samples.resize(count)) {
+        return;
+    }
+
+    MakeContextCurrent();
+    gl->fGetActiveUniformsiv(progname, count, uniformIndices.Elements(), pname,
+                             samples.begin());
 
     JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, count));
-    UniquePtr<GLint[]> samples(new GLint[count]);
-    if (!array || !samples) {
-        ErrorOutOfMemory("%s: Failed to allocate buffers.", funcName);
+    if (!array) {
         return;
     }
-    retval.setObject(*array);
-
-    MakeContextCurrent();
-    gl->fGetActiveUniformsiv(program.mGLName, count, uniformIndices.Elements(), pname,
-                             samples.get());
 
     switch (pname) {
     case LOCAL_GL_UNIFORM_TYPE:
     case LOCAL_GL_UNIFORM_SIZE:
     case LOCAL_GL_UNIFORM_BLOCK_INDEX:
     case LOCAL_GL_UNIFORM_OFFSET:
     case LOCAL_GL_UNIFORM_ARRAY_STRIDE:
     case LOCAL_GL_UNIFORM_MATRIX_STRIDE:
-        for (size_t i = 0; i < count; ++i) {
+        for (uint32_t i = 0; i < count; ++i) {
             JS::RootedValue value(cx);
             value = JS::Int32Value(samples[i]);
-            if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE))
+            if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE)) {
                 return;
+            }
         }
         break;
     case LOCAL_GL_UNIFORM_IS_ROW_MAJOR:
-        for (size_t i = 0; i < count; ++i) {
+        for (uint32_t i = 0; i < count; ++i) {
             JS::RootedValue value(cx);
             value = JS::BooleanValue(samples[i]);
-            if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE))
+            if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE)) {
                 return;
+            }
         }
         break;
 
     default:
-        MOZ_CRASH("Invalid pname");
+        return;
     }
+
+    retval.setObjectOrNull(array);
 }
 
 GLuint
-WebGL2Context::GetUniformBlockIndex(const WebGLProgram& program,
+WebGL2Context::GetUniformBlockIndex(WebGLProgram* program,
                                     const nsAString& uniformBlockName)
 {
     if (IsContextLost())
         return 0;
 
     if (!ValidateObject("getUniformBlockIndex: program", program))
         return 0;
 
-    return program.GetUniformBlockIndex(uniformBlockName);
+    return program->GetUniformBlockIndex(uniformBlockName);
 }
 
 void
-WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, const WebGLProgram& program,
+WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* program,
                                               GLuint uniformBlockIndex, GLenum pname,
                                               JS::MutableHandleValue out_retval,
                                               ErrorResult& out_error)
 {
-    out_retval.setNull();
+    out_retval.set(JS::NullValue());
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getActiveUniformBlockParameter: program", program))
         return;
 
     MakeContextCurrent();
 
     switch(pname) {
     case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
     case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
     case LOCAL_GL_UNIFORM_BLOCK_BINDING:
     case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE:
     case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
-        out_retval.set(program.GetActiveUniformBlockParam(uniformBlockIndex, pname));
+        out_retval.set(program->GetActiveUniformBlockParam(uniformBlockIndex, pname));
         return;
 
     case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
-        out_retval.set(program.GetActiveUniformBlockActiveUniforms(cx, uniformBlockIndex,
-                                                                   &out_error));
+        out_retval.set(program->GetActiveUniformBlockActiveUniforms(cx, uniformBlockIndex,
+                                                                    &out_error));
         return;
     }
 
     ErrorInvalidEnumInfo("getActiveUniformBlockParameter: parameter", pname);
 }
 
 void
-WebGL2Context::GetActiveUniformBlockName(const WebGLProgram& program,
-                                         GLuint uniformBlockIndex, nsAString& retval)
+WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex,
+                                         nsAString& retval)
 {
     retval.SetIsVoid(true);
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getActiveUniformBlockName: program", program))
         return;
 
-    program.GetActiveUniformBlockName(uniformBlockIndex, retval);
+    program->GetActiveUniformBlockName(uniformBlockIndex, retval);
 }
 
 void
-WebGL2Context::UniformBlockBinding(WebGLProgram& program, GLuint uniformBlockIndex,
+WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex,
                                    GLuint uniformBlockBinding)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("uniformBlockBinding: program", program))
         return;
 
-    program.UniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
+    program->UniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -8,27 +8,30 @@
 #include "GLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "WebGLContext.h"
 #include "WebGLElementArrayCache.h"
 
 namespace mozilla {
 
 WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(buf)
     , mContent(Kind::Undefined)
     , mUsage(LOCAL_GL_STATIC_DRAW)
     , mByteLength(0)
+    , mNumActiveTFOs(0)
+    , mBoundForTF(false)
 {
     mContext->mBuffers.insertBack(this);
 }
 
 WebGLBuffer::~WebGLBuffer()
 {
+    MOZ_ASSERT(!mNumActiveTFOs);
     DeleteOnce();
 }
 
 void
 WebGLBuffer::SetContentAfterBind(GLenum target)
 {
     if (mContent != Kind::Undefined)
         return;
@@ -103,16 +106,23 @@ 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;
 
+    if (mNumActiveTFOs) {
+        mContext->ErrorInvalidOperation("%s: Buffer is bound to an active transform"
+                                        " feedback object.",
+                                        funcName);
+        return;
+    }
+
     const auto& gl = mContext->gl;
     gl->MakeCurrent();
     const ScopedLazyBind lazyBind(gl, target, this);
     mContext->InvalidateBufferFetching();
 
 #ifdef XP_MACOSX
     // bug 790879
     if (gl->WorkAroundDriverBugs() &&
@@ -205,16 +215,25 @@ bool
 WebGLBuffer::IsElementArrayUsedWithMultipleTypes() const
 {
     return mCache->BeenUsedWithMultipleTypes();
 }
 
 bool
 WebGLBuffer::ValidateCanBindToTarget(const char* funcName, GLenum target)
 {
+    const bool wouldBeTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
+    if (mWebGLRefCnt && wouldBeTF != mBoundForTF) {
+        mContext->ErrorInvalidOperation("%s: Buffers cannot be simultaneously bound to "
+                                        " transform feedback and bound elsewhere.",
+                                        funcName);
+        return false;
+    }
+    mBoundForTF = wouldBeTF;
+
     /* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
      *
      * In the WebGL 2 API, buffers have their WebGL buffer type
      * initially set to undefined. Calling bindBuffer, bindBufferRange
      * or bindBufferBase with the target argument set to any buffer
      * binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will
      * then set the WebGL buffer type of the buffer being bound
      * according to the table above.
--- a/dom/canvas/WebGLBuffer.h
+++ b/dom/canvas/WebGLBuffer.h
@@ -17,16 +17,17 @@
 namespace mozilla {
 
 class WebGLElementArrayCache;
 
 class WebGLBuffer final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLBuffer>
     , public LinkedListElement<WebGLBuffer>
+    , public WebGLContextBoundObject
 {
     friend class WebGLContext;
     friend class WebGL2Context;
     friend class WebGLTexture;
     friend class WebGLTransformFeedback;
 
 public:
     enum class Kind {
@@ -73,13 +74,15 @@ public:
 
 protected:
     ~WebGLBuffer();
 
     Kind mContent;
     GLenum mUsage;
     size_t mByteLength;
     UniquePtr<WebGLElementArrayCache> mCache;
+    size_t mNumActiveTFOs;
+    bool mBoundForTF;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_BUFFER_H_
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -115,23 +115,21 @@ WebGLContextOptions::WebGLContextOptions
 WebGLContext::WebGLContext()
     : WebGLContextUnchecked(nullptr)
     , mBufferFetchingIsVerified(false)
     , mBufferFetchingHasPerVertex(false)
     , mMaxFetchedVertices(0)
     , mMaxFetchedInstances(0)
     , mLayerIsMirror(false)
     , mBypassShaderValidation(false)
-    , mBuffersForUB_Dirty(true)
     , mContextLossHandler(this)
     , mNeedsFakeNoAlpha(false)
     , mNeedsFakeNoDepth(false)
     , mNeedsFakeNoStencil(false)
     , mNeedsEmulatedLoneDepthStencil(false)
-    , mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation())
 {
     mGeneration = 0;
     mInvalidated = false;
     mCapturedFrameInvalidated = false;
     mShouldPresent = true;
     mResetLayer = true;
     mOptionsFrozen = false;
     mMinCapability = false;
@@ -217,17 +215,17 @@ WebGLContext::~WebGLContext()
     DestroyResourcesAndContext();
     if (NS_IsMainThread()) {
         // XXX mtseng: bug 709490, not thread safe
         WebGLMemoryTracker::RemoveWebGLContext(this);
     }
 }
 
 template<typename T>
-void
+static void
 ClearLinkedList(LinkedList<T>& list)
 {
     while (!list.isEmpty()) {
         list.getLast()->DeleteOnce();
     }
 }
 
 void
@@ -259,17 +257,16 @@ WebGLContext::DestroyResourcesAndContext
     mBoundTransformFeedback = nullptr;
     mDefaultTransformFeedback = nullptr;
 
     mQuerySlot_SamplesPassed = nullptr;
     mQuerySlot_TFPrimsWritten = nullptr;
     mQuerySlot_TimeElapsed = nullptr;
 
     mIndexedUniformBufferBindings.clear();
-    OnUBIndexedBindingsChanged();
 
     //////
 
     ClearLinkedList(mBuffers);
     ClearLinkedList(mFramebuffers);
     ClearLinkedList(mPrograms);
     ClearLinkedList(mQueries);
     ClearLinkedList(mRenderbuffers);
@@ -2217,16 +2214,200 @@ Intersect(uint32_t srcSize, int32_t dstS
     // [=====|==]    // dst box
     // ^-----^
     *out_intStartInDst = std::max<int32_t>(0, 0 - dstStartInSrc);
 
     int32_t intEndInSrc = std::min<int32_t>(srcSize, dstStartInSrc + dstSize);
     *out_intSize = std::max<int32_t>(0, intEndInSrc - *out_intStartInSrc);
 }
 
+static bool
+ZeroTexImageWithClear(WebGLContext* webgl, GLContext* gl, TexImageTarget target,
+                      GLuint tex, uint32_t level, const webgl::FormatUsageInfo* usage,
+                      uint32_t width, uint32_t height)
+{
+    MOZ_ASSERT(gl->IsCurrent());
+
+    ScopedFramebuffer scopedFB(gl);
+    ScopedBindFramebuffer scopedBindFB(gl, scopedFB.FB());
+
+    const auto format = usage->format;
+
+    GLenum attachPoint = 0;
+    GLbitfield clearBits = 0;
+
+    if (format->IsColorFormat()) {
+        attachPoint = LOCAL_GL_COLOR_ATTACHMENT0;
+        clearBits = LOCAL_GL_COLOR_BUFFER_BIT;
+    }
+
+    if (format->d) {
+        attachPoint = LOCAL_GL_DEPTH_ATTACHMENT;
+        clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
+    }
+
+    if (format->s) {
+        attachPoint = (format->d ? LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
+                                 : LOCAL_GL_STENCIL_ATTACHMENT);
+        clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
+    }
+
+    MOZ_RELEASE_ASSERT(attachPoint && clearBits, "GFX: No bits cleared.");
+
+    {
+        gl::GLContext::LocalErrorScope errorScope(*gl);
+        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachPoint, target.get(), tex,
+                                  level);
+        if (errorScope.GetError()) {
+            MOZ_ASSERT(false);
+            return false;
+        }
+    }
+
+    auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
+        return false;
+
+    {
+        gl::GLContext::LocalErrorScope errorScope(*gl);
+
+        const bool fakeNoAlpha = false;
+        webgl->ForceClearFramebufferWithDefaultValues(clearBits, fakeNoAlpha);
+        if (errorScope.GetError()) {
+            MOZ_ASSERT(false);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool
+ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex,
+                TexImageTarget target, uint32_t level,
+                const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
+                uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth)
+{
+    // This has two usecases:
+    // 1. Lazy zeroing of uninitialized textures:
+    //    a. Before draw, when FakeBlack isn't viable. (TexStorage + Draw*)
+    //    b. Before partial upload. (TexStorage + TexSubImage)
+    // 2. Zero subrects from out-of-bounds blits. (CopyTex(Sub)Image)
+
+    // We have no sympathy for any of these cases.
+
+    // "Doctor, it hurts when I do this!" "Well don't do that!"
+    webgl->GenerateWarning("%s: This operation requires zeroing texture data. This is"
+                           " slow.",
+                           funcName);
+
+    gl::GLContext* gl = webgl->GL();
+    gl->MakeCurrent();
+
+    GLenum scopeBindTarget;
+    switch (target.get()) {
+    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        scopeBindTarget = LOCAL_GL_TEXTURE_CUBE_MAP;
+        break;
+    default:
+        scopeBindTarget = target.get();
+        break;
+    }
+    ScopedBindTexture scopeBindTexture(gl, tex, scopeBindTarget);
+    auto compression = usage->format->compression;
+    if (compression) {
+        MOZ_RELEASE_ASSERT(!xOffset && !yOffset && !zOffset, "GFX: Can't zero compressed texture with offsets.");
+
+        auto sizedFormat = usage->format->sizedFormat;
+        MOZ_RELEASE_ASSERT(sizedFormat, "GFX: texture sized format not set");
+
+        const auto fnSizeInBlocks = [](CheckedUint32 pixels, uint8_t pixelsPerBlock) {
+            return RoundUpToMultipleOf(pixels, pixelsPerBlock) / pixelsPerBlock;
+        };
+
+        const auto widthBlocks = fnSizeInBlocks(width, compression->blockWidth);
+        const auto heightBlocks = fnSizeInBlocks(height, compression->blockHeight);
+
+        CheckedUint32 checkedByteCount = compression->bytesPerBlock;
+        checkedByteCount *= widthBlocks;
+        checkedByteCount *= heightBlocks;
+        checkedByteCount *= depth;
+
+        if (!checkedByteCount.isValid())
+            return false;
+
+        const size_t byteCount = checkedByteCount.value();
+
+        UniqueBuffer zeros = calloc(1, byteCount);
+        if (!zeros)
+            return false;
+
+        ScopedUnpackReset scopedReset(webgl);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it
+                                                        // well.
+
+        GLenum error = DoCompressedTexSubImage(gl, target.get(), level, xOffset, yOffset,
+                                               zOffset, width, height, depth, sizedFormat,
+                                               byteCount, zeros.get());
+        if (error)
+            return false;
+
+        return true;
+    }
+
+    const auto driverUnpackInfo = usage->idealUnpack;
+    MOZ_RELEASE_ASSERT(driverUnpackInfo, "GFX: ideal unpack info not set.");
+
+    if (usage->IsRenderable() && depth == 1 &&
+        !xOffset && !yOffset && !zOffset)
+    {
+        // While we would like to skip the extra complexity of trying to zero with an FB
+        // clear, ANGLE_depth_texture requires this.
+        do {
+            if (ZeroTexImageWithClear(webgl, gl, target, tex, level, usage, width,
+                                      height))
+            {
+                return true;
+            }
+        } while (false);
+    }
+
+    const webgl::PackingInfo packing = driverUnpackInfo->ToPacking();
+
+    const auto bytesPerPixel = webgl::BytesPerPixel(packing);
+
+    CheckedUint32 checkedByteCount = bytesPerPixel;
+    checkedByteCount *= width;
+    checkedByteCount *= height;
+    checkedByteCount *= depth;
+
+    if (!checkedByteCount.isValid())
+        return false;
+
+    const size_t byteCount = checkedByteCount.value();
+
+    UniqueBuffer zeros = calloc(1, byteCount);
+    if (!zeros)
+        return false;
+
+    ScopedUnpackReset scopedReset(webgl);
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well.
+    const auto error = DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width,
+                                     height, depth, packing, zeros.get());
+    if (error)
+        return false;
+
+    return true;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 CheckedUint32
 WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
                             uint32_t depth, uint8_t bytesPerPixel)
 {
     if (!width || !height || !depth)
         return 0;
@@ -2384,52 +2565,16 @@ WebGLContext::ValidateArrayBufferView(co
         elemCount = elemCountOverride;
     }
 
     *out_bytes = bytes + (elemOffset * elemSize);
     *out_byteLen = elemCount * elemSize;
     return true;
 }
 
-////
-
-const decltype(WebGLContext::mBuffersForUB)&
-WebGLContext::BuffersForUB() const
-{
-    if (mBuffersForUB_Dirty) {
-        mBuffersForUB.clear();
-        for (const auto& cur : mIndexedUniformBufferBindings) {
-            if (cur.mBufferBinding) {
-                mBuffersForUB.insert(cur.mBufferBinding.get());
-            }
-        }
-        mBuffersForUB_Dirty = false;
-    }
-    return mBuffersForUB;
-}
-
-////
-
-bool
-WebGLContext::ValidateForNonTransformFeedback(const char* funcName, WebGLBuffer* buffer)
-{
-    if (!mBoundTransformFeedback)
-        return true;
-
-    const auto& buffersForTF = mBoundTransformFeedback->BuffersForTF();
-    if (buffersForTF.count(buffer)) {
-        ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for transform"
-                              " feedback.",
-                              funcName);
-        return false;
-    }
-
-    return true;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // XPCOM goop
 
 void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
                             const std::vector<IndexedBufferBinding>& field,
                             const char* name, uint32_t flags)
 {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -158,29 +158,29 @@ struct WebGLContextOptions
     bool antialias;
     bool preserveDrawingBuffer;
     bool failIfMajorPerformanceCaveat;
 };
 
 // From WebGLContextUtils
 TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
 
-struct WebGLIntOrFloat {
-    const enum {
+class WebGLIntOrFloat {
+    enum {
         Int,
         Float,
         Uint
     } mType;
-
     union {
         GLint i;
         GLfloat f;
         GLuint u;
     } mValue;
 
+public:
     explicit WebGLIntOrFloat(GLint i) : mType(Int) { mValue.i = i; }
     explicit WebGLIntOrFloat(GLfloat f) : mType(Float) { mValue.f = f; }
 
     GLint AsInt() const { return (mType == Int) ? mValue.i : NS_lroundf(mValue.f); }
     GLfloat AsFloat() const { return (mType == Float) ? mValue.f : GLfloat(mValue.i); }
 };
 
 struct IndexedBufferBinding
@@ -214,50 +214,50 @@ protected:
         memset(this, 0, sizeof(*this));
     }
 };
 
 ////
 
 struct TexImageSourceAdapter final : public TexImageSource
 {
-    TexImageSourceAdapter(const dom::Nullable<dom::ArrayBufferView>* maybeView,
+    TexImageSourceAdapter(const dom::Nullable<dom::ArrayBufferView>& maybeView,
                           ErrorResult*)
     {
-        if (!maybeView->IsNull()) {
-            mView = &(maybeView->Value());
+        if (!maybeView.IsNull()) {
+            mView = &(maybeView.Value());
         }
     }
 
-    TexImageSourceAdapter(const dom::ArrayBufferView* view, ErrorResult*) {
-        mView = view;
+    TexImageSourceAdapter(const dom::ArrayBufferView& view, ErrorResult*) {
+        mView = &view;
     }
 
-    TexImageSourceAdapter(const dom::ArrayBufferView* view, GLuint viewElemOffset,
+    TexImageSourceAdapter(const dom::ArrayBufferView& view, GLuint viewElemOffset,
                           GLuint viewElemLengthOverride = 0)
     {
-        mView = view;
+        mView = &view;
         mViewElemOffset = viewElemOffset;
         mViewElemLengthOverride = viewElemLengthOverride;
     }
 
-    TexImageSourceAdapter(const WebGLsizeiptr* pboOffset, GLuint ignored1, GLuint ignored2 = 0) {
-        mPboOffset = pboOffset;
+    TexImageSourceAdapter(WebGLsizeiptr pboOffset, GLuint ignored1, GLuint ignored2 = 0) {
+        mPboOffset = &pboOffset;
     }
 
-    TexImageSourceAdapter(const WebGLsizeiptr* pboOffset, ErrorResult* ignored) {
-        mPboOffset = pboOffset;
+    TexImageSourceAdapter(WebGLsizeiptr pboOffset, ErrorResult* ignored) {
+        mPboOffset = &pboOffset;
     }
 
-    TexImageSourceAdapter(const dom::ImageData* imageData, ErrorResult*) {
-        mImageData = imageData;
+    TexImageSourceAdapter(const dom::ImageData& imageData, ErrorResult*) {
+        mImageData = &imageData;
     }
 
-    TexImageSourceAdapter(const dom::Element* domElem, ErrorResult* const out_error) {
-        mDomElem = domElem;
+    TexImageSourceAdapter(const dom::Element& domElem, ErrorResult* const out_error) {
+        mDomElem = &domElem;
         mOut_error = out_error;
     }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class WebGLContext
     : public nsIDOMWebGLRenderingContext
@@ -483,72 +483,77 @@ public:
     void
     GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval);
 
     bool IsContextLost() const { return mContextStatus != ContextNotLost; }
     void GetSupportedExtensions(JSContext* cx,
                                 dom::Nullable< nsTArray<nsString> >& retval);
     void GetExtension(JSContext* cx, const nsAString& name,
                       JS::MutableHandle<JSObject*> retval, ErrorResult& rv);
-    void AttachShader(WebGLProgram& prog, WebGLShader& shader);
-    void BindAttribLocation(WebGLProgram& prog, GLuint location,
+    void AttachShader(WebGLProgram* prog, WebGLShader* shader);
+    void BindAttribLocation(WebGLProgram* prog, GLuint location,
                             const nsAString& name);
     void BindFramebuffer(GLenum target, WebGLFramebuffer* fb);
     void BindRenderbuffer(GLenum target, WebGLRenderbuffer* fb);
     void BindVertexArray(WebGLVertexArray* vao);
     void BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a);
     void BlendEquation(GLenum mode);
     void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
     void BlendFunc(GLenum sfactor, GLenum dfactor);
     void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
                            GLenum srcAlpha, GLenum dstAlpha);
     GLenum CheckFramebufferStatus(GLenum target);
     void Clear(GLbitfield mask);
     void ClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a);
     void ClearDepth(GLclampf v);
     void ClearStencil(GLint v);
     void ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a);
-    void CompileShader(WebGLShader& shader);
+    void CompileShader(WebGLShader* shader);
     void CompileShaderANGLE(WebGLShader* shader);
     void CompileShaderBypass(WebGLShader* shader, const nsCString& shaderSource);
     already_AddRefed<WebGLFramebuffer> CreateFramebuffer();
     already_AddRefed<WebGLProgram> CreateProgram();
     already_AddRefed<WebGLRenderbuffer> CreateRenderbuffer();
     already_AddRefed<WebGLShader> CreateShader(GLenum type);
     already_AddRefed<WebGLVertexArray> CreateVertexArray();
     void CullFace(GLenum face);
     void DeleteFramebuffer(WebGLFramebuffer* fb);
     void DeleteProgram(WebGLProgram* prog);
     void DeleteRenderbuffer(WebGLRenderbuffer* rb);
     void DeleteShader(WebGLShader* shader);
     void DeleteVertexArray(WebGLVertexArray* vao);
     void DepthFunc(GLenum func);
     void DepthMask(WebGLboolean b);
     void DepthRange(GLclampf zNear, GLclampf zFar);
-    void DetachShader(WebGLProgram& prog, const WebGLShader& shader);
+    void DetachShader(WebGLProgram* prog, WebGLShader* shader);
     void DrawBuffers(const dom::Sequence<GLenum>& buffers);
     void Flush();
     void Finish();
     void FramebufferRenderbuffer(GLenum target, GLenum attachment,
                                  GLenum rbTarget, WebGLRenderbuffer* rb);
     void FramebufferTexture2D(GLenum target, GLenum attachment,
                               GLenum texImageTarget, WebGLTexture* tex,
                               GLint level);
 
+    // Framebuffer validation
+    bool ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
+                                       const char* funcName,
+                                       bool badColorAttachmentIsInvalidOp = false);
+
     void FrontFace(GLenum mode);
-    already_AddRefed<WebGLActiveInfo> GetActiveAttrib(const WebGLProgram& prog,
+    already_AddRefed<WebGLActiveInfo> GetActiveAttrib(WebGLProgram* prog,
                                                       GLuint index);
-    already_AddRefed<WebGLActiveInfo> GetActiveUniform(const WebGLProgram& prog,
+    already_AddRefed<WebGLActiveInfo> GetActiveUniform(WebGLProgram* prog,
                                                        GLuint index);
 
     void
-    GetAttachedShaders(const WebGLProgram& prog,
+    GetAttachedShaders(WebGLProgram* prog,
                        dom::Nullable<nsTArray<RefPtr<WebGLShader>>>& retval);
 
-    GLint GetAttribLocation(const WebGLProgram& prog, const nsAString& name);
+    GLint GetAttribLocation(WebGLProgram* prog, const nsAString& name);
     JS::Value GetBufferParameter(GLenum target, GLenum pname);
 
     void GetBufferParameter(JSContext*, GLenum target, GLenum pname,
                             JS::MutableHandle<JS::Value> retval)
     {
         retval.set(GetBufferParameter(target, pname));
     }
 
@@ -561,70 +566,71 @@ public:
                                            GLenum attachment, GLenum pname,
                                            JS::MutableHandle<JS::Value> retval,
                                            ErrorResult& rv)
     {
         retval.set(GetFramebufferAttachmentParameter(cx, target, attachment,
                                                      pname, rv));
     }
 
-    JS::Value GetProgramParameter(const WebGLProgram& prog, GLenum pname);
+    JS::Value GetProgramParameter(WebGLProgram* prog, GLenum pname);
 
-    void  GetProgramParameter(JSContext*, const WebGLProgram& prog, GLenum pname,
+    void  GetProgramParameter(JSContext*, WebGLProgram* prog, GLenum pname,
                               JS::MutableHandle<JS::Value> retval)
     {
         retval.set(GetProgramParameter(prog, pname));
     }
 
-    void GetProgramInfoLog(const WebGLProgram& prog, nsACString& retval);
-    void GetProgramInfoLog(const WebGLProgram& prog, nsAString& retval);
+    void GetProgramInfoLog(WebGLProgram* prog, nsACString& retval);
+    void GetProgramInfoLog(WebGLProgram* prog, nsAString& retval);
     JS::Value GetRenderbufferParameter(GLenum target, GLenum pname);
 
     void GetRenderbufferParameter(JSContext*, GLenum target, GLenum pname,
                                   JS::MutableHandle<JS::Value> retval)
     {
         retval.set(GetRenderbufferParameter(target, pname));
     }
 
-    JS::Value GetShaderParameter(const WebGLShader& shader, GLenum pname);
+    JS::Value GetShaderParameter(WebGLShader* shader, GLenum pname);
 
-    void GetShaderParameter(JSContext*, const WebGLShader& shader, GLenum pname,
+    void GetShaderParameter(JSContext*, WebGLShader* shader, GLenum pname,
                             JS::MutableHandle<JS::Value> retval)
     {
         retval.set(GetShaderParameter(shader, pname));
     }
 
     already_AddRefed<WebGLShaderPrecisionFormat>
     GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype);
 
-    void GetShaderInfoLog(const WebGLShader& shader, nsACString& retval);
-    void GetShaderInfoLog(const WebGLShader& shader, nsAString& retval);
-    void GetShaderSource(const WebGLShader& shader, nsAString& retval);
+    void GetShaderInfoLog(WebGLShader* shader, nsACString& retval);
+    void GetShaderInfoLog(WebGLShader* shader, nsAString& retval);
+    void GetShaderSource(WebGLShader* shader, nsAString& retval);
+    void GetShaderTranslatedSource(WebGLShader* shader, nsAString& retval);
 
-    JS::Value GetUniform(JSContext* cx, const WebGLProgram& prog,
-                         const WebGLUniformLocation& loc);
+    JS::Value GetUniform(JSContext* cx, WebGLProgram* prog,
+                         WebGLUniformLocation* loc);
 
-    void GetUniform(JSContext* cx, const WebGLProgram& prog,
-                    const WebGLUniformLocation& loc,
+    void GetUniform(JSContext* cx, WebGLProgram* prog,
+                    WebGLUniformLocation* loc,
                     JS::MutableHandle<JS::Value> retval)
     {
         retval.set(GetUniform(cx, prog, loc));
     }
 
     already_AddRefed<WebGLUniformLocation>
-    GetUniformLocation(const WebGLProgram& prog, const nsAString& name);
+    GetUniformLocation(WebGLProgram* prog, const nsAString& name);
 
     void Hint(GLenum target, GLenum mode);
-    bool IsFramebuffer(const WebGLFramebuffer* fb);
-    bool IsProgram(const WebGLProgram* prog);
-    bool IsRenderbuffer(const WebGLRenderbuffer* rb);
-    bool IsShader(const WebGLShader* shader);
-    bool IsVertexArray(const WebGLVertexArray* vao);
+    bool IsFramebuffer(WebGLFramebuffer* fb);
+    bool IsProgram(WebGLProgram* prog);
+    bool IsRenderbuffer(WebGLRenderbuffer* rb);
+    bool IsShader(WebGLShader* shader);
+    bool IsVertexArray(WebGLVertexArray* vao);
     void LineWidth(GLfloat width);
-    void LinkProgram(WebGLProgram& prog);
+    void LinkProgram(WebGLProgram* prog);
     void PixelStorei(GLenum pname, GLint param);
     void PolygonOffset(GLfloat factor, GLfloat units);
 
     already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
     bool StartVRPresentation();
 protected:
     bool ReadPixels_SharedPrecheck(ErrorResult* const out_error);
     void ReadPixelsImpl(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
@@ -657,17 +663,17 @@ public:
                              GLsizei width, GLsizei height);
 protected:
     void RenderbufferStorage_base(const char* funcName, GLenum target,
                                   GLsizei samples, GLenum internalformat,
                                   GLsizei width, GLsizei height);
 public:
     void SampleCoverage(GLclampf value, WebGLboolean invert);
     void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
-    void ShaderSource(WebGLShader& shader, const nsAString& source);
+    void ShaderSource(WebGLShader* shader, const nsAString& source);
     void StencilFunc(GLenum func, GLint ref, GLuint mask);
     void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
     void StencilMask(GLuint mask);
     void StencilMaskSeparate(GLenum face, GLuint mask);
     void StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
     void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail,
                            GLenum dppass);
 
@@ -858,17 +864,17 @@ public:
     bool ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
                                           uint8_t setterCols,
                                           uint8_t setterRows,
                                           GLenum setterType,
                                           uint32_t setterArraySize,
                                           bool setterTranspose,
                                           const char* funcName,
                                           uint32_t* out_numElementsToUpload);
-    void ValidateProgram(const WebGLProgram& prog);
+    void ValidateProgram(WebGLProgram* prog);
     bool ValidateUniformLocation(const char* info, WebGLUniformLocation* loc);
     bool ValidateSamplerUniformSetter(const char* info,
                                       WebGLUniformLocation* loc, GLint value);
     void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
 // -----------------------------------------------------------------------------
 // WEBGL_lose_context
 public:
     void LoseContext();
@@ -881,31 +887,32 @@ public:
     void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buf,
                          WebGLintptr offset, WebGLsizeiptr size);
 
 private:
     void BufferDataImpl(GLenum target, size_t dataLen, const uint8_t* data, GLenum usage);
 
 public:
     void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage);
-    void BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeSrc,
-                    GLenum usage);
     void BufferData(GLenum target, const dom::ArrayBufferView& srcData, GLenum usage,
                     GLuint srcElemOffset = 0, GLuint srcElemCountOverride = 0);
+    void BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeData,
+                    GLenum usage);
+    void BufferData(GLenum target, const dom::SharedArrayBuffer& data, GLenum usage);
 
 private:
     void BufferSubDataImpl(GLenum target, WebGLsizeiptr dstByteOffset,
                            size_t srcDataLen, const uint8_t* srcData);
 
 public:
     void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
                        const dom::ArrayBufferView& src, GLuint srcElemOffset = 0,
                        GLuint srcElemCountOverride = 0);
     void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
-                       const dom::ArrayBuffer& src);
+                       const dom::Nullable<dom::ArrayBuffer>& maybeSrc);
     void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
                        const dom::SharedArrayBuffer& src);
 
     already_AddRefed<WebGLBuffer> CreateBuffer();
     void DeleteBuffer(WebGLBuffer* buf);
     bool IsBuffer(WebGLBuffer* buf);
 
 protected:
@@ -932,21 +939,21 @@ protected:
 
     WebGLRefPtr<WebGLQuery>*
     ValidateQuerySlotByTarget(const char* funcName, GLenum target);
 
 public:
     already_AddRefed<WebGLQuery> CreateQuery(const char* funcName = nullptr);
     void DeleteQuery(WebGLQuery* query, const char* funcName = nullptr);
     bool IsQuery(const WebGLQuery* query, const char* funcName = nullptr);
-    void BeginQuery(GLenum target, WebGLQuery& query, const char* funcName = nullptr);
+    void BeginQuery(GLenum target, WebGLQuery* query, const char* funcName = nullptr);
     void EndQuery(GLenum target, const char* funcName = nullptr);
     void GetQuery(JSContext* cx, GLenum target, GLenum pname,
                   JS::MutableHandleValue retval, const char* funcName = nullptr);
-    void GetQueryParameter(JSContext* cx, const WebGLQuery& query, GLenum pname,
+    void GetQueryParameter(JSContext* cx, const WebGLQuery* query, GLenum pname,
                            JS::MutableHandleValue retval, const char* funcName = nullptr);
 
 
 // -----------------------------------------------------------------------------
 // State and State Requests (WebGLContextState.cpp)
 public:
     void Disable(GLenum cap);
     void Enable(GLenum cap);
@@ -1014,32 +1021,32 @@ public:
     void CompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat,
                               GLsizei width, GLsizei height, GLint border,
                               const T& anySrc, GLuint viewElemOffset = 0,
                               GLuint viewElemLengthOverride = 0)
     {
         const char funcName[] = "compressedTexImage2D";
         const uint8_t funcDims = 2;
         const GLsizei depth = 1;
-        const TexImageSourceAdapter src(&anySrc, viewElemOffset, viewElemLengthOverride);
+        const TexImageSourceAdapter src(anySrc, viewElemOffset, viewElemLengthOverride);
         CompressedTexImage(funcName, funcDims, target, level, internalFormat, width,
                            height, depth, border, src);
     }
 
     template<typename T>
     void CompressedTexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                                  GLsizei width, GLsizei height, GLenum unpackFormat,
                                  const T& anySrc, GLuint viewElemOffset = 0,
                                  GLuint viewElemLengthOverride = 0)
     {
         const char funcName[] = "compressedTexSubImage2D";
         const uint8_t funcDims = 2;
         const GLint zOffset = 0;
         const GLsizei depth = 1;
-        const TexImageSourceAdapter src(&anySrc, viewElemOffset, viewElemLengthOverride);
+        const TexImageSourceAdapter src(anySrc, viewElemOffset, viewElemLengthOverride);
         CompressedTexSubImage(funcName, funcDims, target, level, xOffset, yOffset,
                               zOffset, width, height, depth, unpackFormat, src);
     }
 
 protected:
     void CompressedTexImage(const char* funcName, uint8_t funcDims, GLenum target,
                             GLint level, GLenum internalFormat, GLsizei width,
                             GLsizei height, GLsizei depth, GLint border,
@@ -1103,27 +1110,27 @@ public:
 
     ////
 
     template<typename T>
     void TexImage2D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLint border, GLenum unpackFormat, GLenum unpackType,
                     const T& anySrc, ErrorResult& out_error)
     {
-        const TexImageSourceAdapter src(&anySrc, &out_error);
+        const TexImageSourceAdapter src(anySrc, &out_error);
         TexImage2D(target, level, internalFormat, width, height, border, unpackFormat,
                    unpackType, src);
     }
 
     void TexImage2D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLint border, GLenum unpackFormat, GLenum unpackType,
                     const dom::ArrayBufferView& view, GLuint viewElemOffset,
                     ErrorResult&)
     {
-        const TexImageSourceAdapter src(&view, viewElemOffset);
+        const TexImageSourceAdapter src(view, viewElemOffset);
         TexImage2D(target, level, internalFormat, width, height, border, unpackFormat,
                    unpackType, src);
     }
 
 protected:
     void TexImage2D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLint border, GLenum unpackFormat,
                     GLenum unpackType, const TexImageSource& src)
@@ -1143,27 +1150,27 @@ protected:
     ////
 
 public:
     template<typename T>
     void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLsizei width, GLsizei height, GLenum unpackFormat,
                        GLenum unpackType, const T& anySrc, ErrorResult& out_error)
     {
-        const TexImageSourceAdapter src(&anySrc, &out_error);
+        const TexImageSourceAdapter src(anySrc, &out_error);
         TexSubImage2D(target, level, xOffset, yOffset, width, height, unpackFormat,
                       unpackType, src);
     }
 
     void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLsizei width, GLsizei height, GLenum unpackFormat,
                        GLenum unpackType, const dom::ArrayBufferView& view,
                        GLuint viewElemOffset, ErrorResult&)
     {
-        const TexImageSourceAdapter src(&view, viewElemOffset);
+        const TexImageSourceAdapter src(view, viewElemOffset);
         TexSubImage2D(target, level, xOffset, yOffset, width, height, unpackFormat,
                       unpackType, src);
     }
 
 protected:
     void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLsizei width, GLsizei height, GLenum unpackFormat,
                        GLenum unpackType, const TexImageSource& src)
@@ -1515,16 +1522,19 @@ protected:
     bool ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
                                WebGLboolean normalized, GLsizei stride,
                                WebGLintptr byteOffset, const char* info);
     bool ValidateStencilParamsForDrawCall();
 
     bool ValidateCopyTexImage(TexInternalFormat srcFormat, TexInternalFormat dstformat,
                               WebGLTexImageFunc func, WebGLTexDimensions dims);
 
+    bool ValidateSamplerParameterName(GLenum pname, const char* info);
+    bool ValidateSamplerParameterParams(GLenum pname, const WebGLIntOrFloat& param, const char* info);
+
     bool ValidateTexImage(TexImageTarget texImageTarget,
                           GLint level, GLenum internalFormat,
                           GLint xoffset, GLint yoffset, GLint zoffset,
                           GLint width, GLint height, GLint depth,
                           GLint border, GLenum format, GLenum type,
                           WebGLTexImageFunc func, WebGLTexDimensions dims);
     bool ValidateTexImageFormat(GLenum internalFormat, WebGLTexImageFunc func,
                                 WebGLTexDimensions dims);
@@ -1567,46 +1577,33 @@ protected:
                               uint32_t* const out_width, uint32_t* const out_height);
 
     bool HasDrawBuffers() const {
         return IsWebGL2() ||
                IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
     }
 
     WebGLRefPtr<WebGLBuffer>* ValidateBufferSlot(const char* funcName, GLenum target);
-public:
     WebGLBuffer* ValidateBufferSelection(const char* funcName, GLenum target);
-protected:
     IndexedBufferBinding* ValidateIndexedBufferSlot(const char* funcName, GLenum target,
                                                     GLuint index);
 
     bool ValidateIndexedBufferBinding(const char* funcName, GLenum target, GLuint index,
                                       WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
                                       IndexedBufferBinding** const out_indexedBinding);
 
     bool ValidateNonNegative(const char* funcName, const char* argName, int64_t val) {
         if (MOZ_UNLIKELY(val < 0)) {
             ErrorInvalidValue("%s: `%s` must be non-negative.", funcName, argName);
             return false;
         }
         return true;
     }
 
-    bool ValidateForNonTransformFeedback(const char* funcName, WebGLBuffer* buffer);
-
 public:
-    template<typename T>
-    bool ValidateNonNull(const char* funcName, const dom::Nullable<T>& maybe) {
-        if (maybe.IsNull()) {
-            ErrorInvalidValue("%s: `null` is invalid.", funcName);
-            return false;
-        }
-        return true;
-    }
-
     bool ValidateArrayBufferView(const char* funcName, const dom::ArrayBufferView& view,
                                  GLuint elemOffset, GLuint elemCountOverride,
                                  uint8_t** const out_bytes, size_t* const out_byteLen);
 
 protected:
     ////
 
     void Invalidate();
@@ -1618,106 +1615,40 @@ protected:
 
     bool ConvertImage(size_t width, size_t height, size_t srcStride,
                       size_t dstStride, const uint8_t* src, uint8_t* dst,
                       WebGLTexelFormat srcFormat, bool srcPremultiplied,
                       WebGLTexelFormat dstFormat, bool dstPremultiplied,
                       size_t dstTexelSize);
 
     //////
-public:
-    bool ValidateObjectAllowDeleted(const char* funcName,
-                                    const WebGLContextBoundObject& object)
-    {
-        if (!object.IsCompatibleWithContext(this)) {
-            ErrorInvalidOperation("%s: Object from different WebGL context (or older"
-                                  " generation of this one) passed as argument.",
-                                  funcName);
-            return false;
-        }
-
-        return true;
-    }
-
-    bool ValidateObject(const char* funcName, const WebGLDeletableObject& object,
-                        bool isShaderOrProgram = false)
-    {
-        if (!ValidateObjectAllowDeleted(funcName, object))
-            return false;
 
-        if (isShaderOrProgram) {
-            /* GLES 3.0.5 p45:
-             * "Commands that accept shader or program object names will generate the
-             *  error INVALID_VALUE if the provided name is not the name of either a
-             *  shader or program object[.]"
-             * Further, shaders and programs appear to be different from other objects,
-             * in that their lifetimes are better defined. However, they also appear to
-             * allow use of objects marked for deletion, and only reject
-             * actually-destroyed objects.
-             */
-            if (object.IsDeleted()) {
-                ErrorInvalidValue("%s: Shader or program object argument cannot have been"
-                                  " deleted.",
-                                  funcName);
-                return false;
-            }
-        } else {
-            if (object.IsDeleteRequested()) {
-                ErrorInvalidOperation("%s: Object argument cannot have been marked for"
-                                      " deletion.",
-                                      funcName);
-                return false;
-            }
-        }
+    // Returns false if `object` is null or not valid.
+    template<class ObjectType>
+    bool ValidateObject(const char* info, const ObjectType* object);
+
+    // Returns false if `object` is not valid.  Considers null to be valid.
+    template<class ObjectType>
+    bool ValidateObjectAllowNull(const char* info, const ObjectType* object);
 
-        return true;
-    }
-
-    ////
-
-    bool ValidateObject(const char* funcName, const WebGLProgram& object);
-    bool ValidateObject(const char* funcName, const WebGLShader& object);
-
-    ////
-
-    bool ValidateIsObject(const char* funcName,
-                          const WebGLDeletableObject* object) const
-    {
-        if (IsContextLost())
-            return false;
-
-        if (!object)
-            return false;
-
-        if (!object->IsCompatibleWithContext(this))
-            return false;
+    // Returns false if `object` is not valid, but considers deleted objects and
+    // null objects valid.
+    template<class ObjectType>
+    bool ValidateObjectAllowDeletedOrNull(const char* info, const ObjectType* object);
 
-        if (object->IsDeleted())
-            return false;
-
-        return true;
-    }
-
-    bool ValidateDeleteObject(const char* funcName, const WebGLDeletableObject* object) {
-        if (IsContextLost())
-            return false;
+    // Returns false if `object` is null or not valid, but considers deleted
+    // objects valid.
+    template<class ObjectType>
+    bool ValidateObjectAllowDeleted(const char* info, const ObjectType* object);
 
-        if (!object)
-            return false;
-
-        if (!ValidateObjectAllowDeleted(funcName, *object))
-            return false;
-
-        if (object->IsDeleteRequested())
-            return false;
-
-        return true;
-    }
-
-    ////
+private:
+    // Like ValidateObject, but only for cases when `object` is known to not be
+    // null already.
+    template<class ObjectType>
+    bool ValidateObjectAssumeNonNull(const char* info, const ObjectType* object);
 
 private:
     // -------------------------------------------------------------------------
     // Context customization points
     virtual WebGLVertexArray* CreateVertexArrayImpl();
 
     virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, uint32_t* alignment, const char* info) = 0;
     virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) = 0;
@@ -1735,22 +1666,16 @@ protected:
     nsTArray<WebGLRefPtr<WebGLSampler> > mBoundSamplers;
 
     void ResolveTexturesForDraw() const;
 
     WebGLRefPtr<WebGLProgram> mCurrentProgram;
     RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
 
     bool ValidateFramebufferTarget(GLenum target, const char* const info);
-    bool ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
-                                       const dom::Sequence<GLenum>& attachments,
-                                       ErrorResult* const out_rv,
-                                       std::vector<GLenum>* const scopedVector,
-                                       GLsizei* const out_glNumAttachments,
-                                       const GLenum** const out_glAttachments);
 
     WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;
     WebGLRefPtr<WebGLFramebuffer> mBoundReadFramebuffer;
     WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
     WebGLRefPtr<WebGLTransformFeedback> mBoundTransformFeedback;
     WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
 
     LinkedList<WebGLBuffer> mBuffers;
@@ -1813,27 +1738,16 @@ protected:
     UniquePtr<FakeBlackTexture> mFakeBlack_3D_0001;
     UniquePtr<FakeBlackTexture> mFakeBlack_2D_Array_0000;
     UniquePtr<FakeBlackTexture> mFakeBlack_2D_Array_0001;
 
     bool BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fakeBlack);
 
     ////////////////////////////////////
 
-private:
-    mutable bool mBuffersForUB_Dirty;
-    mutable std::set<const WebGLBuffer*> mBuffersForUB;
-
-public:
-    void OnUBIndexedBindingsChanged() const { mBuffersForUB_Dirty = true; }
-    const decltype(mBuffersForUB)& BuffersForUB() const;
-
-    ////////////////////////////////////
-
-protected:
     // Generic Vertex Attributes
     UniquePtr<GLenum[]> mVertexAttribType;
     GLfloat mVertexAttrib0Vector[4];
     GLfloat mFakeVertexAttrib0BufferObjectVector[4];
     size_t mFakeVertexAttrib0BufferObjectSize;
     GLuint mFakeVertexAttrib0BufferObject;
     WebGLVertexAttrib0Status mFakeVertexAttrib0BufferStatus;
 
@@ -1882,18 +1796,16 @@ protected:
 
     uint64_t mLastUseIndex;
 
     bool mNeedsFakeNoAlpha;
     bool mNeedsFakeNoDepth;
     bool mNeedsFakeNoStencil;
     bool mNeedsEmulatedLoneDepthStencil;
 
-    const bool mAllowFBInvalidation;
-
     bool Has64BitTimestamps() const;
 
     struct ScopedMaskWorkaround {
         WebGLContext& mWebGL;
         const bool mFakeNoAlpha;
         const bool mFakeNoDepth;
         const bool mFakeNoStencil;
 
@@ -2006,16 +1918,86 @@ public:
 
 // used by DOM bindings in conjunction with GetParentObject
 inline nsISupports*
 ToSupports(WebGLContext* webgl)
 {
     return static_cast<nsIDOMWebGLRenderingContext*>(webgl);
 }
 
+/**
+ ** Template implementations
+ **/
+
+template<class ObjectType>
+inline bool
+WebGLContext::ValidateObjectAllowDeletedOrNull(const char* info,
+                                               const ObjectType* object)
+{
+    if (object && !object->IsCompatibleWithContext(this)) {
+        ErrorInvalidOperation("%s: object from different WebGL context "
+                              "(or older generation of this one) "
+                              "passed as argument", info);
+        return false;
+    }
+
+    return true;
+}
+
+template<class ObjectType>
+inline bool
+WebGLContext::ValidateObjectAssumeNonNull(const char* info, const ObjectType* object)
+{
+    MOZ_ASSERT(object);
+
+    if (!ValidateObjectAllowDeletedOrNull(info, object))
+        return false;
+
+    if (object->IsDeleted()) {
+        ErrorInvalidValue("%s: Deleted object passed as argument.", info);
+        return false;
+    }
+
+    return true;
+}
+
+template<class ObjectType>
+inline bool
+WebGLContext::ValidateObjectAllowNull(const char* info, const ObjectType* object)
+{
+    if (!object)
+        return true;
+
+    return ValidateObjectAssumeNonNull(info, object);
+}
+
+template<class ObjectType>
+inline bool
+WebGLContext::ValidateObjectAllowDeleted(const char* info, const ObjectType* object)
+{
+    if (!object) {
+        ErrorInvalidValue("%s: null object passed as argument", info);
+        return false;
+    }
+
+    return ValidateObjectAllowDeletedOrNull(info, object);
+}
+
+template<class ObjectType>
+inline bool
+WebGLContext::ValidateObject(const char* info, const ObjectType* object)
+{
+    if (!object) {
+        ErrorInvalidValue("%s: null object passed as argument", info);
+        return false;
+    }
+
+    return ValidateObjectAssumeNonNull(info, object);
+}
+
 // Returns `value` rounded to the next highest multiple of `multiple`.
 // AKA PadToAlignment, StrideForAlignment.
 template<typename V, typename M>
 V
 RoundUpToMultipleOf(const V& value, const M& multiple)
 {
     return ((value + multiple - 1) / multiple) * multiple;
 }
@@ -2123,16 +2105,22 @@ private:
 
 ////
 
 void
 Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
           uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
           uint32_t* const out_intSize);
 
+bool
+ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex,
+                TexImageTarget target, uint32_t level,
+                const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
+                uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth);
+
 ////
 
 void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
                             const std::vector<IndexedBufferBinding>& field,
                             const char* name, uint32_t flags = 0);
 
 void
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -70,19 +70,16 @@ WebGLContext::ValidateBufferSelection(co
         return nullptr;
     const auto& buffer = *slot;
 
     if (!buffer) {
         ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
         return nullptr;
     }
 
-    if (!ValidateForNonTransformFeedback(funcName, buffer.get()))
-        return nullptr;
-
     return buffer.get();
 }
 
 IndexedBufferBinding*
 WebGLContext::ValidateIndexedBufferSlot(const char* funcName, GLenum target, GLuint index)
 {
     decltype(mIndexedUniformBufferBindings)* bindings;
     const char* maxIndexEnum;
@@ -114,19 +111,22 @@ WebGLContext::ValidateIndexedBufferSlot(
 
 void
 WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
 {
     const char funcName[] = "bindBuffer";
     if (IsContextLost())
         return;
 
-    if (buffer && !ValidateObject(funcName, *buffer))
+    if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
         return;
 
+    if (buffer && buffer->IsDeleted())
+        return ErrorInvalidOperation("%s: Cannot bind a deleted object.", funcName);
+
     const auto& slot = ValidateBufferSlot(funcName, target);
     if (!slot)
         return;
 
     if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
         return;
 
     gl->MakeCurrent();
@@ -175,19 +175,22 @@ WebGLContext::ValidateIndexedBufferBindi
 
 void
 WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
 {
     const char funcName[] = "bindBufferBase";
     if (IsContextLost())
         return;
 
-    if (buffer && !ValidateObject(funcName, *buffer))
+    if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
         return;
 
+    if (buffer && buffer->IsDeleted())
+        return ErrorInvalidOperation("%s: Cannot bind a deleted object.", funcName);
+
     WebGLRefPtr<WebGLBuffer>* genericBinding;
     IndexedBufferBinding* indexedBinding;
     if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
                                       &indexedBinding))
     {
         return;
     }
 
@@ -204,38 +207,32 @@ WebGLContext::BindBufferBase(GLenum targ
     *genericBinding = buffer;
     indexedBinding->mBufferBinding = buffer;
     indexedBinding->mRangeStart = 0;
     indexedBinding->mRangeSize = 0;
 
     if (buffer) {
         buffer->SetContentAfterBind(target);
     }
-
-    switch (target) {
-    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
-        mBoundTransformFeedback->OnIndexedBindingsChanged();
-        break;
-    case LOCAL_GL_UNIFORM:
-        OnUBIndexedBindingsChanged();
-        break;
-    }
 }
 
 void
 WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
                               WebGLintptr offset, WebGLsizeiptr size)
 {
     const char funcName[] = "bindBufferRange";
     if (IsContextLost())
         return;
 
-    if (buffer && !ValidateObject(funcName, *buffer))
+    if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
         return;
 
+    if (buffer && buffer->IsDeleted())
+        return ErrorInvalidOperation("%s: Cannot bind a deleted object.", funcName);
+
     if (!ValidateNonNegative(funcName, "offset", offset) ||
         !ValidateNonNegative(funcName, "size", size))
     {
         return;
     }
 
     WebGLRefPtr<WebGLBuffer>* genericBinding;
     IndexedBufferBinding* indexedBinding;
@@ -294,25 +291,16 @@ WebGLContext::BindBufferRange(GLenum tar
     *genericBinding = buffer;
     indexedBinding->mBufferBinding = buffer;
     indexedBinding->mRangeStart = offset;
     indexedBinding->mRangeSize = size;
 
     if (buffer) {
         buffer->SetContentAfterBind(target);
     }
-
-    switch (target) {
-    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
-        mBoundTransformFeedback->OnIndexedBindingsChanged();
-        break;
-    case LOCAL_GL_UNIFORM:
-        OnUBIndexedBindingsChanged();
-        break;
-    }
 }
 
 ////////////////////////////////////////
 
 void
 WebGLContext::BufferDataImpl(GLenum target, size_t dataLen, const uint8_t* data,
                              GLenum usage)
 {
@@ -342,25 +330,35 @@ WebGLContext::BufferData(GLenum target, 
     const UniqueBuffer zeroBuffer(calloc(size, 1));
     if (!zeroBuffer)
         return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName);
 
     BufferDataImpl(target, size_t(size), (const uint8_t*)zeroBuffer.get(), usage);
 }
 
 void
+WebGLContext::BufferData(GLenum target, const dom::SharedArrayBuffer& src, GLenum usage)
+{
+    if (IsContextLost())
+        return;
+
+    src.ComputeLengthAndData();
+    BufferDataImpl(target, src.LengthAllowShared(), src.DataAllowShared(), usage);
+}
+
+void
 WebGLContext::BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeSrc,
                          GLenum usage)
 {
     if (IsContextLost())
         return;
 
-    if (!ValidateNonNull("bufferData", maybeSrc))
-        return;
-    const auto& src = maybeSrc.Value();
+    if (maybeSrc.IsNull())
+        return ErrorInvalidValue("bufferData: null object passed");
+    auto& src = maybeSrc.Value();
 
     src.ComputeLengthAndData();
     BufferDataImpl(target, src.LengthAllowShared(), src.DataAllowShared(), usage);
 }
 
 void
 WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& src, GLenum usage,
                          GLuint srcElemOffset, GLuint srcElemCountOverride)
@@ -390,16 +388,23 @@ WebGLContext::BufferSubDataImpl(GLenum t
 
     if (!ValidateNonNegative(funcName, "byteOffset", dstByteOffset))
         return;
 
     const auto& buffer = ValidateBufferSelection(funcName, target);
     if (!buffer)
         return;
 
+    if (buffer->mNumActiveTFOs) {
+        ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+                              " object.",
+                              "bufferSubData");
+        return;
+    }
+
     if (!buffer->ValidateRange(funcName, dstByteOffset, dataLen))
         return;
 
     if (!CheckedInt<GLintptr>(dataLen).isValid()) {
         ErrorOutOfMemory("%s: Size too large.", funcName);
         return;
     }
     const GLintptr glDataLen(dataLen);
@@ -413,17 +418,33 @@ WebGLContext::BufferSubDataImpl(GLenum t
     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)
+                            const dom::Nullable<dom::ArrayBuffer>& maybeSrc)
+{
+    if (IsContextLost())
+        return;
+
+    if (maybeSrc.IsNull())
+        return ErrorInvalidValue("BufferSubData: returnedData is null.");
+    auto& src = maybeSrc.Value();
+
+    src.ComputeLengthAndData();
+    BufferSubDataImpl(target, dstByteOffset, src.LengthAllowShared(),
+                      src.DataAllowShared());
+}
+
+void
+WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
+                            const dom::SharedArrayBuffer& src)
 {
     if (IsContextLost())
         return;
 
     src.ComputeLengthAndData();
     BufferSubDataImpl(target, dstByteOffset, src.LengthAllowShared(),
                       src.DataAllowShared());
 }
@@ -462,17 +483,23 @@ WebGLContext::CreateBuffer()
 
     RefPtr<WebGLBuffer> globj = new WebGLBuffer(this, buf);
     return globj.forget();
 }
 
 void
 WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
 {
-    if (!ValidateDeleteObject("deleteBuffer", buffer))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteBuffer", buffer))
+        return;
+
+    if (!buffer || buffer->IsDeleted())
         return;
 
     ////
 
     const auto fnClearIfBuffer = [&](WebGLRefPtr<WebGLBuffer>& bindPoint) {
         if (bindPoint == buffer) {
             bindPoint = nullptr;
         }
@@ -510,16 +537,22 @@ WebGLContext::DeleteBuffer(WebGLBuffer* 
     ////
 
     buffer->RequestDelete();
 }
 
 bool
 WebGLContext::IsBuffer(WebGLBuffer* buffer)
 {
-    if (!ValidateIsObject("isBuffer", buffer))
+    if (IsContextLost())
+        return false;
+
+    if (!ValidateObjectAllowDeleted("isBuffer", buffer))
+        return false;
+
+    if (buffer->IsDeleted())
         return false;
 
     MakeContextCurrent();
     return gl->fIsBuffer(buffer->mGLName);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -14,18 +14,16 @@
 #include "WebGLFramebuffer.h"
 #include "WebGLProgram.h"
 #include "WebGLRenderbuffer.h"
 #include "WebGLShader.h"
 #include "WebGLTexture.h"
 #include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
 
-#include <algorithm>
-
 namespace mozilla {
 
 // For a Tegra workaround.
 static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
 
 ////////////////////////////////////////
 
 class ScopedResolveTexturesForDraw
@@ -297,26 +295,16 @@ WebGLContext::DrawArrays_check(const cha
         return false;
     }
 
     return true;
 }
 
 ////////////////////////////////////////
 
-template<typename T>
-static bool
-DoSetsIntersect(const std::set<T>& a, const std::set<T>& b)
-{
-    std::vector<T> intersection;
-    std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
-                          std::back_inserter(intersection));
-    return bool(intersection.size());
-}
-
 class ScopedDrawHelper final
 {
     WebGLContext* const mWebGL;
     bool mDidFake;
 
 public:
     ScopedDrawHelper(WebGLContext* webgl, const char* funcName, uint32_t firstVertex,
                      uint32_t vertCount, uint32_t instanceCount, bool* const out_error)
@@ -350,17 +338,17 @@ public:
             *out_error = true;
             return;
         }
         mDidFake = true;
 
         ////
         // Check UBO sizes.
 
-        const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
+        const auto& linkInfo = webgl->mActiveProgramLinkInfo;
         for (const auto& cur : linkInfo->uniformBlocks) {
             const auto& dataSize = cur->mDataSize;
             const auto& binding = cur->mBinding;
             if (!binding) {
                 mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is null.",
                                               funcName);
                 *out_error = true;
                 return;
@@ -373,32 +361,16 @@ public:
                                               funcName);
                 *out_error = true;
                 return;
             }
         }
 
         ////
 
-        const auto& tfo = mWebGL->mBoundTransformFeedback;
-        if (tfo) {
-            const auto& buffersForTF = tfo->BuffersForTF();
-            const auto& buffersForUB = mWebGL->BuffersForUB();
-            if (DoSetsIntersect(buffersForTF, buffersForUB)) {
-                mWebGL->ErrorInvalidOperation("%s: At least one WebGLBuffer is bound for"
-                                              " both transform feedback and as a uniform"
-                                              " buffer.",
-                                              funcName);
-                *out_error = true;
-                return;
-            }
-        }
-
-        ////
-
         mWebGL->RunContextLossTimer();
     }
 
     ~ScopedDrawHelper() {
         if (mDidFake) {
             mWebGL->UndoFakeVertexAttrib0();
         }
     }
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -52,28 +52,16 @@
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtrExtensions.h"
 
 namespace mozilla {
 
-bool
-WebGLContext::ValidateObject(const char* funcName, const WebGLProgram& object)
-{
-    return ValidateObject(funcName, object, true);
-}
-
-bool
-WebGLContext::ValidateObject(const char* funcName, const WebGLShader& object)
-{
-    return ValidateObject(funcName, object, true);
-}
-
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 //
 //  WebGL API
 //
 
@@ -94,55 +82,58 @@ WebGLContext::ActiveTexture(GLenum textu
     }
 
     MakeContextCurrent();
     mActiveTexture = texture - LOCAL_GL_TEXTURE0;
     gl->fActiveTexture(texture);
 }
 
 void
-WebGLContext::AttachShader(WebGLProgram& program, WebGLShader& shader)
+WebGLContext::AttachShader(WebGLProgram* program, WebGLShader* shader)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("attachShader: program", program) ||
         !ValidateObject("attachShader: shader", shader))
     {
         return;
     }
 
-    program.AttachShader(&shader);
+    program->AttachShader(shader);
 }
 
 void
-WebGLContext::BindAttribLocation(WebGLProgram& prog, GLuint location,
+WebGLContext::BindAttribLocation(WebGLProgram* prog, GLuint location,
                                  const nsAString& name)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("bindAttribLocation: program", prog))
         return;
 
-    prog.BindAttribLocation(location, name);
+    prog->BindAttribLocation(location, name);
 }
 
 void
 WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer* wfb)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateFramebufferTarget(target, "bindFramebuffer"))
         return;
 
-    if (wfb && !ValidateObject("bindFramebuffer", *wfb))
+    if (!ValidateObjectAllowDeletedOrNull("bindFramebuffer", wfb))
         return;
 
+    if (wfb && wfb->IsDeleted())
+        return ErrorInvalidOperation("bindFramebuffer: Cannot bind a deleted object.");
+
     MakeContextCurrent();
 
     if (!wfb) {
         gl->fBindFramebuffer(target, 0);
     } else {
         GLuint framebuffername = wfb->mGLName;
         gl->fBindFramebuffer(target, framebuffername);
 #ifdef ANDROID
@@ -170,19 +161,22 @@ void
 WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer* wrb)
 {
     if (IsContextLost())
         return;
 
     if (target != LOCAL_GL_RENDERBUFFER)
         return ErrorInvalidEnumInfo("bindRenderbuffer: target", target);
 
-    if (wrb && !ValidateObject("bindRenderbuffer", *wrb))
+    if (!ValidateObjectAllowDeletedOrNull("bindRenderbuffer", wrb))
         return;
 
+    if (wrb && wrb->IsDeleted())
+        return ErrorInvalidOperation("bindRenderbuffer: Cannot bind a deleted object.");
+
     // Usually, we would now call into glBindRenderbuffer. However, since we have to
     // potentially emulate packed-depth-stencil, there's not a specific renderbuffer that
     // we know we should bind here.
     // Instead, we do all renderbuffer binding lazily.
 
     if (wrb) {
         wrb->mHasBeenBound = true;
     }
@@ -321,17 +315,23 @@ WebGLContext::CullFace(GLenum face)
 
     MakeContextCurrent();
     gl->fCullFace(face);
 }
 
 void
 WebGLContext::DeleteFramebuffer(WebGLFramebuffer* fbuf)
 {
-    if (!ValidateDeleteObject("deleteFramebuffer", fbuf))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteFramebuffer", fbuf))
+        return;
+
+    if (!fbuf || fbuf->IsDeleted())
         return;
 
     fbuf->RequestDelete();
 
     if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
         if (mBoundDrawFramebuffer == fbuf) {
             BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
                             static_cast<WebGLFramebuffer*>(nullptr));
@@ -343,17 +343,23 @@ WebGLContext::DeleteFramebuffer(WebGLFra
         BindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
                         static_cast<WebGLFramebuffer*>(nullptr));
     }
 }
 
 void
 WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf)
 {
-    if (!ValidateDeleteObject("deleteRenderbuffer", rbuf))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteRenderbuffer", rbuf))
+        return;
+
+    if (!rbuf || rbuf->IsDeleted())
         return;
 
     if (mBoundDrawFramebuffer)
         mBoundDrawFramebuffer->DetachRenderbuffer(rbuf);
 
     if (mBoundReadFramebuffer)
         mBoundReadFramebuffer->DetachRenderbuffer(rbuf);
 
@@ -363,17 +369,23 @@ WebGLContext::DeleteRenderbuffer(WebGLRe
         BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nullptr);
 
     rbuf->RequestDelete();
 }
 
 void
 WebGLContext::DeleteTexture(WebGLTexture* tex)
 {
-    if (!ValidateDeleteObject("deleteTexture", tex))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteTexture", tex))
+        return;
+
+    if (!tex || tex->IsDeleted())
         return;
 
     if (mBoundDrawFramebuffer)
         mBoundDrawFramebuffer->DetachTexture(tex);
 
     if (mBoundReadFramebuffer)
         mBoundReadFramebuffer->DetachTexture(tex);
 
@@ -391,46 +403,58 @@ WebGLContext::DeleteTexture(WebGLTexture
     ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture);
 
     tex->RequestDelete();
 }
 
 void
 WebGLContext::DeleteProgram(WebGLProgram* prog)
 {
-    if (!ValidateDeleteObject("deleteProgram", prog))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteProgram", prog))
+        return;
+
+    if (!prog || prog->IsDeleted())
         return;
 
     prog->RequestDelete();
 }
 
 void
 WebGLContext::DeleteShader(WebGLShader* shader)
 {
-    if (!ValidateDeleteObject("deleteShader", shader))
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteShader", shader))
+        return;
+
+    if (!shader || shader->IsDeleted())
         return;
 
     shader->RequestDelete();
 }
 
 void
-WebGLContext::DetachShader(WebGLProgram& program, const WebGLShader& shader)
+WebGLContext::DetachShader(WebGLProgram* program, WebGLShader* shader)
 {
     if (IsContextLost())
         return;
 
     // It's valid to attempt to detach a deleted shader, since it's still a
     // shader.
     if (!ValidateObject("detachShader: program", program) ||
-        !ValidateObjectAllowDeleted("detachShader: shader", shader))
+        !ValidateObjectAllowDeleted("detashShader: shader", shader))
     {
         return;
     }
 
-    program.DetachShader(&shader);
+    program->DetachShader(shader);
 }
 
 void
 WebGLContext::DepthFunc(GLenum func)
 {
     if (IsContextLost())
         return;
 
@@ -535,63 +559,68 @@ WebGLContext::FrontFace(GLenum mode)
             return ErrorInvalidEnumInfo("frontFace: mode", mode);
     }
 
     MakeContextCurrent();
     gl->fFrontFace(mode);
 }
 
 already_AddRefed<WebGLActiveInfo>
-WebGLContext::GetActiveAttrib(const WebGLProgram& prog, GLuint index)
+WebGLContext::GetActiveAttrib(WebGLProgram* prog, GLuint index)
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getActiveAttrib: program", prog))
         return nullptr;
 
-    return prog.GetActiveAttrib(index);
+    return prog->GetActiveAttrib(index);
 }
 
 already_AddRefed<WebGLActiveInfo>
-WebGLContext::GetActiveUniform(const WebGLProgram& prog, GLuint index)
+WebGLContext::GetActiveUniform(WebGLProgram* prog, GLuint index)
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getActiveUniform: program", prog))
         return nullptr;
 
-    return prog.GetActiveUniform(index);
+    return prog->GetActiveUniform(index);
 }
 
 void
-WebGLContext::GetAttachedShaders(const WebGLProgram& prog,
+WebGLContext::GetAttachedShaders(WebGLProgram* prog,
                                  dom::Nullable<nsTArray<RefPtr<WebGLShader>>>& retval)
 {
     retval.SetNull();
     if (IsContextLost())
         return;
 
+    if (!prog) {
+        ErrorInvalidValue("getAttachedShaders: Invalid program.");
+        return;
+    }
+
     if (!ValidateObject("getAttachedShaders", prog))
         return;
 
-    prog.GetAttachedShaders(&retval.SetValue());
+    prog->GetAttachedShaders(&retval.SetValue());
 }
 
 GLint
-WebGLContext::GetAttribLocation(const WebGLProgram& prog, const nsAString& name)
+WebGLContext::GetAttribLocation(WebGLProgram* prog, const nsAString& name)
 {
     if (IsContextLost())
         return -1;
 
     if (!ValidateObject("getAttribLocation: program", prog))
         return -1;
 
-    return prog.GetAttribLocation(name);
+    return prog->GetAttribLocation(name);
 }
 
 JS::Value
 WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
@@ -876,70 +905,72 @@ WebGLContext::GetError()
     MakeContextCurrent();
     GetAndFlushUnderlyingGLErrors();
 
     err = GetAndClearError(&mUnderlyingGLError);
     return err;
 }
 
 JS::Value
-WebGLContext::GetProgramParameter(const WebGLProgram& prog, GLenum pname)
+WebGLContext::GetProgramParameter(WebGLProgram* prog, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
     if (!ValidateObjectAllowDeleted("getProgramParameter: program", prog))
         return JS::NullValue();
 
-    return prog.GetProgramParameter(pname);
+    return prog->GetProgramParameter(pname);
 }
 
 void
-WebGLContext::GetProgramInfoLog(const WebGLProgram& prog, nsAString& retval)
+WebGLContext::GetProgramInfoLog(WebGLProgram* prog, nsAString& retval)
 {
     retval.SetIsVoid(true);
 
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getProgramInfoLog: program", prog))
         return;
 
-    prog.GetProgramInfoLog(&retval);
+    prog->GetProgramInfoLog(&retval);
+
+    retval.SetIsVoid(false);
 }
 
 JS::Value
-WebGLContext::GetUniform(JSContext* js, const WebGLProgram& prog,
-                         const WebGLUniformLocation& loc)
+WebGLContext::GetUniform(JSContext* js, WebGLProgram* prog,
+                         WebGLUniformLocation* loc)
 {
     if (IsContextLost())
         return JS::NullValue();
 
     if (!ValidateObject("getUniform: `program`", prog))
         return JS::NullValue();
 
-    if (!ValidateObjectAllowDeleted("getUniform: `location`", loc))
+    if (!ValidateObject("getUniform: `location`", loc))
         return JS::NullValue();
 
-    if (!loc.ValidateForProgram(&prog, "getUniform"))
+    if (!loc->ValidateForProgram(prog, "getUniform"))
         return JS::NullValue();
 
-    return loc.GetUniform(js);
+    return loc->GetUniform(js);
 }
 
 already_AddRefed<WebGLUniformLocation>
-WebGLContext::GetUniformLocation(const WebGLProgram& prog, const nsAString& name)
+WebGLContext::GetUniformLocation(WebGLProgram* prog, const nsAString& name)
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getUniformLocation: program", prog))
         return nullptr;
 
-    return prog.GetUniformLocation(name);
+    return prog->GetUniformLocation(name);
 }
 
 void
 WebGLContext::Hint(GLenum target, GLenum mode)
 {
     if (IsContextLost())
         return;
 
@@ -966,84 +997,97 @@ WebGLContext::Hint(GLenum target, GLenum
     if (!isValid)
         return ErrorInvalidEnum("hint: invalid hint");
 
     MakeContextCurrent();
     gl->fHint(target, mode);
 }
 
 bool
-WebGLContext::IsFramebuffer(const WebGLFramebuffer* fb)
+WebGLContext::IsFramebuffer(WebGLFramebuffer* fb)
 {
-    if (!ValidateIsObject("isFramebuffer", fb))
+    if (IsContextLost())
+        return false;
+
+    if (!ValidateObjectAllowDeleted("isFramebuffer", fb))
+        return false;
+
+    if (fb->IsDeleted())
         return false;
 
 #ifdef ANDROID
     if (gl->WorkAroundDriverBugs() &&
         gl->Renderer() == GLRenderer::AndroidEmulator)
     {
         return fb->mIsFB;
     }
 #endif
 
     MakeContextCurrent();
     return gl->fIsFramebuffer(fb->mGLName);
 }
 
 bool
-WebGLContext::IsProgram(const WebGLProgram* prog)
+WebGLContext::IsProgram(WebGLProgram* prog)
 {
-    if (!ValidateIsObject("isProgram", prog))
+    if (IsContextLost())
         return false;
 
-    return true;
+    return ValidateObjectAllowDeleted("isProgram", prog) && !prog->IsDeleted();
 }
 
 bool
-WebGLContext::IsRenderbuffer(const WebGLRenderbuffer* rb)
+WebGLContext::IsRenderbuffer(WebGLRenderbuffer* rb)
 {
-    if (!ValidateIsObject("isRenderbuffer", rb))
+    if (IsContextLost())
+        return false;
+
+    if (!ValidateObjectAllowDeleted("isRenderBuffer", rb))
+        return false;
+
+    if (rb->IsDeleted())
         return false;
 
     return rb->mHasBeenBound;
 }
 
 bool
-WebGLContext::IsShader(const WebGLShader* shader)
+WebGLContext::IsShader(WebGLShader* shader)
 {
-    if (!ValidateIsObject("isShader", shader))
+    if (IsContextLost())
         return false;
 
-    return true;
+    return ValidateObjectAllowDeleted("isShader", shader) &&
+        !shader->IsDeleted();
 }
 
 void
-WebGLContext::LinkProgram(WebGLProgram& prog)
+WebGLContext::LinkProgram(WebGLProgram* prog)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("linkProgram", prog))
         return;
 
-    prog.LinkProgram();
-
-    if (!prog.IsLinked()) {
+    prog->LinkProgram();
+
+    if (!prog->IsLinked()) {
         // If we failed to link, but `prog == mCurrentProgram`, we are *not* supposed to
         // null out mActiveProgramLinkInfo.
         return;
     }
 
-    if (&prog == mCurrentProgram) {
-        mActiveProgramLinkInfo = prog.LinkInfo();
+    if (prog == mCurrentProgram) {
+        mActiveProgramLinkInfo = prog->LinkInfo();
 
         if (gl->WorkAroundDriverBugs() &&
             gl->Vendor() == gl::GLVendor::NVIDIA)
         {
-            gl->fUseProgram(prog.mGLName);
+            gl->fUseProgram(prog->mGLName);
         }
     }
 }
 
 void
 WebGLContext::PixelStorei(GLenum pname, GLint param)
 {
     if (IsContextLost())
@@ -1334,52 +1378,60 @@ WebGLContext::ReadPixels(GLint x, GLint 
 
     ReadPixelsImpl(x, y, width, height, format, type, bytes, byteLen);
 }
 
 void
 WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
                          GLenum type, WebGLsizeiptr offset, ErrorResult& out_error)
 {
-    const char funcName[] = "readPixels";
     if (!ReadPixels_SharedPrecheck(&out_error))
         return;
 
-    const auto& buffer = ValidateBufferSelection(funcName, LOCAL_GL_PIXEL_PACK_BUFFER);
-    if (!buffer)
+    if (!mBoundPixelPackBuffer) {
+        ErrorInvalidOperation("readPixels: PIXEL_PACK_BUFFER must not be null.");
         return;
+    }
+
+    if (mBoundPixelPackBuffer->mNumActiveTFOs) {
+        ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+                              " object.",
+                              "readPixels");
+        return;
+    }
 
     //////
 
-    if (!ValidateNonNegative(funcName, "offset", offset))
+    if (offset < 0) {
+        ErrorInvalidValue("readPixels: offset must not be negative.");
         return;
+    }
 
     {
         const auto bytesPerType = webgl::BytesPerPixel({LOCAL_GL_RED, type});
 
         if (offset % bytesPerType != 0) {
-            ErrorInvalidOperation("%s: `offset` must be divisible by the size of `type`"
-                                  " in bytes.",
-                                  funcName);
+            ErrorInvalidOperation("readPixels: `offset` must be divisible by the size"
+                                  " a `type` in bytes.");
             return;
         }
     }
 
     //////
 
-    const auto bytesAvailable = buffer->ByteLength();
+    const auto bytesAvailable = mBoundPixelPackBuffer->ByteLength();
     const auto checkedBytesAfterOffset = CheckedUint32(bytesAvailable) - offset;
 
     uint32_t bytesAfterOffset = 0;
     if (checkedBytesAfterOffset.isValid()) {
         bytesAfterOffset = checkedBytesAfterOffset.value();
     }
 
     gl->MakeCurrent();
-    const ScopedLazyBind lazyBind(gl, LOCAL_GL_PIXEL_PACK_BUFFER, buffer);
+    const ScopedLazyBind lazyBind(gl, LOCAL_GL_PIXEL_PACK_BUFFER, mBoundPixelPackBuffer);
 
     ReadPixelsImpl(x, y, width, height, format, type, (void*)offset, bytesAfterOffset);
 }
 
 static bool
 ValidateReadPixelsFormatAndType(const webgl::FormatInfo* srcFormat,
                                 const webgl::PackingInfo& pi, gl::GLContext* gl,
                                 WebGLContext* webgl)
@@ -2059,35 +2111,35 @@ WebGLContext::UseProgram(WebGLProgram* p
         return;
 
     if (!prog) {
         mCurrentProgram = nullptr;
         mActiveProgramLinkInfo = nullptr;
         return;
     }
 
-    if (!ValidateObject("useProgram", *prog))
+    if (!ValidateObject("useProgram", prog))
         return;
 
     if (prog->UseProgram()) {
         mCurrentProgram = prog;
         mActiveProgramLinkInfo = mCurrentProgram->LinkInfo();
     }
 }
 
 void
-WebGLContext::ValidateProgram(const WebGLProgram& prog)
+WebGLContext::ValidateProgram(WebGLProgram* prog)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("validateProgram", prog))
         return;
 
-    prog.ValidateProgram();
+    prog->ValidateProgram();
 }
 
 already_AddRefed<WebGLFramebuffer>
 WebGLContext::CreateFramebuffer()
 {
     if (IsContextLost())
         return nullptr;
 
@@ -2124,51 +2176,53 @@ WebGLContext::Viewport(GLint x, GLint y,
 
     mViewportX = x;
     mViewportY = y;
     mViewportWidth = width;
     mViewportHeight = height;
 }
 
 void
-WebGLContext::CompileShader(WebGLShader& shader)
+WebGLContext::CompileShader(WebGLShader* shader)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("compileShader", shader))
         return;
 
-    shader.CompileShader();
+    shader->CompileShader();
 }
 
 JS::Value
-WebGLContext::GetShaderParameter(const WebGLShader& shader, GLenum pname)
+WebGLContext::GetShaderParameter(WebGLShader* shader, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
-    if (!ValidateObjectAllowDeleted("getShaderParameter: shader", shader))
+    if (!ValidateObject("getShaderParameter: shader", shader))
         return JS::NullValue();
 
-    return shader.GetShaderParameter(pname);
+    return shader->GetShaderParameter(pname);
 }
 
 void
-WebGLContext::GetShaderInfoLog(const WebGLShader& shader, nsAString& retval)
+WebGLContext::GetShaderInfoLog(WebGLShader* shader, nsAString& retval)
 {
     retval.SetIsVoid(true);
 
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getShaderInfoLog: shader", shader))
         return;
 
-    shader.GetShaderInfoLog(&retval);
+    shader->GetShaderInfoLog(&retval);
+
+    retval.SetIsVoid(false);
 }
 
 already_AddRefed<WebGLShaderPrecisionFormat>
 WebGLContext::GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)
 {
     if (IsContextLost())
         return nullptr;
 
@@ -2210,39 +2264,53 @@ WebGLContext::GetShaderPrecisionFormat(G
     }
 
     RefPtr<WebGLShaderPrecisionFormat> retShaderPrecisionFormat
         = new WebGLShaderPrecisionFormat(this, range[0], range[1], precision);
     return retShaderPrecisionFormat.forget();
 }
 
 void
-WebGLContext::GetShaderSource(const WebGLShader& shader, nsAString& retval)
+WebGLContext::GetShaderSource(WebGLShader* shader, nsAString& retval)
 {
     retval.SetIsVoid(true);
 
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getShaderSource: shader", shader))
         return;
 
-    shader.GetShaderSource(&retval);
+    shader->GetShaderSource(&retval);
 }
 
 void
-WebGLContext::ShaderSource(WebGLShader& shader, const nsAString& source)
+WebGLContext::ShaderSource(WebGLShader* shader, const nsAString& source)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("shaderSource: shader", shader))
         return;
 
-    shader.ShaderSource(source);
+    shader->ShaderSource(source);
+}
+
+void
+WebGLContext::GetShaderTranslatedSource(WebGLShader* shader, nsAString& retval)
+{
+    retval.SetIsVoid(true);
+
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObject("getShaderTranslatedSource: shader", shader))
+        return;
+
+    shader->GetShaderTranslatedSource(&retval);
 }
 
 void
 WebGLContext::LoseContext()
 {
     if (IsContextLost())
         return ErrorInvalidOperation("loseContext: Context is already lost.");
 
--- a/dom/canvas/WebGLContextTextures.cpp
+++ b/dom/canvas/WebGLContextTextures.cpp
@@ -204,17 +204,17 @@ WebGLContext::InvalidateResolveCacheForT
 // GL calls
 
 void
 WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
 {
     if (IsContextLost())
         return;
 
-     if (newTex && !ValidateObject("bindTexture", *newTex))
+     if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex))
         return;
 
     // Need to check rawTarget first before comparing against newTex->Target() as
     // newTex->Target() returns a TexTarget, which will assert on invalid value.
     WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
     switch (rawTarget) {
     case LOCAL_GL_TEXTURE_2D:
         currentTexPtr = &mBound2DTextures[mActiveTexture];
@@ -285,17 +285,20 @@ WebGLContext::GetTexParameter(GLenum raw
     }
 
     return tex->GetTexParameter(texTarget, pname);
 }
 
 bool
 WebGLContext::IsTexture(WebGLTexture* tex)
 {
-    if (!ValidateIsObject("isTexture", tex))
+    if (IsContextLost())
+        return false;
+
+    if (!ValidateObjectAllowDeleted("isTexture", tex))
         return false;
 
     return tex->IsTexture();
 }
 
 void
 WebGLContext::TexParameter_base(GLenum rawTexTarget, GLenum pname, GLint* maybeIntParam,
                                 GLfloat* maybeFloatParam)
--- a/dom/canvas/WebGLContextUnchecked.cpp
+++ b/dom/canvas/WebGLContextUnchecked.cpp
@@ -11,9 +11,84 @@
 
 namespace mozilla {
 
 WebGLContextUnchecked::WebGLContextUnchecked(gl::GLContext* _gl)
     : mGL_OnlyClearInDestroyResourcesAndContext(_gl)
     , gl(mGL_OnlyClearInDestroyResourcesAndContext) // const reference
 { }
 
+// -----------------------------------------------------------------------------
+// Sampler Objects
+
+void
+WebGLContextUnchecked::BindSampler(GLuint unit, WebGLSampler* sampler)
+{
+    gl->MakeCurrent();
+    gl->fBindSampler(unit, sampler ? sampler->mGLName : 0);
+}
+
+GLint
+WebGLContextUnchecked::GetSamplerParameteriv(WebGLSampler* sampler,
+                                             GLenum pname)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+
+    GLint param = 0;
+    gl->MakeCurrent();
+    gl->fGetSamplerParameteriv(sampler->mGLName, pname, &param);
+
+    return param;
+}
+
+GLfloat
+WebGLContextUnchecked::GetSamplerParameterfv(WebGLSampler* sampler,
+                                             GLenum pname)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+
+    GLfloat param = 0.0f;
+    gl->MakeCurrent();
+    gl->fGetSamplerParameterfv(sampler->mGLName, pname, &param);
+    return param;
+}
+
+void
+WebGLContextUnchecked::SamplerParameteri(WebGLSampler* sampler,
+                                         GLenum pname,
+                                         GLint param)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+    gl->MakeCurrent();
+    gl->fSamplerParameteri(sampler->mGLName, pname, param);
+}
+
+void
+WebGLContextUnchecked::SamplerParameteriv(WebGLSampler* sampler,
+                                          GLenum pname,
+                                          const GLint* param)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+    gl->MakeCurrent();
+    gl->fSamplerParameteriv(sampler->mGLName, pname, param);
+}
+
+void
+WebGLContextUnchecked::SamplerParameterf(WebGLSampler* sampler,
+                                         GLenum pname,
+                                         GLfloat param)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+    gl->MakeCurrent();
+    gl->fSamplerParameterf(sampler->mGLName, pname, param);
+}
+
+void
+WebGLContextUnchecked::SamplerParameterfv(WebGLSampler* sampler,
+                                          GLenum pname,
+                                          const GLfloat* param)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+    gl->MakeCurrent();
+    gl->fSamplerParameterfv(sampler->mGLName, pname, param);
+}
+
 } // namespace mozilla
--- a/dom/canvas/WebGLContextUnchecked.h
+++ b/dom/canvas/WebGLContextUnchecked.h
@@ -15,16 +15,28 @@ namespace mozilla {
 class WebGLBuffer;
 class WebGLSampler;
 
 class WebGLContextUnchecked
 {
 public:
     explicit WebGLContextUnchecked(gl::GLContext* gl);
 
+    // -------------------------------------------------------------------------
+    // Sampler Objects
+    void BindSampler(GLuint unit, WebGLSampler* sampler);
+
+    GLint   GetSamplerParameteriv(WebGLSampler* sampler, GLenum pname);
+    GLfloat GetSamplerParameterfv(WebGLSampler* sampler, GLenum pname);
+
+    void SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param);
+    void SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const GLint* param);
+    void SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param);
+    void SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const GLfloat* param);
+
 protected:
     // We've had issues in the past with nulling `gl` without actually releasing
     // all of our resources. This construction ensures that we are aware that we
     // should only null `gl` in DestroyResourcesAndContext.
     RefPtr<gl::GLContext> mGL_OnlyClearInDestroyResourcesAndContext;
 public:
     // Grab a const reference so we can see changes, but can't make changes.
     const decltype(mGL_OnlyClearInDestroyResourcesAndContext)& gl;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -192,27 +192,182 @@ WebGLContext::ValidateDrawModeEnum(GLenu
 
     default:
         ErrorInvalidEnumInfo(info, mode);
         return false;
     }
 }
 
 bool
+WebGLContext::ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
+                                            const char* funcName,
+                                            bool badColorAttachmentIsInvalidOp)
+{
+    if (!fb) {
+        switch (attachment) {
+        case LOCAL_GL_COLOR:
+        case LOCAL_GL_DEPTH:
+        case LOCAL_GL_STENCIL:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
+                             funcName, attachment);
+            return false;
+        }
+    }
+
+    if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
+        attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
+        attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+    {
+        return true;
+    }
+
+    if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
+        attachment <= LastColorAttachmentEnum())
+    {
+        return true;
+    }
+
+    if (badColorAttachmentIsInvalidOp &&
+        attachment >= LOCAL_GL_COLOR_ATTACHMENT0)
+    {
+        const uint32_t offset = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
+        ErrorInvalidOperation("%s: Bad color attachment: COLOR_ATTACHMENT%u. (0x%04x)",
+                              funcName, offset, attachment);
+    } else {
+        ErrorInvalidEnum("%s: attachment: Bad attachment 0x%x.", funcName, attachment);
+    }
+    return false;
+}
+
+/**
+ * Return true if pname is valid for GetSamplerParameter calls.
+ */
+bool
+WebGLContext::ValidateSamplerParameterName(GLenum pname, const char* info)
+{
+    switch (pname) {
+    case LOCAL_GL_TEXTURE_MIN_FILTER:
+    case LOCAL_GL_TEXTURE_MAG_FILTER:
+    case LOCAL_GL_TEXTURE_WRAP_S:
+    case LOCAL_GL_TEXTURE_WRAP_T:
+    case LOCAL_GL_TEXTURE_WRAP_R:
+    case LOCAL_GL_TEXTURE_MIN_LOD:
+    case LOCAL_GL_TEXTURE_MAX_LOD:
+    case LOCAL_GL_TEXTURE_COMPARE_MODE:
+    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
+        return true;
+
+    default:
+        ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
+        return false;
+    }
+}
+
+/**
+ * Return true if pname and param are valid combination for SamplerParameter calls.
+ */
+bool
+WebGLContext::ValidateSamplerParameterParams(GLenum pname, const WebGLIntOrFloat& param, const char* info)
+{
+    const GLenum p = param.AsInt();
+
+    switch (pname) {
+    case LOCAL_GL_TEXTURE_MIN_FILTER:
+        switch (p) {
+        case LOCAL_GL_NEAREST:
+        case LOCAL_GL_LINEAR:
+        case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
+        case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
+        case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
+        case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    case LOCAL_GL_TEXTURE_MAG_FILTER:
+        switch (p) {
+        case LOCAL_GL_NEAREST:
+        case LOCAL_GL_LINEAR:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    case LOCAL_GL_TEXTURE_WRAP_S:
+    case LOCAL_GL_TEXTURE_WRAP_T:
+    case LOCAL_GL_TEXTURE_WRAP_R:
+        switch (p) {
+        case LOCAL_GL_CLAMP_TO_EDGE:
+        case LOCAL_GL_REPEAT:
+        case LOCAL_GL_MIRRORED_REPEAT:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    case LOCAL_GL_TEXTURE_MIN_LOD:
+    case LOCAL_GL_TEXTURE_MAX_LOD:
+        return true;
+
+    case LOCAL_GL_TEXTURE_COMPARE_MODE:
+        switch (param.AsInt()) {
+        case LOCAL_GL_NONE:
+        case LOCAL_GL_COMPARE_REF_TO_TEXTURE:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
+        switch (p) {
+        case LOCAL_GL_LEQUAL:
+        case LOCAL_GL_GEQUAL:
+        case LOCAL_GL_LESS:
+        case LOCAL_GL_GREATER:
+        case LOCAL_GL_EQUAL:
+        case LOCAL_GL_NOTEQUAL:
+        case LOCAL_GL_ALWAYS:
+        case LOCAL_GL_NEVER:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    default:
+        ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
+        return false;
+    }
+}
+
+bool
 WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
 {
     /* GLES 2.0.25, p38:
      *   If the value of location is -1, the Uniform* commands will silently
      *   ignore the data passed in, and the current uniform values will not be
      *   changed.
      */
     if (!loc)
         return false;
 
-    if (!ValidateObjectAllowDeleted(funcName, *loc))
+    if (!ValidateObject(funcName, loc))
         return false;
 
     if (!mCurrentProgram) {
         ErrorInvalidOperation("%s: No program is currently bound.", funcName);
         return false;
     }
 
     return loc->ValidateForProgram(mCurrentProgram, funcName);
--- a/dom/canvas/WebGLContextVertexArray.cpp
+++ b/dom/canvas/WebGLContextVertexArray.cpp
@@ -13,19 +13,30 @@
 namespace mozilla {
 
 void
 WebGLContext::BindVertexArray(WebGLVertexArray* array)
 {
     if (IsContextLost())
         return;
 
-    if (array && !ValidateObject("bindVertexArrayObject", *array))
+    if (!ValidateObjectAllowDeletedOrNull("bindVertexArrayObject", array))
         return;
 
+    if (array && array->IsDeleted()) {
+        /* http://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt
+         * BindVertexArrayOES fails and an INVALID_OPERATION error is
+         * generated if array is not a name returned from a previous call to
+         * GenVertexArraysOES, or if such a name has since been deleted with
+         * DeleteVertexArraysOES
+         */
+        ErrorInvalidOperation("bindVertexArray: can't bind a deleted array!");
+        return;
+    }
+
     InvalidateBufferFetching();
 
     MakeContextCurrent();
 
     if (array == nullptr) {
         array = mDefaultVertexArray;
     }
 
@@ -52,28 +63,43 @@ WebGLVertexArray*
 WebGLContext::CreateVertexArrayImpl()
 {
     return WebGLVertexArray::Create(this);
 }
 
 void
 WebGLContext::DeleteVertexArray(WebGLVertexArray* array)
 {
-    if (!ValidateDeleteObject("deleteVertexArray", array))
+    if (IsContextLost())
+        return;
+
+    if (array == nullptr)
+        return;
+
+    if (array->IsDeleted())
         return;
 
     if (mBoundVertexArray == array)
         BindVertexArray(static_cast<WebGLVertexArray*>(nullptr));
 
     array->RequestDelete();
 }
 
 bool
-WebGLContext::IsVertexArray(const WebGLVertexArray* array)
+WebGLContext::IsVertexArray(WebGLVertexArray* array)
 {
-    if (!ValidateIsObject("isVertexArray", array))
+    if (IsContextLost())
+        return false;
+
+    if (!array)
+        return false;
+
+    if (!ValidateObjectAllowDeleted("isVertexArray", array))
+        return false;
+
+    if (array->IsDeleted())
         return false;
 
     MakeContextCurrent();
     return array->IsVertexArray();
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLExtensionDebugShaders.cpp
+++ b/dom/canvas/WebGLExtensionDebugShaders.cpp
@@ -2,48 +2,42 @@
 /* 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 "WebGLExtensions.h"
 
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "WebGLContext.h"
-#include "WebGLShader.h"
 
 namespace mozilla {
 
 WebGLExtensionDebugShaders::WebGLExtensionDebugShaders(WebGLContext* webgl)
     : WebGLExtensionBase(webgl)
 {
 }
 
 WebGLExtensionDebugShaders::~WebGLExtensionDebugShaders()
 {
 }
 
 // If no source has been defined, compileShader() has not been called, or the
 // translation has failed for shader, an empty string is returned; otherwise,
 // return the translated source.
 void
-WebGLExtensionDebugShaders::GetTranslatedShaderSource(const WebGLShader& shader,
-                                                      nsAString& retval) const
+WebGLExtensionDebugShaders::GetTranslatedShaderSource(WebGLShader* shader,
+                                                      nsAString& retval)
 {
     retval.SetIsVoid(true);
 
     if (mIsLost) {
         mContext->ErrorInvalidOperation("%s: Extension is lost.",
                                         "getTranslatedShaderSource");
         return;
     }
 
-    if (mContext->IsContextLost())
-        return;
-
-    if (!mContext->ValidateObject("getShaderTranslatedSource: shader", shader))
-        return;
-
-    shader.GetShaderTranslatedSource(&retval);
+    retval.SetIsVoid(false);
+    mContext->GetShaderTranslatedSource(shader, retval);
 }
 
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionDebugShaders, WEBGL_debug_shaders)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
+++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
@@ -52,17 +52,17 @@ WebGLExtensionDisjointTimerQuery::IsQuer
     const char funcName[] = "isQueryEXT";
     if (mIsLost)
         return false;
 
     return mContext->IsQuery(query, funcName);
 }
 
 void
-WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target, WebGLQuery& query) const
+WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target, WebGLQuery* query) const
 {
     const char funcName[] = "beginQueryEXT";
     if (mIsLost)
         return;
 
     mContext->BeginQuery(target, query, funcName);
 }
 
@@ -72,43 +72,43 @@ WebGLExtensionDisjointTimerQuery::EndQue
     const char funcName[] = "endQueryEXT";
     if (mIsLost)
         return;
 
     mContext->EndQuery(target, funcName);
 }
 
 void
-WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLQuery& query, GLenum target) const
+WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLQuery* query, GLenum target) const
 {
     const char funcName[] = "queryCounterEXT";
     if (mIsLost)
         return;
 
     if (!mContext->ValidateObject(funcName, query))
         return;
 
-    query.QueryCounter(funcName, target);
+    query->QueryCounter(funcName, target);
 }
 
 void
 WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, GLenum pname,
                                               JS::MutableHandleValue retval) const
 {
     const char funcName[] = "getQueryEXT";
     retval.setNull();
     if (mIsLost)
         return;
 
     mContext->GetQuery(cx, target, pname, retval, funcName);
 }
 
 void
 WebGLExtensionDisjointTimerQuery::GetQueryObjectEXT(JSContext* cx,
-                                                    const WebGLQuery& query, GLenum pname,
+                                                    const WebGLQuery* query, GLenum pname,
                                                     JS::MutableHandleValue retval) const
 {
     const char funcName[] = "getQueryObjectEXT";
     retval.setNull();
     if (mIsLost)
         return;
 
     mContext->GetQueryParameter(cx, query, pname, retval, funcName);
--- a/dom/canvas/WebGLExtensionVertexArray.cpp
+++ b/dom/canvas/WebGLExtensionVertexArray.cpp
@@ -36,17 +36,17 @@ WebGLExtensionVertexArray::DeleteVertexA
 {
     if (mIsLost)
         return;
 
     mContext->DeleteVertexArray(array);
 }
 
 bool
-WebGLExtensionVertexArray::IsVertexArrayOES(const WebGLVertexArray* array)
+WebGLExtensionVertexArray::IsVertexArrayOES(WebGLVertexArray* array)
 {
     if (mIsLost)
         return false;
 
     return mContext->IsVertexArray(array);
 }
 
 void
--- a/dom/canvas/WebGLExtensions.h
+++ b/dom/canvas/WebGLExtensions.h
@@ -122,17 +122,17 @@ public:
 
 class WebGLExtensionDebugShaders
     : public WebGLExtensionBase
 {
 public:
     explicit WebGLExtensionDebugShaders(WebGLContext*);
     virtual ~WebGLExtensionDebugShaders();
 
-    void GetTranslatedShaderSource(const WebGLShader& shader, nsAString& retval) const;
+    void GetTranslatedShaderSource(WebGLShader* shader, nsAString& retval);
 
     DECL_WEBGL_EXTENSION_GOOP
 };
 
 class WebGLExtensionDepthTexture
     : public WebGLExtensionBase
 {
 public:
@@ -321,17 +321,17 @@ class WebGLExtensionVertexArray
     : public WebGLExtensionBase
 {
 public:
     explicit WebGLExtensionVertexArray(WebGLContext* webgl);
     virtual ~WebGLExtensionVertexArray();
 
     already_AddRefed<WebGLVertexArray> CreateVertexArrayOES();
     void DeleteVertexArrayOES(WebGLVertexArray* array);
-    bool IsVertexArrayOES(const WebGLVertexArray* array);
+    bool IsVertexArrayOES(WebGLVertexArray* array);
     void BindVertexArrayOES(WebGLVertexArray* array);
 
     DECL_WEBGL_EXTENSION_GOOP
 };
 
 class WebGLExtensionInstancedArrays
     : public WebGLExtensionBase
 {
@@ -367,22 +367,22 @@ class WebGLExtensionDisjointTimerQuery
 {
 public:
     explicit WebGLExtensionDisjointTimerQuery(WebGLContext* webgl);
     virtual ~WebGLExtensionDisjointTimerQuery();
 
     already_AddRefed<WebGLQuery> CreateQueryEXT() const;
     void DeleteQueryEXT(WebGLQuery* query) const;
     bool IsQueryEXT(const WebGLQuery* query) const;
-    void BeginQueryEXT(GLenum target, WebGLQuery& query) const;
+    void BeginQueryEXT(GLenum target, WebGLQuery* query) const;
     void EndQueryEXT(GLenum target) const;
-    void QueryCounterEXT(WebGLQuery& query, GLenum target) const;
+    void QueryCounterEXT(WebGLQuery* query, GLenum target) const;
     void GetQueryEXT(JSContext* cx, GLenum target, GLenum pname,
                      JS::MutableHandleValue retval) const;
-    void GetQueryObjectEXT(JSContext* cx, const WebGLQuery& query,
+    void GetQueryObjectEXT(JSContext* cx, const WebGLQuery* query,
                            GLenum pname, JS::MutableHandleValue retval) const;
 
     static bool IsSupported(const WebGLContext*);
 
     DECL_WEBGL_EXTENSION_GOOP
 };
 
 } // namespace mozilla
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -599,17 +599,17 @@ WebGLFBAttachPoint::GetParameter(const c
     return JS::Int32Value(ret);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // WebGLFramebuffer
 
 WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(fbo)
 #ifdef ANDROID
     , mIsFB(false)
 #endif
     , mDepthAttachment(this, LOCAL_GL_DEPTH_ATTACHMENT)
     , mStencilAttachment(this, LOCAL_GL_STENCIL_ATTACHMENT)
     , mDepthStencilAttachment(this, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
 {
@@ -1296,17 +1296,17 @@ WebGLFramebuffer::FramebufferRenderbuffe
 
     // `rbTarget`
     if (rbtarget != LOCAL_GL_RENDERBUFFER) {
         mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: rbtarget:", rbtarget);
         return;
     }
 
     // `rb`
-    if (rb && !mContext->ValidateObject("framebufferRenderbuffer: rb", *rb))
+    if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: rb", rb))
         return;
 
     // End of validation.
 
     if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
         mDepthAttachment.SetRenderbuffer(rb);
         mStencilAttachment.SetRenderbuffer(rb);
     } else {
@@ -1338,20 +1338,20 @@ WebGLFramebuffer::FramebufferTexture2D(c
          texImageTarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
     {
         mContext->ErrorInvalidEnumInfo("framebufferTexture2D: texImageTarget:",
                                        texImageTarget);
         return;
     }
 
     // `texture`
+    if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", tex))
+        return;
+
     if (tex) {
-        if (!mContext->ValidateObject("framebufferTexture2D: texture", *tex))
-            return;
-
         if (!tex->HasEverBeenBound()) {
             mContext->ErrorInvalidOperation("%s: `texture` has never been bound.",
                                             funcName);
             return;
         }
 
         const TexTarget destTexTarget = TexImageTargetToTexTarget(texImageTarget);
         if (tex->Target() != destTexTarget) {
@@ -1414,35 +1414,34 @@ WebGLFramebuffer::FramebufferTextureLaye
     // `attachment`
     const auto maybeAttach = GetAttachPoint(attachEnum);
     if (!maybeAttach || !maybeAttach.value()) {
         mContext->ErrorInvalidEnum("%s: Bad `attachment`: 0x%x.", funcName, attachEnum);
         return;
     }
     const auto& attach = maybeAttach.value();
 
+    // `texture`
+    if (!mContext->ValidateObjectAllowNull("framebufferTextureLayer: texture", tex))
+        return;
+
+    if (tex && !tex->HasEverBeenBound()) {
+        mContext->ErrorInvalidOperation("%s: `texture` has never been bound.", funcName);
+        return;
+    }
+
     // `level`, `layer`
     if (layer < 0)
         return mContext->ErrorInvalidValue("%s: `layer` must be >= 0.", funcName);
 
     if (level < 0)
         return mContext->ErrorInvalidValue("%s: `level` must be >= 0.", funcName);
 
-    // `texture`
     TexImageTarget texImageTarget = LOCAL_GL_TEXTURE_3D;
     if (tex) {
-        if (!mContext->ValidateObject("framebufferTextureLayer: texture", *tex))
-            return;
-
-        if (!tex->HasEverBeenBound()) {
-            mContext->ErrorInvalidOperation("%s: `texture` has never been bound.",
-                                            funcName);
-            return;
-        }
-
         texImageTarget = tex->Target().get();
         switch (texImageTarget.get()) {
         case LOCAL_GL_TEXTURE_3D:
             if (uint32_t(layer) >= mContext->mImplMax3DTextureSize) {
                 mContext->ErrorInvalidValue("%s: `layer` must be < %s.", funcName,
                                             "MAX_3D_TEXTURE_SIZE");
                 return;
             }
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -127,16 +127,17 @@ public:
         }
     };
 };
 
 class WebGLFramebuffer final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLFramebuffer>
     , public LinkedListElement<WebGLFramebuffer>
+    , public WebGLContextBoundObject
     , public SupportsWeakPtr<WebGLFramebuffer>
 {
     friend class WebGLContext;
 
 public:
     MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLFramebuffer)
 
     const GLuint mGLName;
--- a/dom/canvas/WebGLObjectModel.h
+++ b/dom/canvas/WebGLObjectModel.h
@@ -7,65 +7,18 @@
 #define WEBGLOBJECTMODEL_H_
 
 #include "nsCycleCollectionNoteChild.h"
 
 #include "WebGLTypes.h"
 
 namespace mozilla {
 
-template<typename> class LinkedList;
 class WebGLContext;
 
-////
-
-// This class is a mixin for objects that are tied to a specific
-// context (which is to say, all of them).  They provide initialization
-// as well as comparison with the current context.
-class WebGLContextBoundObject
-{
-public:
-    WebGLContext* const mContext;
-private:
-    const uint32_t mContextGeneration;
-
-public:
-    explicit WebGLContextBoundObject(WebGLContext* webgl);
-
-    bool IsCompatibleWithContext(const WebGLContext* other) const;
-};
-
-////
-
-class WebGLDeletableObject : public WebGLContextBoundObject
-{
-    template<typename> friend class WebGLRefCountedObject;
-
-private:
-    enum DeletionStatus { Default, DeleteRequested, Deleted };
-
-    DeletionStatus mDeletionStatus;
-
-    ////
-
-    explicit WebGLDeletableObject(WebGLContext* webgl)
-      : WebGLContextBoundObject(webgl)
-      , mDeletionStatus(Default)
-    { }
-
-    ~WebGLDeletableObject() {
-        MOZ_ASSERT(mDeletionStatus == Deleted,
-                   "Derived class destructor must call DeleteOnce().");
-    }
-
-public:
-    bool IsDeleted() const { return mDeletionStatus == Deleted; }
-    bool IsDeleteRequested() const { return mDeletionStatus != Default; }
-};
-
 /* Each WebGL object class WebGLFoo wants to:
  *  - inherit WebGLRefCountedObject<WebGLFoo>
  *  - implement a Delete() method
  *  - have its destructor call DeleteOnce()
  *
  * This base class provides two features to WebGL object types:
  * 1. support for OpenGL object reference counting
  * 2. support for OpenGL deletion statuses
@@ -133,35 +86,32 @@ public:
  * derived class were final, but that would be impossible to enforce and would
  * lead to strange bugs if it were subclassed.
  *
  * This WebGLRefCountedObject class takes the Derived type as template
  * parameter, as a means to allow DeleteOnce to call Delete() on the Derived
  * class, without either method being virtual. This is a common C++ pattern
  * known as the "curiously recursive template pattern (CRTP)".
  */
-
 template<typename Derived>
-class WebGLRefCountedObject : public WebGLDeletableObject
+class WebGLRefCountedObject
 {
-    friend class WebGLContext;
-    template<typename T> friend void ClearLinkedList(LinkedList<T>& list);
+public:
+    enum DeletionStatus { Default, DeleteRequested, Deleted };
 
-private:
-    nsAutoRefCnt mWebGLRefCnt;
-
-public:
-    explicit WebGLRefCountedObject(WebGLContext* webgl)
-        : WebGLDeletableObject(webgl)
-    { }
+    WebGLRefCountedObject()
+      : mDeletionStatus(Default)
+    {}
 
     ~WebGLRefCountedObject() {
         MOZ_ASSERT(mWebGLRefCnt == 0,
                    "Destroying WebGL object still referenced by other WebGL"
                    " objects.");
+        MOZ_ASSERT(mDeletionStatus == Deleted,
+                   "Derived class destructor must call DeleteOnce().");
     }
 
     // called by WebGLRefPtr
     void WebGLAddRef() {
         ++mWebGLRefCnt;
     }
 
     // called by WebGLRefPtr
@@ -174,32 +124,43 @@ public:
 
     // this is the function that WebGL.deleteXxx() functions want to call
     void RequestDelete() {
         if (mDeletionStatus == Default)
             mDeletionStatus = DeleteRequested;
         MaybeDelete();
     }
 
-protected:
+    bool IsDeleted() const {
+        return mDeletionStatus == Deleted;
+    }
+
+    bool IsDeleteRequested() const {
+        return mDeletionStatus != Default;
+    }
+
     void DeleteOnce() {
         if (mDeletionStatus != Deleted) {
             static_cast<Derived*>(this)->Delete();
             mDeletionStatus = Deleted;
         }
     }
 
 private:
     void MaybeDelete() {
         if (mWebGLRefCnt == 0 &&
             mDeletionStatus == DeleteRequested)
         {
             DeleteOnce();
         }
     }
+
+protected:
+    nsAutoRefCnt mWebGLRefCnt;
+    DeletionStatus mDeletionStatus;
 };
 
 /* This WebGLRefPtr class is meant to be used for references between WebGL
  * objects. For example, a WebGLProgram holds WebGLRefPtr's to the WebGLShader's
  * attached to it.
  *
  * Why the need for a separate refptr class? The only special thing that
  * WebGLRefPtr does is that it increments and decrements the WebGL refcount of
@@ -293,16 +254,31 @@ private:
         mRawPtr = newPtr;
         ReleasePtr(oldPtr);
     }
 
 protected:
     T* mRawPtr;
 };
 
+// This class is a mixin for objects that are tied to a specific
+// context (which is to say, all of them).  They provide initialization
+// as well as comparison with the current context.
+class WebGLContextBoundObject
+{
+public:
+    explicit WebGLContextBoundObject(WebGLContext* webgl);
+
+    bool IsCompatibleWithContext(const WebGLContext* other) const;
+
+    WebGLContext* const mContext;
+protected:
+    const uint32_t mContextGeneration;
+};
+
 // this class is a mixin for GL objects that have dimensions
 // that we need to track.
 class WebGLRectangleObject
 {
 public:
     WebGLRectangleObject()
         : mWidth(0)
         , mHeight(0)
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -438,17 +438,17 @@ webgl::LinkedProgramInfo::~LinkedProgram
 static GLuint
 CreateProgram(gl::GLContext* gl)
 {
     gl->MakeCurrent();
     return gl->fCreateProgram();
 }
 
 WebGLProgram::WebGLProgram(WebGLContext* webgl)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(CreateProgram(webgl->GL()))
     , mNumActiveTFOs(0)
     , mNextLink_TransformFeedbackBufferMode(LOCAL_GL_SEPARATE_ATTRIBS)
 {
     mContext->mPrograms.insertBack(this);
 }
 
 WebGLProgram::~WebGLProgram()
@@ -532,17 +532,17 @@ WebGLProgram::BindAttribLocation(GLuint 
     const bool wasInserted = res.second;
     if (!wasInserted) {
         auto itr = res.first;
         itr->second = loc;
     }
 }
 
 void
-WebGLProgram::DetachShader(const WebGLShader* shader)
+WebGLProgram::DetachShader(WebGLShader* shader)
 {
     MOZ_ASSERT(shader);
 
     WebGLRefPtr<WebGLShader>* shaderSlot;
     switch (shader->mType) {
     case LOCAL_GL_VERTEX_SHADER:
         shaderSlot = &mVertShader;
         break;
@@ -1439,17 +1439,17 @@ WebGLProgram::TransformFeedbackVaryings(
     case LOCAL_GL_INTERLEAVED_ATTRIBS:
         break;
 
     case LOCAL_GL_SEPARATE_ATTRIBS:
         {
             GLuint maxAttribs = 0;
             gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
                              &maxAttribs);
-            if (varyings.Length() > maxAttribs) {
+            if (varyings.Length() >= maxAttribs) {
                 mContext->ErrorInvalidValue("%s: Length of `varyings` exceeds %s.",
                                             funcName,
                                             "TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
                 return;
             }
         }
         break;
 
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -125,31 +125,32 @@ struct LinkedProgramInfo final
 };
 
 } // namespace webgl
 
 class WebGLProgram final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLProgram>
     , public LinkedListElement<WebGLProgram>
+    , public WebGLContextBoundObject
 {
     friend class WebGLTransformFeedback;
 
 public:
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
 
     explicit WebGLProgram(WebGLContext* webgl);
 
     void Delete();
 
     // GL funcs
     void AttachShader(WebGLShader* shader);
     void BindAttribLocation(GLuint index, const nsAString& name);
-    void DetachShader(const WebGLShader* shader);
+    void DetachShader(WebGLShader* shader);
     already_AddRefed<WebGLActiveInfo> GetActiveAttrib(GLuint index) const;
     already_AddRefed<WebGLActiveInfo> GetActiveUniform(GLuint index) const;
     void GetAttachedShaders(nsTArray<RefPtr<WebGLShader>>* const out) const;
     GLint GetAttribLocation(const nsAString& name) const;
     GLint GetFragDataLocation(const nsAString& name) const;
     void GetProgramInfoLog(nsAString* const out) const;
     JS::Value GetProgramParameter(GLenum pname) const;
     GLuint GetUniformBlockIndex(const nsAString& name) const;
--- a/dom/canvas/WebGLQuery.cpp
+++ b/dom/canvas/WebGLQuery.cpp
@@ -35,17 +35,17 @@ GenQuery(gl::GLContext* gl)
     gl->MakeCurrent();
 
     GLuint ret = 0;
     gl->fGenQueries(1, &ret);
     return ret;
 }
 
 WebGLQuery::WebGLQuery(WebGLContext* webgl)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(GenQuery(mContext->gl))
     , mTarget(0)
     , mActiveSlot(nullptr)
     , mCanBeAvailable(false)
 {
     mContext->mQueries.insertBack(this);
 }
 
@@ -206,28 +206,30 @@ WebGLQuery::GetQueryParameter(GLenum pna
     default:
         MOZ_CRASH("Bad `pname`.");
     }
 }
 
 bool
 WebGLQuery::IsQuery() const
 {
-    MOZ_ASSERT(!IsDeleted());
+    if (IsDeleted())
+        return false;
 
     if (!mTarget)
         return false;
 
     return true;
 }
 
 void
 WebGLQuery::DeleteQuery()
 {
-    MOZ_ASSERT(!IsDeleteRequested());
+    if (IsDeleted())
+        return;
 
     if (mActiveSlot) {
         EndQuery();
     }
 
     RequestDelete();
 }
 
--- a/dom/canvas/WebGLQuery.h
+++ b/dom/canvas/WebGLQuery.h
@@ -13,16 +13,17 @@
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 
 class WebGLQuery final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLQuery>
     , public LinkedListElement<WebGLQuery>
+    , public WebGLContextBoundObject
 {
     friend class AvailableRunnable;
     friend class WebGLRefCountedObject<WebGLQuery>;
 
 public:
     const GLuint mGLName;
 private:
     GLenum mTarget;
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -42,17 +42,17 @@ DoCreateRenderbuffer(gl::GLContext* gl)
 
 static bool
 EmulatePackedDepthStencil(gl::GLContext* gl)
 {
     return !gl->IsSupported(gl::GLFeature::packed_depth_stencil);
 }
 
 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mPrimaryRB( DoCreateRenderbuffer(webgl->gl) )
     , mEmulatePackedDepthStencil( EmulatePackedDepthStencil(webgl->gl) )
     , mSecondaryRB(0)
     , mFormat(nullptr)
     , mSamples(0)
     , mImageDataStatus(WebGLImageDataStatus::NoImageData)
     , mHasBeenBound(false)
 {
--- a/dom/canvas/WebGLRenderbuffer.h
+++ b/dom/canvas/WebGLRenderbuffer.h
@@ -18,16 +18,17 @@ namespace webgl {
 struct FormatUsageInfo;
 }
 
 class WebGLRenderbuffer final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLRenderbuffer>
     , public LinkedListElement<WebGLRenderbuffer>
     , public WebGLRectangleObject
+    , public WebGLContextBoundObject
     , public WebGLFramebufferAttachable
 {
     friend class WebGLContext;
     friend class WebGLFramebuffer;
     friend class WebGLFBAttachPoint;
 
 public:
     const GLuint mPrimaryRB;
--- a/dom/canvas/WebGLSampler.cpp
+++ b/dom/canvas/WebGLSampler.cpp
@@ -7,17 +7,17 @@
 
 #include "GLContext.h"
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "WebGLContext.h"
 
 namespace mozilla {
 
 WebGLSampler::WebGLSampler(WebGLContext* webgl, GLuint sampler)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(sampler)
     , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
     , mMagFilter(LOCAL_GL_LINEAR)
     , mWrapS(LOCAL_GL_REPEAT)
     , mWrapT(LOCAL_GL_REPEAT)
     , mWrapR(LOCAL_GL_REPEAT)
     , mMinLod(-1000)
     , mMaxLod(1000)
@@ -48,161 +48,116 @@ WebGLSampler::GetParentObject() const
 }
 
 JSObject*
 WebGLSampler::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
 {
     return dom::WebGLSamplerBinding::Wrap(cx, this, givenProto);
 }
 
-static bool
-ValidateSamplerParameterParams(WebGLContext* webgl, const char* funcName, GLenum pname,
-                               GLint paramInt)
+void
+WebGLSampler::SamplerParameter1i(GLenum pname, GLint param)
 {
     switch (pname) {
     case LOCAL_GL_TEXTURE_MIN_FILTER:
-        switch (paramInt) {
-        case LOCAL_GL_NEAREST:
-        case LOCAL_GL_LINEAR:
-        case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
-        case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
-        case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
-        case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
-            return true;
-
-        default:
-            break;
-        }
+        mMinFilter = param;
         break;
 
     case LOCAL_GL_TEXTURE_MAG_FILTER:
-        switch (paramInt) {
-        case LOCAL_GL_NEAREST:
-        case LOCAL_GL_LINEAR:
-            return true;
-
-        default:
-            break;
-        }
+        mMagFilter = param;
         break;
 
     case LOCAL_GL_TEXTURE_WRAP_S:
+        mWrapS = param;
+        break;
+
     case LOCAL_GL_TEXTURE_WRAP_T:
-    case LOCAL_GL_TEXTURE_WRAP_R:
-        switch (paramInt) {
-        case LOCAL_GL_CLAMP_TO_EDGE:
-        case LOCAL_GL_REPEAT:
-        case LOCAL_GL_MIRRORED_REPEAT:
-            return true;
-
-        default:
-            break;
-        }
+        mWrapT = param;
         break;
 
-    case LOCAL_GL_TEXTURE_MIN_LOD:
-    case LOCAL_GL_TEXTURE_MAX_LOD:
-        return true;
+    case LOCAL_GL_TEXTURE_WRAP_R:
+        mWrapR = param;
+        break;
 
     case LOCAL_GL_TEXTURE_COMPARE_MODE:
-        switch (paramInt) {
-        case LOCAL_GL_NONE:
-        case LOCAL_GL_COMPARE_REF_TO_TEXTURE:
-            return true;
-
-        default:
-            break;
-        }
+        mCompareMode = param;
         break;
 
     case LOCAL_GL_TEXTURE_COMPARE_FUNC:
-        switch (paramInt) {
-        case LOCAL_GL_LEQUAL:
-        case LOCAL_GL_GEQUAL:
-        case LOCAL_GL_LESS:
-        case LOCAL_GL_GREATER:
-        case LOCAL_GL_EQUAL:
-        case LOCAL_GL_NOTEQUAL:
-        case LOCAL_GL_ALWAYS:
-        case LOCAL_GL_NEVER:
-            return true;
-
-        default:
-            break;
-        }
-        break;
-
-    default:
-        webgl->ErrorInvalidEnum("%s: invalid pname: %s", funcName,
-                                webgl->EnumName(pname));
-        return false;
-    }
-
-    webgl->ErrorInvalidEnum("%s: invalid param: %s", funcName, webgl->EnumName(paramInt));
-    return false;
-}
-
-void
-WebGLSampler::SamplerParameter(const char* funcName, GLenum pname, GLint paramInt)
-{
-    if (!ValidateSamplerParameterParams(mContext, funcName, pname, paramInt))
-        return;
-
-    switch (pname) {
-    case LOCAL_GL_TEXTURE_MIN_FILTER:
-        mMinFilter = paramInt;
-        break;
-
-    case LOCAL_GL_TEXTURE_MAG_FILTER:
-        mMagFilter = paramInt;
-        break;
-
-    case LOCAL_GL_TEXTURE_WRAP_S:
-        mWrapS = paramInt;
-        break;
-
-    case LOCAL_GL_TEXTURE_WRAP_T:
-        mWrapT = paramInt;
-        break;
-
-    case LOCAL_GL_TEXTURE_WRAP_R:
-        mWrapR = paramInt;
-        break;
-
-    case LOCAL_GL_TEXTURE_COMPARE_MODE:
-        mCompareMode = paramInt;
-        break;
-
-    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
-        mCompareFunc = paramInt;
+        mCompareFunc = param;
         break;
 
     case LOCAL_GL_TEXTURE_MIN_LOD:
-        mMinLod = paramInt;
+        mMinLod = param;
         break;
 
     case LOCAL_GL_TEXTURE_MAX_LOD:
-        mMaxLod = paramInt;
+        mMaxLod = param;
         break;
 
     default:
         MOZ_CRASH("GFX: Unhandled pname");
         break;
     }
 
     for (uint32_t i = 0; i < mContext->mBoundSamplers.Length(); ++i) {
         if (this == mContext->mBoundSamplers[i])
             mContext->InvalidateResolveCacheForTextureWithTexUnit(i);
     }
-
-    ////
-
-    mContext->gl->MakeCurrent();
-    mContext->gl->fSamplerParameteri(mGLName, pname, paramInt);
 }
 
-////
+void
+WebGLSampler::SamplerParameter1f(GLenum pname, GLfloat param)
+{
+    switch (pname) {
+    case LOCAL_GL_TEXTURE_MIN_LOD:
+        mMinLod = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_MAX_LOD:
+        mMaxLod = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_WRAP_S:
+        mWrapS = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_WRAP_T:
+        mWrapT = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_WRAP_R:
+        mWrapR = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_MAG_FILTER:
+        mMagFilter = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_MIN_FILTER:
+        mMinFilter = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_COMPARE_MODE:
+        mCompareMode = param;
+        break;
+
+    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
+        mCompareFunc = param;
+        break;
+
+    default:
+        MOZ_CRASH("GFX: Unhandled pname");
+        break;
+    }
+
+    for (uint32_t i = 0; i < mContext->mBoundSamplers.Length(); ++i) {
+        if (this == mContext->mBoundSamplers[i])
+            mContext->InvalidateResolveCacheForTextureWithTexUnit(i);
+    }
+}
+
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLSampler)
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLSampler, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLSampler, Release)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLSampler.h
+++ b/dom/canvas/WebGLSampler.h
@@ -12,33 +12,36 @@
 #include "WebGLStrongTypes.h"
 
 namespace mozilla {
 
 class WebGLSampler final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLSampler>
     , public LinkedListElement<WebGLSampler>
+    , public WebGLContextBoundObject
 {
     friend class WebGLContext2;
     friend class WebGLTexture;
 
 public:
     WebGLSampler(WebGLContext* webgl, GLuint sampler);
 
     const GLuint mGLName;
 
     void Delete();
     WebGLContext* GetParentObject() const;
 
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
-    void SamplerParameter(const char* funcName, GLenum pname, GLint paramInt);
+    void SamplerParameter1i(GLenum pname, GLint param);
+    void SamplerParameter1f(GLenum pname, GLfloat param);
 
 private:
+
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSampler)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLSampler)
 
     TexMinFilter mMinFilter;
     TexMagFilter mMagFilter;
     TexWrap mWrapS;
     TexWrap mWrapT;
     TexWrap mWrapR;
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -136,17 +136,17 @@ GetCompilationStatusAndLog(gl::GLContext
 static GLuint
 CreateShader(gl::GLContext* gl, GLenum type)
 {
     gl->MakeCurrent();
     return gl->fCreateShader(type);
 }
 
 WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(CreateShader(webgl->GL(), type))
     , mType(type)
     , mTranslationSuccessful(false)
     , mCompilationSuccessful(false)
 {
     mContext->mShaders.insertBack(this);
 }
 
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -23,16 +23,17 @@ namespace mozilla {
 namespace webgl {
 class ShaderValidator;
 } // namespace webgl
 
 class WebGLShader final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLShader>
     , public LinkedListElement<WebGLShader>
+    , public WebGLContextBoundObject
 {
     friend class WebGLContext;
     friend class WebGLProgram;
 
 public:
     WebGLShader(WebGLContext* webgl, GLenum type);
 
 protected:
--- a/dom/canvas/WebGLSync.cpp
+++ b/dom/canvas/WebGLSync.cpp
@@ -7,17 +7,17 @@
 
 #include "GLContext.h"
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "WebGLContext.h"
 
 namespace mozilla {
 
 WebGLSync::WebGLSync(WebGLContext* webgl, GLenum condition, GLbitfield flags)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
 {
    mContext->mSyncs.insertBack(this);
    mGLName = mContext->gl->fFenceSync(condition, flags);
 }
 
 WebGLSync::~WebGLSync()
 {
     DeleteOnce();
--- a/dom/canvas/WebGLSync.h
+++ b/dom/canvas/WebGLSync.h
@@ -11,16 +11,17 @@
 #include "WebGLObjectModel.h"
 
 namespace mozilla {
 
 class WebGLSync final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLSync>
     , public LinkedListElement<WebGLSync>
+    , public WebGLContextBoundObject
 {
     friend class WebGL2Context;
 
 public:
     WebGLSync(WebGLContext* webgl, GLenum condition, GLbitfield flags);
 
     void Delete();
     WebGLContext* GetParentObject() const;
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -122,17 +122,17 @@ WebGLTexture::ImageInfo::SetIsDataInitia
 ////////////////////////////////////////
 
 JSObject*
 WebGLTexture::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) {
     return dom::WebGLTextureBinding::Wrap(cx, this, givenProto);
 }
 
 WebGLTexture::WebGLTexture(WebGLContext* webgl, GLuint tex)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(tex)
     , mTarget(LOCAL_GL_NONE)
     , mFaceCount(0)
     , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
     , mMagFilter(LOCAL_GL_LINEAR)
     , mWrapS(LOCAL_GL_REPEAT)
     , mWrapT(LOCAL_GL_REPEAT)
     , mImmutable(false)
@@ -578,185 +578,31 @@ WebGLTexture::EnsureImageDataInitialized
     MOZ_ASSERT(imageInfo.IsDefined());
 
     if (imageInfo.IsDataInitialized())
         return true;
 
     return InitializeImageData(funcName, target, level);
 }
 
-static void
-ZeroANGLEDepthTexture(WebGLContext* webgl, GLuint tex,
-                      const webgl::FormatUsageInfo* usage, uint32_t width,
-                      uint32_t height)
-{
-    const auto& format = usage->format;
-    GLenum attachPoint = 0;
-    GLbitfield clearBits = 0;
-
-    if (format->d) {
-        attachPoint = LOCAL_GL_DEPTH_ATTACHMENT;
-        clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
-    }
-
-    if (format->s) {
-        attachPoint = (format->d ? LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
-                                 : LOCAL_GL_STENCIL_ATTACHMENT);
-        clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
-    }
-
-    MOZ_RELEASE_ASSERT(attachPoint && clearBits, "GFX: No bits cleared.");
-
-    ////
-    const auto& gl = webgl->gl;
-    MOZ_ASSERT(gl->IsCurrent());
-
-    gl::ScopedFramebuffer scopedFB(gl);
-    const gl::ScopedBindFramebuffer scopedBindFB(gl, scopedFB.FB());
-
-    gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachPoint, LOCAL_GL_TEXTURE_2D,
-                              tex, 0);
-
-    const auto& status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
-    MOZ_RELEASE_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
-
-    ////
-
-    const bool fakeNoAlpha = false;
-    webgl->ForceClearFramebufferWithDefaultValues(clearBits, fakeNoAlpha);
-}
-
-static bool
-ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex,
-                TexImageTarget target, uint32_t level,
-                const webgl::FormatUsageInfo* usage, uint32_t width, uint32_t height,
-                uint32_t depth)
-{
-    // This has two usecases:
-    // 1. Lazy zeroing of uninitialized textures:
-    //    a. Before draw, when FakeBlack isn't viable. (TexStorage + Draw*)
-    //    b. Before partial upload. (TexStorage + TexSubImage)
-    // 2. Zero subrects from out-of-bounds blits. (CopyTex(Sub)Image)
-
-    // We have no sympathy for any of these cases.
-
-    // "Doctor, it hurts when I do this!" "Well don't do that!"
-    webgl->GenerateWarning("%s: This operation requires zeroing texture data. This is"
-                           " slow.",
-                           funcName);
-
-    gl::GLContext* gl = webgl->GL();
-    gl->MakeCurrent();
-
-    GLenum scopeBindTarget;
-    switch (target.get()) {
-    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-        scopeBindTarget = LOCAL_GL_TEXTURE_CUBE_MAP;
-        break;
-    default:
-        scopeBindTarget = target.get();
-        break;
-    }
-    const gl::ScopedBindTexture scopeBindTexture(gl, tex, scopeBindTarget);
-    auto compression = usage->format->compression;
-    if (compression) {
-        auto sizedFormat = usage->format->sizedFormat;
-        MOZ_RELEASE_ASSERT(sizedFormat, "GFX: texture sized format not set");
-
-        const auto fnSizeInBlocks = [](CheckedUint32 pixels, uint8_t pixelsPerBlock) {
-            return RoundUpToMultipleOf(pixels, pixelsPerBlock) / pixelsPerBlock;
-        };
-
-        const auto widthBlocks = fnSizeInBlocks(width, compression->blockWidth);
-        const auto heightBlocks = fnSizeInBlocks(height, compression->blockHeight);
-
-        CheckedUint32 checkedByteCount = compression->bytesPerBlock;
-        checkedByteCount *= widthBlocks;
-        checkedByteCount *= heightBlocks;
-        checkedByteCount *= depth;
-
-        if (!checkedByteCount.isValid())
-            return false;
-
-        const size_t byteCount = checkedByteCount.value();
-
-        UniqueBuffer zeros = calloc(1, byteCount);
-        if (!zeros)
-            return false;
-
-        ScopedUnpackReset scopedReset(webgl);
-        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it
-                                                        // well.
-
-        const auto error = DoCompressedTexSubImage(gl, target.get(), level, 0, 0, 0,
-                                                   width, height, depth, sizedFormat,
-                                                   byteCount, zeros.get());
-        return !error;
-    }
-
-    const auto driverUnpackInfo = usage->idealUnpack;
-    MOZ_RELEASE_ASSERT(driverUnpackInfo, "GFX: ideal unpack info not set.");
-
-    if (webgl->IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
-        gl->IsANGLE() &&
-        usage->format->d)
-    {
-        // ANGLE_depth_texture does not allow uploads, so we have to clear.
-        // (Restriction because of D3D9)
-        MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D);
-        MOZ_ASSERT(level == 0);
-        ZeroANGLEDepthTexture(webgl, tex, usage, width, height);
-        return true;
-    }
-
-    const webgl::PackingInfo packing = driverUnpackInfo->ToPacking();
-
-    const auto bytesPerPixel = webgl::BytesPerPixel(packing);
-
-    CheckedUint32 checkedByteCount = bytesPerPixel;
-    checkedByteCount *= width;
-    checkedByteCount *= height;
-    checkedByteCount *= depth;
-
-    if (!checkedByteCount.isValid())
-        return false;
-
-    const size_t byteCount = checkedByteCount.value();
-
-    UniqueBuffer zeros = calloc(1, byteCount);
-    if (!zeros)
-        return false;
-
-    ScopedUnpackReset scopedReset(webgl);
-    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well.
-    const auto error = DoTexSubImage(gl, target, level, 0, 0, 0, width, height, depth,
-                                     packing, zeros.get());
-    return !error;
-}
-
 bool
 WebGLTexture::InitializeImageData(const char* funcName, TexImageTarget target,
                                   uint32_t level)
 {
     auto& imageInfo = ImageInfoAt(target, level);
     MOZ_ASSERT(imageInfo.IsDefined());
     MOZ_ASSERT(!imageInfo.IsDataInitialized());
 
     const auto& usage = imageInfo.mFormat;
     const auto& width = imageInfo.mWidth;
     const auto& height = imageInfo.mHeight;
     const auto& depth = imageInfo.mDepth;
 
-    if (!ZeroTextureData(mContext, funcName, mGLName, target, level, usage, width, height,
-                         depth))
+    if (!ZeroTextureData(mContext, funcName, mGLName, target, level, usage, 0, 0, 0,
+                         width, height, depth))
     {
         return false;
     }
 
     imageInfo.SetIsDataInitialized(true, this);
     return true;
 }
 
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -52,16 +52,17 @@ DoesTargetMatchDimensions(WebGLContext* 
 
 
 // NOTE: When this class is switched to new DOM bindings, update the (then-slow)
 // WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
 class WebGLTexture final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLTexture>
     , public LinkedListElement<WebGLTexture>
+    , public WebGLContextBoundObject
 {
     // Friends
     friend class WebGLContext;
     friend class WebGLFramebuffer;
 
     ////////////////////////////////////
     // Members
 public:
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -180,29 +180,24 @@ FromView(WebGLContext* webgl, const char
         }
     }
     return MakeUnique<webgl::TexUnpackBytes>(webgl, target, width, height, depth,
                                              isClientData, bytes, availByteCount);
 }
 
 static UniquePtr<webgl::TexUnpackBytes>
 FromPboOffset(WebGLContext* webgl, const char* funcName, TexImageTarget target,
-              uint32_t width, uint32_t height, uint32_t depth, WebGLsizeiptr pboOffset)
+              uint32_t width, uint32_t height, uint32_t depth, WebGLsizeiptr pboOffset,
+              size_t availBufferBytes)
 {
     if (pboOffset < 0) {
         webgl->ErrorInvalidValue("%s: offset cannot be negative.", funcName);
         return nullptr;
     }
 
-    const auto& buffer = webgl->ValidateBufferSelection(funcName,
-                                                        LOCAL_GL_PIXEL_UNPACK_BUFFER);
-    if (!buffer)
-        return nullptr;
-
-    size_t availBufferBytes = buffer->ByteLength();
     if (size_t(pboOffset) > availBufferBytes) {
         webgl->ErrorInvalidOperation("%s: Offset is passed end of buffer.", funcName);
         return nullptr;
     }
     availBufferBytes -= pboOffset;
 
     const bool isClientData = false;
     const auto ptr = (const uint8_t*)pboOffset;
@@ -366,22 +361,35 @@ WebGLContext::From(const char* funcName,
     uint32_t width, height, depth;
     if (!ValidateExtents(this, funcName, rawWidth, rawHeight, rawDepth, border, &width,
                          &height, &depth))
     {
         return nullptr;
     }
 
     if (src.mPboOffset) {
+        if (!mBoundPixelUnpackBuffer) {
+            ErrorInvalidOperation("%s: PACK_BUFFER must be non-null.", funcName);
+            return nullptr;
+        }
+
+        if (mBoundPixelUnpackBuffer->mNumActiveTFOs) {
+            ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+                                  " object.",
+                                  funcName);
+            return nullptr;
+        }
+
+        const auto& availBytes = mBoundPixelUnpackBuffer->ByteLength();
         return FromPboOffset(this, funcName, target, width, height, depth,
-                             *(src.mPboOffset));
+                             *(src.mPboOffset), availBytes);
     }
 
     if (mBoundPixelUnpackBuffer) {
-        ErrorInvalidOperation("%s: PIXEL_UNPACK_BUFFER must be null.", funcName);
+        ErrorInvalidOperation("%s: PACK_BUFFER must be null.", funcName);
         return nullptr;
     }
 
     if (src.mImageData) {
         return FromImageData(this, funcName, target, width, height, depth,
                              *(src.mImageData), scopedArr);
     }
 
@@ -1357,22 +1365,35 @@ WebGLContext::FromCompressed(const char*
     uint32_t width, height, depth;
     if (!ValidateExtents(this, funcName, rawWidth, rawHeight, rawDepth, border, &width,
                          &height, &depth))
     {
         return nullptr;
     }
 
     if (src.mPboOffset) {
+        if (!mBoundPixelUnpackBuffer) {
+            ErrorInvalidOperation("%s: PACK_BUFFER must be non-null.", funcName);
+            return nullptr;
+        }
+
+        if (mBoundPixelUnpackBuffer->mNumActiveTFOs) {
+            ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+                                  " object.",
+                                  funcName);
+            return nullptr;
+        }
+
+        const auto& availBytes = mBoundPixelUnpackBuffer->ByteLength();
         return FromPboOffset(this, funcName, target, width, height, depth,
-                             *(src.mPboOffset));
+                             *(src.mPboOffset), availBytes);
     }
 
     if (mBoundPixelUnpackBuffer) {
-        ErrorInvalidOperation("%s: PIXEL_UNPACK_BUFFER must be null.", funcName);
+        ErrorInvalidOperation("%s: PACK_BUFFER must be null.", funcName);
         return nullptr;
     }
 
     return FromView(this, funcName, target, width, height, depth, src.mView,
                     src.mViewElemOffset, src.mViewElemLengthOverride);
 }
 
 void
@@ -1915,100 +1936,16 @@ WebGLTexture::ValidateCopyTexImageForFee
                                             " READ_BUFFER-selected COLOR_ATTACHMENT%u.",
                                             funcName, attach->mAttachmentPoint);
             return false;
         }
     }
     return true;
 }
 
-static bool
-DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage,
-                    const WebGLTexture* tex, TexImageTarget target, GLint level,
-                    GLint xWithinSrc, GLint yWithinSrc,
-                    uint32_t srcTotalWidth, uint32_t srcTotalHeight,
-                    const webgl::FormatUsageInfo* srcUsage,
-                    GLint xOffset, GLint yOffset, GLint zOffset,
-                    uint32_t dstWidth, uint32_t dstHeight,
-                    const webgl::FormatUsageInfo* dstUsage)
-{
-    gl::GLContext* gl = webgl->gl;
-    gl->MakeCurrent();
-
-    ////
-
-    uint32_t readX, readY;
-    uint32_t writeX, writeY;
-    uint32_t rwWidth, rwHeight;
-    Intersect(srcTotalWidth, xWithinSrc, dstWidth, &readX, &writeX, &rwWidth);
-    Intersect(srcTotalHeight, yWithinSrc, dstHeight, &readY, &writeY, &rwHeight);
-
-    ////
-
-    GLenum error = 0;
-    do {
-        const auto& idealUnpack = dstUsage->idealUnpack;
-        if (!isSubImage) {
-            UniqueBuffer buffer;
-
-            if (rwWidth != dstWidth || rwHeight != dstHeight) {
-                const auto& pi = idealUnpack->ToPacking();
-                CheckedUint32 byteCount = BytesPerPixel(pi);
-                byteCount *= dstWidth;
-                byteCount *= dstHeight;
-
-                if (byteCount.isValid()) {
-                    buffer = calloc(1, byteCount.value());
-                }
-
-                if (!buffer.get()) {
-                    webgl->ErrorOutOfMemory("%s: Ran out of memory allocating zeros.",
-                                            funcName);
-                    return false;
-                }
-            }
-
-            const ScopedUnpackReset unpackReset(webgl);
-            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
-            error = DoTexImage(gl, target, level, idealUnpack, dstWidth, dstHeight, 1,
-                               buffer.get());
-            if (error)
-                break;
-        }
-
-        if (!rwWidth || !rwHeight) {
-            // There aren't any pixels to copy, so we're 'done'.
-            return true;
-        }
-
-        const auto& srcFormat = srcUsage->format;
-        ScopedCopyTexImageSource maybeSwizzle(webgl, funcName, srcTotalWidth,
-                                              srcTotalHeight, srcFormat, dstUsage);
-
-        const uint8_t zOffset = 0;
-        error = DoCopyTexSubImage(gl, target, level, writeX, writeY, zOffset, readX,
-                                  readY, rwWidth, rwHeight);
-        if (error)
-            break;
-
-        return true;
-    } while (false);
-
-    if (error == LOCAL_GL_OUT_OF_MEMORY) {
-        webgl->ErrorOutOfMemory("%s: Ran out of memory during texture copy.", funcName);
-        return false;
-    }
-
-    MOZ_RELEASE_ASSERT(false, "GFX: We should have caught all other errors.");
-    webgl->GenerateWarning("%s: Unexpected error during texture copy. Context lost.",
-                           funcName);
-    webgl->ForceLoseContext();
-    return false;
-}
-
 // There is no CopyTexImage3D.
 void
 WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
                              GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeight,
                              GLint border)
 {
     const char funcName[] = "copyTexImage2D";
 
@@ -2029,57 +1966,107 @@ WebGLTexture::CopyTexImage2D(TexImageTar
         return;
     }
     MOZ_ASSERT(imageInfo);
 
     ////////////////////////////////////
     // Get source info
 
     const webgl::FormatUsageInfo* srcUsage;
-    uint32_t srcTotalWidth;
-    uint32_t srcTotalHeight;
-    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcTotalWidth,
-                                        &srcTotalHeight))
-    {
+    uint32_t srcWidth;
+    uint32_t srcHeight;
+    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight))
         return;
-    }
+    auto srcFormat = srcUsage->format;
 
     if (!ValidateCopyTexImageForFeedback(funcName, level))
         return;
 
     ////////////////////////////////////
     // Check that source and dest info are compatible
 
-    const auto& srcFormat = srcUsage->format;
     const auto dstUsage = ValidateCopyDestUsage(funcName, mContext, srcFormat,
                                                 internalFormat);
     if (!dstUsage)
         return;
 
-    const auto& dstFormat = dstUsage->format;
+    const auto dstFormat = dstUsage->format;
+
     if (!ValidateTargetForFormat(funcName, mContext, target, dstFormat))
         return;
 
     if (!mContext->IsWebGL2() && dstFormat->d) {
         mContext->ErrorInvalidOperation("%s: Function may not be called with format %s.",
                                         funcName, dstFormat->name);
         return;
     }
 
     if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
         return;
 
     ////////////////////////////////////
     // Do the thing!
 
-    const bool isSubImage = false;
-    if (!DoCopyTexOrSubImage(mContext, funcName, isSubImage, this, target, level, x, y,
-                             srcTotalWidth, srcTotalHeight, srcUsage, 0, 0, 0, width,
-                             height, dstUsage))
-    {
+    gl::GLContext* gl = mContext->gl;
+    gl->MakeCurrent();
+
+    ScopedCopyTexImageSource maybeSwizzle(mContext, funcName, srcWidth, srcHeight,
+                                          srcFormat, dstUsage);
+
+    uint32_t readX, readY;
+    uint32_t writeX, writeY;
+    uint32_t rwWidth, rwHeight;
+    Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
+    Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
+
+    const auto& idealUnpack = dstUsage->idealUnpack;
+    const auto& driverInternalFormat = idealUnpack->internalFormat;
+
+    GLenum error = DoCopyTexImage2D(gl, target, level, driverInternalFormat, x, y, width,
+                                    height);
+    do {
+        if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height))
+            break;
+
+        if (error)
+            break;
+
+        // 1. Zero the texture data.
+        // 2. CopyTexSubImage the subrect.
+
+        const uint8_t zOffset = 0;
+        if (!ZeroTextureData(mContext, funcName, mGLName, target, level, dstUsage, 0, 0,
+                             zOffset, width, height, depth))
+        {
+            mContext->ErrorOutOfMemory("%s: Failed to zero texture data.", funcName);
+            MOZ_ASSERT(false, "Failed to zero texture data.");
+            return;
+        }
+
+        if (!rwWidth || !rwHeight) {
+            // There aren't any, so we're 'done'.
+            mContext->DummyReadFramebufferOperation(funcName);
+            return;
+        }
+
+        error = DoCopyTexSubImage(gl, target, level, writeX, writeY, zOffset, readX,
+                                  readY, rwWidth, rwHeight);
+    } while (false);
+
+    if (error == LOCAL_GL_OUT_OF_MEMORY) {
+        mContext->ErrorOutOfMemory("%s: Ran out of memory during texture copy.",
+                                   funcName);
+        return;
+    }
+    if (error) {
+        MOZ_RELEASE_ASSERT(false, "GFX: We should have caught all other errors.");
+        mContext->GenerateWarning("%s: Unexpected error during texture copy. Context"
+                                  " lost.",
+                                  funcName);
+        mContext->ForceLoseContext();
         return;
     }
 
     ////////////////////////////////////
     // Update our specification data.
 
     const bool isDataInitialized = true;
     const ImageInfo newImageInfo(dstUsage, width, height, depth, isDataInitialized);
@@ -2106,63 +2093,87 @@ WebGLTexture::CopyTexSubImage(const char
                                    width, height, depth, &imageInfo))
     {
         return;
     }
     MOZ_ASSERT(imageInfo);
 
     auto dstUsage = imageInfo->mFormat;
     MOZ_ASSERT(dstUsage);
+    auto dstFormat = dstUsage->format;
 
-    auto dstFormat = dstUsage->format;
     if (!mContext->IsWebGL2() && dstFormat->d) {
         mContext->ErrorInvalidOperation("%s: Function may not be called on a texture of"
                                         " format %s.",
                                         funcName, dstFormat->name);
         return;
     }
 
     ////////////////////////////////////
     // Get source info
 
     const webgl::FormatUsageInfo* srcUsage;
-    uint32_t srcTotalWidth;
-    uint32_t srcTotalHeight;
-    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcTotalWidth,
-                                        &srcTotalHeight))
-    {
+    uint32_t srcWidth;
+    uint32_t srcHeight;
+    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight))
         return;
-    }
+    auto srcFormat = srcUsage->format;
 
     if (!ValidateCopyTexImageForFeedback(funcName, level, zOffset))
         return;
 
     ////////////////////////////////////
     // Check that source and dest info are compatible
 
-    auto srcFormat = srcUsage->format;
     if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
         return;
 
     ////////////////////////////////////
     // Do the thing!
 
+    mContext->gl->MakeCurrent();
+
+    ScopedCopyTexImageSource maybeSwizzle(mContext, funcName, srcWidth, srcHeight,
+                                          srcFormat, dstUsage);
+
+    uint32_t readX, readY;
+    uint32_t writeX, writeY;
+    uint32_t rwWidth, rwHeight;
+    Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
+    Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
+
+    if (!rwWidth || !rwHeight) {
+        // There aren't any, so we're 'done'.
+        mContext->DummyReadFramebufferOperation(funcName);
+        return;
+    }
+
     bool uploadWillInitialize;
     if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
                                              yOffset, zOffset, width, height, depth,
                                              imageInfo, &uploadWillInitialize))
     {
         return;
     }
 
-    const bool isSubImage = true;
-    if (!DoCopyTexOrSubImage(mContext, funcName, isSubImage, this, target, level, x, y,
-                             srcTotalWidth, srcTotalHeight, srcUsage, xOffset, yOffset,
-                             zOffset, width, height, dstUsage))
-    {
+    GLenum error = DoCopyTexSubImage(mContext->gl, target, level, xOffset + writeX,
+                                     yOffset + writeY, zOffset, readX, readY, rwWidth,
+                                     rwHeight);
+
+    if (error == LOCAL_GL_OUT_OF_MEMORY) {
+        mContext->ErrorOutOfMemory("%s: Ran out of memory during texture copy.",
+                                   funcName);
+        return;
+    }
+    if (error) {
+        MOZ_RELEASE_ASSERT(false, "GFX: We should have caught all other errors.");
+        mContext->GenerateWarning("%s: Unexpected error during texture copy. Context"
+                                  " lost.",
+                                  funcName);
+        mContext->ForceLoseContext();
         return;
     }
 
     ////////////////////////////////////
     // Update our specification data?
 
     if (uploadWillInitialize) {
         imageInfo->SetIsDataInitialized(true, this);
--- a/dom/canvas/WebGLTransformFeedback.cpp
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -7,22 +7,21 @@
 
 #include "GLContext.h"
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "WebGL2Context.h"
 
 namespace mozilla {
 
 WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(tf)
     , mIndexedBindings(webgl->mGLMaxTransformFeedbackSeparateAttribs)
     , mIsPaused(false)
     , mIsActive(false)
-    , mBuffersForTF_Dirty(true)
 {
     mContext->mTransformFeedbacks.insertBack(this);
 }
 
 WebGLTransformFeedback::~WebGLTransformFeedback()
 {
     DeleteOnce();
 }
@@ -32,38 +31,16 @@ WebGLTransformFeedback::Delete()
 {
     if (mGLName) {
         mContext->MakeContextCurrent();
         mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
     }
     removeFrom(mContext->mTransformFeedbacks);
 }
 
-////
-
-const decltype(WebGLTransformFeedback::mBuffersForTF)&
-WebGLTransformFeedback::BuffersForTF() const
-{
-    // The generic bind point cannot incur undefined read/writes because otherwise it
-    // would be impossible to read back from this. The spec implies that readback from
-    // the TRANSFORM_FEEDBACK target is possible, just not simultaneously with being
-    // "bound or in use for transform feedback".
-    // Therefore, only the indexed bindings of the TFO count.
-    if (mBuffersForTF_Dirty) {
-        mBuffersForTF.clear();
-        for (const auto& cur : mIndexedBindings) {
-            if (cur.mBufferBinding) {
-                mBuffersForTF.insert(cur.mBufferBinding.get());
-            }
-        }
-        mBuffersForTF_Dirty = false;
-    }
-    return mBuffersForTF;
-}
-
 ////////////////////////////////////////
 
 void
 WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode)
 {
     const char funcName[] = "beginTransformFeedback";
 
     if (mIsActive)
@@ -125,16 +102,23 @@ WebGLTransformFeedback::BeginTransformFe
 
     mActive_Program = prog;
     mActive_PrimMode = primMode;
     mActive_VertPosition = 0;
     mActive_VertCapacity = minVertCapacity;
 
     ////
 
+    for (const auto& cur : mIndexedBindings) {
+        const auto& buffer = cur.mBufferBinding;
+        if (buffer) {
+            buffer->mNumActiveTFOs++;
+        }
+    }
+
     mActive_Program->mNumActiveTFOs++;
 }
 
 
 void
 WebGLTransformFeedback::EndTransformFeedback()
 {
     const char funcName[] = "endTransformFeedback";
@@ -150,16 +134,23 @@ WebGLTransformFeedback::EndTransformFeed
 
     ////
 
     mIsActive = false;
     mIsPaused = false;
 
     ////
 
+    for (const auto& cur : mIndexedBindings) {
+        const auto& buffer = cur.mBufferBinding;
+        if (buffer) {
+            buffer->mNumActiveTFOs--;
+        }
+    }
+
     mActive_Program->mNumActiveTFOs--;
 }
 
 void
 WebGLTransformFeedback::PauseTransformFeedback()
 {
     const char funcName[] = "pauseTransformFeedback";
 
--- a/dom/canvas/WebGLTransformFeedback.h
+++ b/dom/canvas/WebGLTransformFeedback.h
@@ -11,16 +11,17 @@
 #include "WebGLObjectModel.h"
 
 namespace mozilla {
 
 class WebGLTransformFeedback final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLTransformFeedback>
     , public LinkedListElement<WebGLTransformFeedback>
+    , public WebGLContextBoundObject
 {
     friend class ScopedDrawWithTransformFeedback;
     friend class WebGLContext;
     friend class WebGL2Context;
     friend class WebGLProgram;
 
 public:
     const GLuint mGLName;
@@ -31,37 +32,29 @@ private:
     bool mIsPaused;
     bool mIsActive;
     // Not in state tables:
     WebGLRefPtr<WebGLProgram> mActive_Program;
     MOZ_INIT_OUTSIDE_CTOR GLenum mActive_PrimMode;
     MOZ_INIT_OUTSIDE_CTOR size_t mActive_VertPosition;
     MOZ_INIT_OUTSIDE_CTOR size_t mActive_VertCapacity;
 
-    mutable bool mBuffersForTF_Dirty;
-    mutable std::set<const WebGLBuffer*> mBuffersForTF;
-
 public:
     WebGLTransformFeedback(WebGLContext* webgl, GLuint tf);
 private:
     ~WebGLTransformFeedback();
 
 public:
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTransformFeedback)
 
     void Delete();
     WebGLContext* GetParentObject() const { return mContext; }
     virtual JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
 
-    ////
-
-    void OnIndexedBindingsChanged() const { mBuffersForTF_Dirty = true; }
-    const decltype(mBuffersForTF)& BuffersForTF() const;
-
     // GL Funcs
     void BeginTransformFeedback(GLenum primMode);
     void EndTransformFeedback();
     void PauseTransformFeedback();
     void ResumeTransformFeedback();
 };
 
 } // namespace mozilla
--- a/dom/canvas/WebGLUniformLocation.cpp
+++ b/dom/canvas/WebGLUniformLocation.cpp
@@ -24,18 +24,17 @@ WebGLUniformLocation::WebGLUniformLocati
     , mLoc(loc)
     , mArrayIndex(arrayIndex)
 { }
 
 WebGLUniformLocation::~WebGLUniformLocation()
 { }
 
 bool
-WebGLUniformLocation::ValidateForProgram(const WebGLProgram* prog,
-                                         const char* funcName) const
+WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, const char* funcName) const
 {
     // Check the weak-pointer.
     if (!mLinkInfo) {
         mContext->ErrorInvalidOperation("%s: This uniform location is obsolete because"
                                         " its program has been successfully relinked.",
                                         funcName);
         return false;
     }
--- a/dom/canvas/WebGLUniformLocation.h
+++ b/dom/canvas/WebGLUniformLocation.h
@@ -47,17 +47,17 @@ public:
     const GLuint mLoc;
     const size_t mArrayIndex;
 
     //////
 
     WebGLUniformLocation(WebGLContext* webgl, const webgl::LinkedProgramInfo* linkInfo,
                          webgl::UniformInfo* info, GLuint loc, size_t arrayIndex);
 
-    bool ValidateForProgram(const WebGLProgram* prog, const char* funcName) const;
+    bool ValidateForProgram(WebGLProgram* prog, const char* funcName) const;
     bool ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
                              const char* funcName) const;
     bool ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
                              const char* funcName) const;
 
     JS::Value GetUniform(JSContext* js) const;
 
     // Needed for certain helper functions like ValidateObject.
--- a/dom/canvas/WebGLVertexArray.cpp
+++ b/dom/canvas/WebGLVertexArray.cpp
@@ -16,17 +16,17 @@ namespace mozilla {
 
 JSObject*
 WebGLVertexArray::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
 {
     return dom::WebGLVertexArrayObjectBinding::Wrap(cx, this, givenProto);
 }
 
 WebGLVertexArray::WebGLVertexArray(WebGLContext* webgl)
-    : WebGLRefCountedObject(webgl)
+    : WebGLContextBoundObject(webgl)
     , mGLName(0)
 {
     mContext->mVertexArrays.insertBack(this);
 }
 
 WebGLVertexArray*
 WebGLVertexArray::Create(WebGLContext* webgl)
 {
@@ -45,17 +45,17 @@ WebGLVertexArray::Delete()
     DeleteImpl();
 
     LinkedListElement<WebGLVertexArray>::removeFrom(mContext->mVertexArrays);
     mElementArrayBuffer = nullptr;
     mAttribs.Clear();
 }
 
 bool
-WebGLVertexArray::IsVertexArray() const
+WebGLVertexArray::IsVertexArray()
 {
     return IsVertexArrayImpl();
 }
 
 void
 WebGLVertexArray::EnsureAttrib(GLuint index)
 {
     MOZ_ASSERT(index < GLuint(mContext->mGLMaxVertexAttribs));
--- a/dom/canvas/WebGLVertexArray.h
+++ b/dom/canvas/WebGLVertexArray.h
@@ -18,16 +18,17 @@
 namespace mozilla {
 
 class WebGLVertexArrayFake;
 
 class WebGLVertexArray
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLVertexArray>
     , public LinkedListElement<WebGLVertexArray>
+    , public WebGLContextBoundObject
 {
 public:
     static WebGLVertexArray* Create(WebGLContext* webgl);
 
     void BindVertexArray() {
         // Bind to dummy value to signal that this vertex array has ever been
         // bound.
         BindVertexArrayImpl();
@@ -38,17 +39,17 @@ public:
         return index < mAttribs.Length();
     }
     bool IsAttribArrayEnabled(GLuint index) const {
         return HasAttrib(index) && mAttribs[index].mEnabled;
     }
 
     // Implement parent classes:
     void Delete();
-    bool IsVertexArray() const;
+    bool IsVertexArray();
 
     WebGLContext* GetParentObject() const {
         return mContext;
     }
 
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArray)
@@ -61,17 +62,17 @@ protected:
 
     virtual ~WebGLVertexArray() {
         MOZ_ASSERT(IsDeleted());
     }
 
     virtual void GenVertexArray() = 0;
     virtual void BindVertexArrayImpl() = 0;
     virtual void DeleteImpl() = 0;
-    virtual bool IsVertexArrayImpl() const = 0;
+    virtual bool IsVertexArrayImpl() = 0;
 
     GLuint mGLName;
     nsTArray<WebGLVertexAttribData> mAttribs;
     WebGLRefPtr<WebGLBuffer> mElementArrayBuffer;
 
     friend class WebGLContext;
     friend class WebGLVertexArrayFake;
     friend class WebGL2Context;
--- a/dom/canvas/WebGLVertexArrayFake.cpp
+++ b/dom/canvas/WebGLVertexArrayFake.cpp
@@ -57,14 +57,14 @@ WebGLVertexArrayFake::BindVertexArrayImp
 
 void
 WebGLVertexArrayFake::DeleteImpl()
 {
     mIsVAO = false;
 }
 
 bool
-WebGLVertexArrayFake::IsVertexArrayImpl() const
+WebGLVertexArrayFake::IsVertexArrayImpl()
 {
     return mIsVAO;
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLVertexArrayFake.h
+++ b/dom/canvas/WebGLVertexArrayFake.h
@@ -14,17 +14,17 @@ class WebGLVertexArrayFake final
     : public WebGLVertexArray
 {
     friend class WebGLVertexArray;
 
 protected:
     virtual void BindVertexArrayImpl() override;
     virtual void DeleteImpl() override;
     virtual void GenVertexArray() override {};
-    virtual bool IsVertexArrayImpl() const override;
+    virtual bool IsVertexArrayImpl() override;
 
 private:
     explicit WebGLVertexArrayFake(WebGLContext* webgl);
 
     ~WebGLVertexArrayFake() {
         DeleteOnce();
     }
 
--- a/dom/canvas/WebGLVertexArrayGL.cpp
+++ b/dom/canvas/WebGLVertexArrayGL.cpp
@@ -42,17 +42,17 @@ WebGLVertexArrayGL::BindVertexArrayImpl(
 
 void
 WebGLVertexArrayGL::GenVertexArray()
 {
     mContext->gl->fGenVertexArrays(1, &mGLName);
 }
 
 bool
-WebGLVertexArrayGL::IsVertexArrayImpl() const
+WebGLVertexArrayGL::IsVertexArrayImpl()
 {
     gl::GLContext* gl = mContext->gl;
     if (gl->WorkAroundDriverBugs())
     {
         return mIsVAO;
     }
 
     mContext->MakeContextCurrent();
--- a/dom/canvas/WebGLVertexArrayGL.h
+++ b/dom/canvas/WebGLVertexArrayGL.h
@@ -14,17 +14,17 @@ class WebGLVertexArrayGL
     : public WebGLVertexArray
 {
     friend class WebGLVertexArray;
 
 public:
     virtual void DeleteImpl() override;
     virtual void BindVertexArrayImpl() override;
     virtual void GenVertexArray() override;
-    virtual bool IsVertexArrayImpl() const override;
+    virtual bool IsVertexArrayImpl() override;
 
 protected:
     explicit WebGLVertexArrayGL(WebGLContext* webgl);
     ~WebGLVertexArrayGL();
 
     // Bug 1140459: Some drivers (including our test slaves!) don't
     // give reasonable answers for IsVertexArray, maybe others.
     //
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -4,17 +4,17 @@
 # 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/.
 
 TEST_DIRS += [
     'gtest'
 ]
 
 # Change the following line(s) to avoid bug 1081323 (clobber after changing a manifest):
-# * Adjust failure errata for webgl-conf.
+# * Implement ReadPixel with PBOs.
 
 MOCHITEST_MANIFESTS += [
     'test/crash/mochitest.ini',
     'test/crossorigin/mochitest.ini',
     'test/mochitest.ini',
     'test/webgl-conf/generated-mochitest.ini',
     'test/webgl-mochitest/mochitest.ini',
 ]
--- a/dom/canvas/test/webgl-conf/checkout/conformance/buffers/buffer-data-and-buffer-sub-data.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/buffers/buffer-data-and-buffer-sub-data.html
@@ -46,17 +46,17 @@ debug('Regression test for <a href="http
 var wtu = WebGLTestUtils;
 var gl = wtu.create3DContext();
 if (!gl) {
     testFailed("WebGL context does not exist");
 } else {
     testPassed("WebGL context exists");
 
     bufferDataTest();
-    bufferDataSizesTest();
+    bufferDataSizesTest();    
 
     bufferSubDataTest();
 }
 
 function bufferDataTest() {
     debug("");
     debug("Test bufferData without ArrayBuffer input");
 
@@ -158,29 +158,32 @@ function bufferSubDataTest() {
     gl.bufferSubData(gl.ARRAY_BUFFER, -10, new Float32Array(8));
     wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
         "calling bufferSubData with ArrayBufferView when offset is negative should generate INVALID_VALUE");
 
     gl.bufferSubData(gl.ARRAY_BUFFER, 10, array);
     wtu.glErrorShouldBe(gl, gl.NO_ERROR,
         "calling bufferSubData with ArrayBuffer should succeed");
 
+    gl.bufferSubData(gl.ARRAY_BUFFER, 10, null);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
+        "calling bufferSubData when BufferDataSource is null should generate INVALID_VALUE");
+
+    wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, "gl.bufferSubData(gl.ARRAY_BUFFER, 10, undefined)");
+
     gl.bufferSubData(gl.ARRAY_BUFFER, 10, new Float32Array(0));
     wtu.glErrorShouldBe(gl, gl.NO_ERROR,
         "calling bufferSubData with zero-sized ArrayBufferView should succeed");
 
     // Arguments that are not ArrayBuffers, null or undefined should throw a TypeError exception
     shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, 42);");
     shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, 5.5);");
     shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, \"5.5\");");
     shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, [4]);");
     shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, { mynumber: 42});");
-    shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 10, null)");
-    shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 10, undefined)");
-    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should generate no GL error");
 
     gl.bindBuffer(gl.ARRAY_BUFFER, null);
 }
 
 var successfullyParsed = true;
 </script>
 
 <script src="../../js/js-test-post.js"></script>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/context/context-lost.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/context/context-lost.html
@@ -80,19 +80,16 @@ function init()
     }
     extension = gl.getExtension(extensionName);
 
     // need an extension that exposes new API methods.
     OES_vertex_array_object = wtu.getExtensionWithKnownPrefixes(gl, "OES_vertex_array_object");
 
     canvas.addEventListener("webglcontextlost", testLostContext, false);
 
-    // We need to initialize |uniformLocation| before losing context.
-    // Otherwise gl.getUniform() when context is lost will throw.
-    uniformLocation = gl.getUniformLocation(program, "tex");
     loseContext();
 }
 
 function loseContext()
 {
     debug("");
     debug("Lose context");
 
@@ -241,24 +238,24 @@ function testLostContext()
         "gl.stencilFuncSeparate(gl.FRONT, gl.NEVER, 0, 0)",
         "gl.stencilMask(0)",
         "gl.stencilMaskSeparate(gl.FRONT, 0)",
         "gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP)",
         "gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.KEEP)",
         "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)",
         "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData)",
         "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)",
-        "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d)",
+        "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas)",
         "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video)",
         "gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)",
         "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)",
         "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)",
         "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData)",
         "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, image)",
-        "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d)",
+        "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, canvas)",
         "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, video)",
         "gl.uniform1f(uniformLocation, 0)",
         "gl.uniform1fv(uniformLocation, float32array)",
         "gl.uniform1fv(uniformLocation, [0])",
         "gl.uniform1i(uniformLocation, 0)",
         "gl.uniform1iv(uniformLocation, int32array)",
         "gl.uniform1iv(uniformLocation, [0])",
         "gl.uniform2f(uniformLocation, 0, 0)",
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html
@@ -121,33 +121,33 @@ function runSupportedTest(extensionEnabl
             testPassed("OES_vertex_array_object not listed as supported and getExtension failed -- this is legal");
         }
     }
 }
 
 function runBindingTestDisabled() {
     debug("");
     debug("Testing binding enum with extension disabled");
-
+    
     // Use the constant directly as we don't have the extension
     var VERTEX_ARRAY_BINDING_OES = 0x85B5;
-
+    
     gl.getParameter(VERTEX_ARRAY_BINDING_OES);
     wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "VERTEX_ARRAY_BINDING_OES should not be queryable if extension is disabled");
 }
 
 function runBindingTestEnabled() {
     debug("");
     debug("Testing binding enum with extension enabled");
-
+    
     shouldBe("ext.VERTEX_ARRAY_BINDING_OES", "0x85B5");
-
+    
     gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES);
     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "VERTEX_ARRAY_BINDING_OES query should succeed if extension is enabled");
-
+    
     // Default value is null
     if (gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) === null) {
         testPassed("Default value of VERTEX_ARRAY_BINDING_OES is null");
     } else {
         testFailed("Default value of VERTEX_ARRAY_BINDING_OES is not null");
     }
 
     debug("");
@@ -174,88 +174,88 @@ function runBindingTestEnabled() {
     ext.bindVertexArrayOES(null);
     shouldBeNull("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)");
     ext.deleteVertexArrayOES(vao1);
 }
 
 function runObjectTest() {
     debug("");
     debug("Testing object creation");
-
+    
     vao = ext.createVertexArrayOES();
     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "createVertexArrayOES should not set an error");
     shouldBeNonNull("vao");
-
+    
     // Expect false if never bound
     shouldBeFalse("ext.isVertexArrayOES(vao)");
     ext.bindVertexArrayOES(vao);
     shouldBeTrue("ext.isVertexArrayOES(vao)");
     ext.bindVertexArrayOES(null);
     shouldBeTrue("ext.isVertexArrayOES(vao)");
-
+    
     shouldBeFalse("ext.isVertexArrayOES(null)");
-
+    
     ext.deleteVertexArrayOES(vao);
     vao = null;
 }
 
 function runAttributeTests() {
     debug("");
     debug("Testing attributes work across bindings");
-
+    
     var states = [];
-
+    
     var attrCount = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
     for (var n = 0; n < attrCount; n++) {
         gl.bindBuffer(gl.ARRAY_BUFFER, null);
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
-
+        
         var state = {};
         states.push(state);
-
+        
         var vao = state.vao = ext.createVertexArrayOES();
         ext.bindVertexArrayOES(vao);
-
+        
         var enableArray = (n % 2 == 0);
         if (enableArray) {
             gl.enableVertexAttribArray(n);
         } else {
             gl.disableVertexAttribArray(n);
         }
-
+        
         if (enableArray) {
             var buffer = state.buffer = gl.createBuffer();
             gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
             gl.bufferData(gl.ARRAY_BUFFER, 1024, gl.STATIC_DRAW);
-
+            
             gl.vertexAttribPointer(n, 1 + n % 4, gl.FLOAT, true, n * 4, n * 4);
         }
-
+        
         if (enableArray) {
             var elbuffer = state.elbuffer = gl.createBuffer();
             gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elbuffer);
             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 1024, gl.STATIC_DRAW);
         }
-
+        
         ext.bindVertexArrayOES(null);
     }
-
+    
     var anyMismatch = false;
     for (var n = 0; n < attrCount; n++) {
         var state = states[n];
-
+        
         ext.bindVertexArrayOES(state.vao);
-
+        
         var shouldBeEnabled = (n % 2 == 0);
         var isEnabled = gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_ENABLED);
         if (shouldBeEnabled != isEnabled) {
             testFailed("VERTEX_ATTRIB_ARRAY_ENABLED not preserved");
             anyMismatch = true;
         }
-
+        
         var buffer = gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
         if (shouldBeEnabled) {
             if (buffer == state.buffer) {
                 // Matched
                 if ((gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_SIZE) == 1 + n % 4) &&
                     (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_TYPE) == gl.FLOAT) &&
                     (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED) == true) &&
                     (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_STRIDE) == n * 4) &&
@@ -271,17 +271,17 @@ function runAttributeTests() {
             }
         } else {
             // GL_CURRENT_VERTEX_ATTRIB is not preserved
             if (buffer) {
                 testFailed("VERTEX_ATTRIB_ARRAY_BUFFER_BINDING not preserved");
                 anyMismatch = true;
             }
         }
-
+        
         var elbuffer = gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING);
         if (shouldBeEnabled) {
             if (elbuffer == state.elbuffer) {
                 // Matched
             } else {
                 testFailed("ELEMENT_ARRAY_BUFFER_BINDING not preserved");
                 anyMismatch = true;
             }
@@ -293,81 +293,81 @@ function runAttributeTests() {
                 anyMismatch = true;
             }
         }
     }
     ext.bindVertexArrayOES(null);
     if (!anyMismatch) {
         testPassed("All attributes preserved across bindings");
     }
-
+    
     for (var n = 0; n < attrCount; n++) {
         var state = states[n];
         ext.deleteVertexArrayOES(state.vao);
     }
 }
 
 function runAttributeValueTests() {
     debug("");
     debug("Testing that attribute values are not attached to bindings");
-
+    
     var v;
     var vao0 = ext.createVertexArrayOES();
     var anyFailed = false;
-
+    
     ext.bindVertexArrayOES(null);
     gl.vertexAttrib4f(0, 0, 1, 2, 3);
-
+    
     v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
     if (!(v[0] == 0 && v[1] == 1 && v[2] == 2 && v[3] == 3)) {
         testFailed("Vertex attrib value not round-tripped?");
         anyFailed = true;
     }
-
+    
     ext.bindVertexArrayOES(vao0);
-
+    
     v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
     if (!(v[0] == 0 && v[1] == 1 && v[2] == 2 && v[3] == 3)) {
         testFailed("Vertex attrib value reset across bindings");
         anyFailed = true;
     }
-
+    
     gl.vertexAttrib4f(0, 4, 5, 6, 7);
     ext.bindVertexArrayOES(null);
-
+    
     v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
     if (!(v[0] == 4 && v[1] == 5 && v[2] == 6 && v[3] == 7)) {
         testFailed("Vertex attrib value bound to buffer");
         anyFailed = true;
     }
-
+    
     if (!anyFailed) {
         testPassed("Vertex attribute values are not attached to bindings")
     }
-
+    
     ext.bindVertexArrayOES(null);
     ext.deleteVertexArrayOES(vao0);
 }
 
 function runDrawTests() {
     debug("");
     debug("Testing draws with various VAO bindings");
-
+    
     canvas.width = 50; canvas.height = 50;
     gl.viewport(0, 0, canvas.width, canvas.height);
-
+    
     var vao0 = ext.createVertexArrayOES();
     var vao1 = ext.createVertexArrayOES();
     var vao2 = ext.createVertexArrayOES();
 
     var positionLocation = 0;
     var colorLocation = 1;
-
+    
     var program = wtu.setupSimpleVertexColorProgram(gl, positionLocation, colorLocation);
-
+    
     function setupQuad(s, colorsInArray) {
         var vertexObject = gl.createBuffer();
         gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
              1.0 * s,  1.0 * s, 0.0,
             -1.0 * s,  1.0 * s, 0.0,
             -1.0 * s, -1.0 * s, 0.0,
              1.0 * s,  1.0 * s, 0.0,
@@ -388,17 +388,17 @@ function runDrawTests() {
                 0.0, 0.0, 0.0, 1.0,
                 0.0, 0.0, 0.0, 1.0]), gl.STATIC_DRAW);
             gl.enableVertexAttribArray(colorLocation);
             gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);
         } else {
             gl.disableVertexAttribArray(colorLocation);
         }
     };
-
+    
     function verifyDiagonalPixels(s, expectedInside, drawDescription) {
         // Tests pixels along a diagonal running from the center of the canvas to the (0, 0) corner.
         // Values on the points list indicate relative position along this diagonal.
         var points = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
         for (var n = 0; n < points.length; n++) {
             var expected = points[n] <= s ? expectedInside : 255;
             var x = Math.round((1 - points[n]) * canvas.width / 2);
             var y = Math.round((1 - points[n]) * canvas.height / 2);
@@ -406,28 +406,28 @@ function runDrawTests() {
                 "Drawing " + drawDescription + " should pass", 2);
         }
     };
     function verifyDraw(drawDescription, s, colorsInArray) {
         wtu.clearAndDrawUnitQuad(gl);
         var expectedInside = colorsInArray ? 0 : 128;
         verifyDiagonalPixels(s, expectedInside, drawDescription);
     };
-
+    
     // Setup all bindings
     setupQuad(1, true);
     ext.bindVertexArrayOES(vao0);
     setupQuad(0.5, true);
     ext.bindVertexArrayOES(vao1);
     setupQuad(0.25, true);
     ext.bindVertexArrayOES(vao2);
     setupQuad(0.75, false);
 
     gl.vertexAttrib4f(colorLocation, 0.5, 0.5, 0.5, 1);
-
+    
     // Verify drawing
     ext.bindVertexArrayOES(null);
     verifyDraw("with the default VAO", 1, true);
     ext.bindVertexArrayOES(vao0);
     verifyDraw("with VAO #0", 0.5, true);
     ext.bindVertexArrayOES(vao1);
     verifyDraw("with VAO #1", 0.25, true);
     ext.bindVertexArrayOES(vao2);
@@ -619,41 +619,35 @@ function runBoundDeleteTests() {
 
     // delete the color buffers AND the position buffer, that are bound to the current VAO
     for (var ii = 0; ii < vaos.length; ++ii) {
         ext.bindVertexArrayOES(vaos[ii]);
 
         gl.deleteBuffer(colorBuffer);
         gl.deleteBuffer(positionBuffer);
 
-        var expectRetained = (ii != 0);
-        var shouldBeStr = (expectRetained ? "retained" : "cleared");
-
+        // The buffers should not be accessible at this point. Deleted objects that are bound
+        // in the current context undergo an automatic unbinding
         var boundPositionBuffer = gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
-        if (expectRetained != (boundPositionBuffer == positionBuffer)) {
-            testFailed("Position attrib stored buffer should be " + shouldBeStr + ".");
+        if(boundPositionBuffer == positionBuffer) {
+            testFailed("Position buffer should be automatically unbound when deleted");
         }
-
         var boundColorBuffer = gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
-        if (expectRetained != (boundColorBuffer == colorBuffer)) {
-            testFailed("Color attrib stored buffer should be " + shouldBeStr + ".");
+        if(boundColorBuffer == colorBuffer) {
+            testFailed("Color buffer should be automatically unbound when deleted");
         }
 
-        // If retained, everything should still work. If cleared, drawing should now fail.
         gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
-        var expectedError = (expectRetained ? gl.NO_ERROR : gl.INVALID_OPERATION);
-        wtu.glErrorShouldBe(gl, expectedError,
-                            "Draw call should " + (expectRetained ? "not " : "") + "fail.");
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Draw call should fail with unbound position and color buffers");
 
-        if (!gl.isBuffer(positionBuffer)) {
-            testFailed("Position buffer should count for isBuffer.");
-        }
-        if (!gl.isBuffer(colorBuffer)) {
-            testFailed("Color buffer should count for isBuffer.");
-        }
+        var isPositionBuffer = gl.isBuffer(positionBuffer);
+        var isColorBuffer    = gl.isBuffer(colorBuffer);
+
+        if(isPositionBuffer)  testFailed("Position buffer should no longer exist after last ref removed");
+        if(isColorBuffer)     testFailed("Color buffer should no longer exist after last ref removed");
     }
 }
 
 function runArrayBufferBindTests() {
     debug("");
     debug("Testing that buffer bindings on VAOs don't affect default VAO ARRAY_BUFFER binding.");
 
     ext.bindVertexArrayOES(null);
--- a/dom/canvas/test/webgl-conf/checkout/conformance/misc/error-reporting.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/error-reporting.html
@@ -46,29 +46,31 @@ var program = wtu.loadStandardProgram(co
 // of many synthetic GL errors. This test verifies the raising of certain
 // known real GL errors, and contains a few regression tests for bugs
 // discovered in the synthetic error generation and in the WebGL
 // implementation itself.
 
 wtu.glErrorShouldBe(context, context.NO_ERROR);
 
 debug("Testing getActiveAttrib");
-shouldThrow("context.getActiveAttrib(null, 2)");
-wtu.glErrorShouldBe(context, context.NO_ERROR);
+// Synthetic OpenGL error
+shouldBeNull("context.getActiveAttrib(null, 2)");
+wtu.glErrorShouldBe(context, context.INVALID_VALUE);
 // Error state should be clear by this point
 wtu.glErrorShouldBe(context, context.NO_ERROR);
 // Real OpenGL error
 shouldBeNull("context.getActiveAttrib(program, 2)");
 wtu.glErrorShouldBe(context, context.INVALID_VALUE);
 // Error state should be clear by this point
 wtu.glErrorShouldBe(context, context.NO_ERROR);
 
 debug("Testing getActiveUniform");
-shouldThrow("context.getActiveUniform(null, 0)");
-wtu.glErrorShouldBe(context, context.NO_ERROR);
+// Synthetic OpenGL error
+shouldBeNull("context.getActiveUniform(null, 0)");
+wtu.glErrorShouldBe(context, context.INVALID_VALUE);
 // Error state should be clear by this point
 wtu.glErrorShouldBe(context, context.NO_ERROR);
 // Real OpenGL error
 shouldBeNull("context.getActiveUniform(program, 50)");
 wtu.glErrorShouldBe(context, context.INVALID_VALUE);
 // Error state should be clear by this point
 wtu.glErrorShouldBe(context, context.NO_ERROR);
 
--- a/dom/canvas/test/webgl-conf/checkout/conformance/misc/null-object-behaviour.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/null-object-behaviour.html
@@ -44,47 +44,47 @@ description("Tests calling WebGL APIs wi
 
 var context = wtu.create3DContext();
 var program = wtu.loadStandardProgram(context);
 var shader = wtu.loadStandardVertexShader(context);
 var shouldGenerateGLError = wtu.shouldGenerateGLError;
 
 assertMsg(program != null, "Program Compiled");
 assertMsg(shader != null, "Shader Compiled");
-shouldThrow("context.compileShader(undefined)");
-shouldThrow("context.linkProgram(undefined)");
-shouldThrow("context.attachShader(undefined, undefined)");
-shouldThrow("context.attachShader(program, undefined)");
-shouldThrow("context.attachShader(undefined, shader)");
-shouldThrow("context.detachShader(program, undefined)");
-shouldThrow("context.detachShader(undefined, shader)");
-shouldThrow("context.shaderSource(undefined, undefined)");
-shouldThrow("context.shaderSource(undefined, 'foo')");
-shouldThrow("context.bindAttribLocation(undefined, 0, 'foo')");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.compileShader(undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.linkProgram(undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.attachShader(undefined, undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.attachShader(program, undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.attachShader(undefined, shader)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.detachShader(program, undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.detachShader(undefined, shader)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.shaderSource(undefined, undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.shaderSource(undefined, 'foo')");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.bindAttribLocation(undefined, 0, 'foo')");
 shouldThrow("context.bindBuffer(context.ARRAY_BUFFER, 0)");
 shouldThrow("context.bindFramebuffer(context.FRAMEBUFFER, 0)");
 shouldThrow("context.bindRenderbuffer(context.RENDERBUFFER, 0)");
 shouldThrow("context.bindTexture(context.TEXTURE_2D, 0)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.bindBuffer(context.ARRAY_BUFFER, null)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.bindFramebuffer(context.FRAMEBUFFER, null)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.bindRenderbuffer(context.RENDERBUFFER, null)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.bindTexture(context.TEXTURE_2D, null)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.bindBuffer(context.ARRAY_BUFFER, undefined)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.bindFramebuffer(context.FRAMEBUFFER, undefined)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.bindRenderbuffer(context.RENDERBUFFER, undefined)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.bindTexture(context.TEXTURE_2D, undefined)");
 shouldGenerateGLError(context, context.INVALID_OPERATION, "context.framebufferRenderbuffer(context.FRAMEBUFFER, context.DEPTH_ATTACHMENT, context.RENDERBUFFER, null)");
 shouldGenerateGLError(context, context.INVALID_OPERATION, "context.framebufferTexture2D(context.FRAMEBUFFER, context.COLOR_ATTACHMENT0, context.TEXTURE_2D, null, 0)");
-shouldThrow("context.getProgramParameter(undefined, 0)");
-shouldThrow("context.getProgramInfoLog(undefined, 0)");
-shouldThrow("context.getShaderParameter(undefined, 0)");
-shouldThrow("context.getShaderInfoLog(undefined, 0)");
-shouldThrow("context.getShaderSource(undefined)");
-shouldThrow("context.getUniform(undefined, null)");
-shouldThrow("context.getUniformLocation(undefined, 'foo')");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getProgramParameter(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getProgramInfoLog(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getShaderParameter(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getShaderInfoLog(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getShaderSource(undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getUniform(undefined, null)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getUniformLocation(undefined, 'foo')");
 
 debug("");
 debug("check with bindings");
 context.bindBuffer(context.ARRAY_BUFFER, context.createBuffer());
 context.bindTexture(context.TEXTURE_2D, context.createTexture());
 shouldGenerateGLError(context, context.NO_ERROR, "context.bufferData(context.ARRAY_BUFFER, 1, context.STATIC_DRAW)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.getBufferParameter(context.ARRAY_BUFFER, context.BUFFER_SIZE)");
 shouldGenerateGLError(context, context.NO_ERROR, "context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, 1, 1, 0, context.RGBA, context.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]))");
--- a/dom/canvas/test/webgl-conf/checkout/conformance/programs/get-active-test.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/programs/get-active-test.html
@@ -52,18 +52,18 @@ var program2 = wtu.loadProgramFromFile(c
 wtu.glErrorShouldBe(context, context.NO_ERROR);
 shouldBe("context.getActiveUniform(program, 0).name", "'u_modelViewProjMatrix'");
 shouldBe("context.getActiveUniform(program, 0).type", "context.FLOAT_MAT4");
 shouldBe("context.getActiveUniform(program, 0).size", "1");
 shouldBeNull("context.getActiveUniform(program, 1)");
 wtu.glErrorShouldBe(context, context.INVALID_VALUE);
 shouldBeNull("context.getActiveUniform(program, -1)");
 wtu.glErrorShouldBe(context, context.INVALID_VALUE);
-shouldThrow("context.getActiveUniform(null, 0)");
-wtu.glErrorShouldBe(context, context.NO_ERROR);
+shouldBeNull("context.getActiveUniform(null, 0)");
+wtu.glErrorShouldBe(context, context.INVALID_VALUE);
 
 // we don't know the order the attribs will appear.
 var info = [
   context.getActiveAttrib(program, 0),
   context.getActiveAttrib(program, 1)
 ];
 for (var ii = 0; ii < info.length; ++ii)
     shouldBeNonNull("info[ii]");
@@ -109,18 +109,18 @@ for (var ii = 0; ii < info2.length; ++ii
     shouldBe("info2[ii].type", "expected2[ii].type");
     shouldBe("info2[ii].size", "expected2[ii].size");
 }
 
 shouldBeNull("context.getActiveAttrib(program, 2)");
 wtu.glErrorShouldBe(context, context.INVALID_VALUE);
 shouldBeNull("context.getActiveAttrib(program, -1)");
 wtu.glErrorShouldBe(context, context.INVALID_VALUE);
-shouldThrow("context.getActiveAttrib(null, 0)");
-wtu.glErrorShouldBe(context, context.NO_ERROR);
+shouldBeNull("context.getActiveAttrib(null, 0)");
+wtu.glErrorShouldBe(context, context.INVALID_VALUE);
 
 wtu.glErrorShouldBe(context2, context.NO_ERROR);
 
 debug("Check trying to get attribs from different context");
 shouldBeNull("context2.getActiveAttrib(program, 0)");
 wtu.glErrorShouldBe(context2, context2.INVALID_OPERATION);
 shouldBeNull("context2.getActiveUniform(program, 0)");
 wtu.glErrorShouldBe(context2, context2.INVALID_OPERATION);
--- a/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/bound-buffer-size-change-test.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/bound-buffer-size-change-test.html
@@ -56,18 +56,16 @@ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_
 wtu.glErrorShouldBe(gl, gl.NO_ERROR,
     "Calling bindBufferBase on a buffer where no storage is allocated should succeed.");
 shouldBe("gl.getParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING)", "buffer1");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buffer1");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "0");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "0");
 
 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4, gl.STATIC_DRAW);
-wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
-
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buffer1");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "0");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "0");
 
 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
 
 debug("");
 debug("bindBufferBase with UNIFORM_BUFFER target");
@@ -94,23 +92,21 @@ gl.bindBufferRange(gl.TRANSFORM_FEEDBACK
 wtu.glErrorShouldBe(gl, gl.NO_ERROR,
     "Calling bindBufferRange on a buffer where no storage is allocated should succeed.");
 shouldBe("gl.getParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING)", "buffer3");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buffer3");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "8");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "4");
 
 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4, gl.STATIC_DRAW);
-wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buffer3");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "8");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "4");
 
 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 12, gl.STATIC_DRAW);
-wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buffer3");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "8");
 shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "4");
 
 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
 
 debug("");
 debug("bindBufferRange with UNIFORM_BUFFER target");
--- a/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/buffer-type-restrictions.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/buffer-type-restrictions.html
@@ -83,27 +83,26 @@ var testBindingFn = function(firstBindFn
   bind(secondBindFn, secondTarget, null);
 
   var messagePrefix = "Binding buffer first with " + firstBindFn + " to gl." + firstTargetStr
     + " and then binding buffer with " + secondBindFn + " to gl." + secondTargetStr + " should ";
   if (firstTarget == secondTarget || noElementArrayVsOtherDataConflicts(firstTarget, secondTarget))
     wtu.glErrorShouldBe(gl, gl.NO_ERROR, messagePrefix + "WORK");
   else
     wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, messagePrefix + "FAIL");
-  /*
+
   if ((firstTarget == gl.TRANSFORM_FEEDBACK_BUFFER && secondTarget != gl.TRANSFORM_FEEDBACK_BUFFER) ||
       (firstTarget != gl.TRANSFORM_FEEDBACK_BUFFER && secondTarget == gl.TRANSFORM_FEEDBACK_BUFFER)) {
     bind(firstBindFn, firstTarget, buffer);
     bind(secondBindFn, secondTarget, buffer);
 
     var message = "Binding buffer first with " + firstBindFn + " to gl." + firstTargetStr
     + " and simultaneously binding buffer with " + secondBindFn + " to gl." + secondTargetStr + " should FAIL";
     wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, message);
   }
-  */
 }
 
 var testBinding = function(firstTarget, secondTarget) {
   for (var i = 0; i < bindFunctions.length; i++)
     if (i == 0 || firstTarget == gl.UNIFORM_BUFFER || firstTarget == gl.TRANSFORM_FEEDBACK_BUFFER)
       for (var j = 0; j < bindFunctions.length; j++)
         if (j == 0 || secondTarget == gl.UNIFORM_BUFFER || secondTarget == gl.TRANSFORM_FEEDBACK_BUFFER)
           testBindingFn(bindFunctions[i], bindFunctions[j], firstTarget, secondTarget);
--- a/dom/canvas/test/webgl-conf/checkout/conformance2/context/constants-and-properties-2.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/context/constants-and-properties-2.html
@@ -41,131 +41,131 @@
 "use strict";
 description("This test ensures that the WebGL context has all the constants and (non-function) properties in the specification.");
 
 var constants = {
     /* ClearBufferMask */
 DEPTH_BUFFER_BIT               : 0x00000100,
 STENCIL_BUFFER_BIT             : 0x00000400,
 COLOR_BUFFER_BIT               : 0x00004000,
-
+    
     /* BeginMode */
 POINTS                         : 0x0000,
 LINES                          : 0x0001,
 LINE_LOOP                      : 0x0002,
 LINE_STRIP                     : 0x0003,
 TRIANGLES                      : 0x0004,
 TRIANGLE_STRIP                 : 0x0005,
 TRIANGLE_FAN                   : 0x0006,
-
+    
     /* AlphaFunction (not supported in ES20) */
     /*      NEVER */
     /*      LESS */
     /*      EQUAL */
     /*      LEQUAL */
     /*      GREATER */
     /*      NOTEQUAL */
     /*      GEQUAL */
     /*      ALWAYS */
-
+    
     /* BlendingFactorDest */
 ZERO                           : 0,
 ONE                            : 1,
 SRC_COLOR                      : 0x0300,
 ONE_MINUS_SRC_COLOR            : 0x0301,
 SRC_ALPHA                      : 0x0302,
 ONE_MINUS_SRC_ALPHA            : 0x0303,
 DST_ALPHA                      : 0x0304,
 ONE_MINUS_DST_ALPHA            : 0x0305,
-
+    
     /* BlendingFactorSrc */
     /*      ZERO */
     /*      ONE */
 DST_COLOR                      : 0x0306,
 ONE_MINUS_DST_COLOR            : 0x0307,
 SRC_ALPHA_SATURATE             : 0x0308,
     /*      SRC_ALPHA */
     /*      ONE_MINUS_SRC_ALPHA */
     /*      DST_ALPHA */
     /*      ONE_MINUS_DST_ALPHA */
-
+    
     /* BlendEquationSeparate */
 FUNC_ADD                       : 0x8006,
 BLEND_EQUATION                 : 0x8009,
 BLEND_EQUATION_RGB             : 0x8009,   /* same as BLEND_EQUATION */
 BLEND_EQUATION_ALPHA           : 0x883D,
-
+    
     /* BlendSubtract */
 FUNC_SUBTRACT                  : 0x800A,
 FUNC_REVERSE_SUBTRACT          : 0x800B,
-
+    
     /* Separate Blend Functions */
 BLEND_DST_RGB                  : 0x80C8,
 BLEND_SRC_RGB                  : 0x80C9,
 BLEND_DST_ALPHA                : 0x80CA,
 BLEND_SRC_ALPHA                : 0x80CB,
 CONSTANT_COLOR                 : 0x8001,
 ONE_MINUS_CONSTANT_COLOR       : 0x8002,
 CONSTANT_ALPHA                 : 0x8003,
 ONE_MINUS_CONSTANT_ALPHA       : 0x8004,
 BLEND_COLOR                    : 0x8005,
-
+    
     /* Buffer Objects */
 ARRAY_BUFFER                   : 0x8892,
 ELEMENT_ARRAY_BUFFER           : 0x8893,
 ARRAY_BUFFER_BINDING           : 0x8894,
 ELEMENT_ARRAY_BUFFER_BINDING   : 0x8895,
-
+    
 STREAM_DRAW                    : 0x88E0,
 STATIC_DRAW                    : 0x88E4,
 DYNAMIC_DRAW                   : 0x88E8,
-
+    
 BUFFER_SIZE                    : 0x8764,
 BUFFER_USAGE                   : 0x8765,
-
+    
 CURRENT_VERTEX_ATTRIB          : 0x8626,
-
+    
     /* CullFaceMode */
 FRONT                          : 0x0404,
 BACK                           : 0x0405,
 FRONT_AND_BACK                 : 0x0408,
-
+    
     /* DepthFunction */
     /*      NEVER */
     /*      LESS */
     /*      EQUAL */
     /*      LEQUAL */
     /*      GREATER */
     /*      NOTEQUAL */
     /*      GEQUAL */
     /*      ALWAYS */
-
+    
     /* EnableCap */
     /* TEXTURE_2D */
 CULL_FACE                      : 0x0B44,
 BLEND                          : 0x0BE2,
 DITHER                         : 0x0BD0,
 STENCIL_TEST                   : 0x0B90,
 DEPTH_TEST                     : 0x0B71,
 SCISSOR_TEST                   : 0x0C11,
 POLYGON_OFFSET_FILL            : 0x8037,
 SAMPLE_ALPHA_TO_COVERAGE       : 0x809E,
 SAMPLE_COVERAGE                : 0x80A0,
-
+    
     /* ErrorCode */
 NO_ERROR                       : 0,
 INVALID_ENUM                   : 0x0500,
 INVALID_VALUE                  : 0x0501,
 INVALID_OPERATION              : 0x0502,
 OUT_OF_MEMORY                  : 0x0505,
-
+    
     /* FrontFaceDirection */
 CW                             : 0x0900,
 CCW                            : 0x0901,
-
+    
     /* GetPName */
 LINE_WIDTH                     : 0x0B21,
 ALIASED_POINT_SIZE_RANGE       : 0x846D,
 ALIASED_LINE_WIDTH_RANGE       : 0x846E,
 CULL_FACE_MODE                 : 0x0B45,
 FRONT_FACE                     : 0x0B46,
 DEPTH_RANGE                    : 0x0B70,
 DEPTH_WRITEMASK                : 0x0B72,
@@ -205,56 +205,56 @@ STENCIL_BITS                   : 0x0D57,
 POLYGON_OFFSET_UNITS           : 0x2A00,
     /*      POLYGON_OFFSET_FILL */
 POLYGON_OFFSET_FACTOR          : 0x8038,
 TEXTURE_BINDING_2D             : 0x8069,
 SAMPLE_BUFFERS                 : 0x80A8,
 SAMPLES                        : 0x80A9,
 SAMPLE_COVERAGE_VALUE          : 0x80AA,
 SAMPLE_COVERAGE_INVERT         : 0x80AB,
-
+    
     /* GetTextureParameter */
     /*      TEXTURE_MAG_FILTER */
     /*      TEXTURE_MIN_FILTER */
     /*      TEXTURE_WRAP_S */
     /*      TEXTURE_WRAP_T */
-
+    
 COMPRESSED_TEXTURE_FORMATS     : 0x86A3,
-
+    
     /* HintMode */
 DONT_CARE                      : 0x1100,
 FASTEST                        : 0x1101,
 NICEST                         : 0x1102,
-
+    
     /* HintTarget */
 GENERATE_MIPMAP_HINT            : 0x8192,
-
+    
     /* DataType */
 BYTE                           : 0x1400,
 UNSIGNED_BYTE                  : 0x1401,
 SHORT                          : 0x1402,
 UNSIGNED_SHORT                 : 0x1403,
 INT                            : 0x1404,
 UNSIGNED_INT                   : 0x1405,
 FLOAT                          : 0x1406,
-
+    
     /* PixelFormat */
 DEPTH_COMPONENT                : 0x1902,
 ALPHA                          : 0x1906,
 RGB                            : 0x1907,
 RGBA                           : 0x1908,
 LUMINANCE                      : 0x1909,
 LUMINANCE_ALPHA                : 0x190A,
-
+    
     /* PixelType */
     /*      UNSIGNED_BYTE */
 UNSIGNED_SHORT_4_4_4_4         : 0x8033,
 UNSIGNED_SHORT_5_5_5_1         : 0x8034,
 UNSIGNED_SHORT_5_6_5           : 0x8363,
-
+    
     /* Shaders */
 FRAGMENT_SHADER                  : 0x8B30,
 VERTEX_SHADER                    : 0x8B31,
 MAX_VERTEX_ATTRIBS               : 0x8869,
 MAX_VERTEX_UNIFORM_VECTORS       : 0x8DFB,
 MAX_VARYING_VECTORS              : 0x8DFC,
 MAX_COMBINED_TEXTURE_IMAGE_UNITS : 0x8B4D,
 MAX_VERTEX_TEXTURE_IMAGE_UNITS   : 0x8B4C,
@@ -264,74 +264,74 @@ SHADER_TYPE                      : 0x8B4
 DELETE_STATUS                    : 0x8B80,
 LINK_STATUS                      : 0x8B82,
 VALIDATE_STATUS                  : 0x8B83,
 ATTACHED_SHADERS                 : 0x8B85,
 ACTIVE_UNIFORMS                  : 0x8B86,
 ACTIVE_ATTRIBUTES                : 0x8B89,
 SHADING_LANGUAGE_VERSION         : 0x8B8C,
 CURRENT_PROGRAM                  : 0x8B8D,
-
+    
     /* StencilFunction */
 NEVER                          : 0x0200,
 LESS                           : 0x0201,
 EQUAL                          : 0x0202,
 LEQUAL                         : 0x0203,
 GREATER                        : 0x0204,
 NOTEQUAL                       : 0x0205,
 GEQUAL                         : 0x0206,
 ALWAYS                         : 0x0207,
-
+    
     /* StencilOp */
     /*      ZERO */
 KEEP                           : 0x1E00,
 REPLACE                        : 0x1E01,
 INCR                           : 0x1E02,
 DECR                           : 0x1E03,
 INVERT                         : 0x150A,
 INCR_WRAP                      : 0x8507,
 DECR_WRAP                      : 0x8508,
-
+    
     /* StringName */
 VENDOR                         : 0x1F00,
 RENDERER                       : 0x1F01,
 VERSION                        : 0x1F02,
-
+    
     /* TextureMagFilter */
 NEAREST                        : 0x2600,
 LINEAR                         : 0x2601,
-
+    
     /* TextureMinFilter */
     /*      NEAREST */
     /*      LINEAR */
 NEAREST_MIPMAP_NEAREST         : 0x2700,
 LINEAR_MIPMAP_NEAREST          : 0x2701,
 NEAREST_MIPMAP_LINEAR          : 0x2702,
 LINEAR_MIPMAP_LINEAR           : 0x2703,
-
+    
     /* TextureParameterName */
 TEXTURE_MAG_FILTER             : 0x2800,
 TEXTURE_MIN_FILTER             : 0x2801,
 TEXTURE_WRAP_S                 : 0x2802,
 TEXTURE_WRAP_T                 : 0x2803,
-
+    
     /* TextureTarget */
 TEXTURE_2D                     : 0x0DE1,
 TEXTURE                        : 0x1702,
-
+    
 TEXTURE_CUBE_MAP               : 0x8513,
 TEXTURE_BINDING_CUBE_MAP       : 0x8514,
 TEXTURE_CUBE_MAP_POSITIVE_X    : 0x8515,
 TEXTURE_CUBE_MAP_NEGATIVE_X    : 0x8516,
 TEXTURE_CUBE_MAP_POSITIVE_Y    : 0x8517,
 TEXTURE_CUBE_MAP_NEGATIVE_Y    : 0x8518,
 TEXTURE_CUBE_MAP_POSITIVE_Z    : 0x8519,
 TEXTURE_CUBE_MAP_NEGATIVE_Z    : 0x851A,
 MAX_CUBE_MAP_TEXTURE_SIZE      : 0x851C,
-
+    
     /* TextureUnit */
 TEXTURE0                       : 0x84C0,
 TEXTURE1                       : 0x84C1,
 TEXTURE2                       : 0x84C2,
 TEXTURE3                       : 0x84C3,
 TEXTURE4                       : 0x84C4,
 TEXTURE5                       : 0x84C5,
 TEXTURE6                       : 0x84C6,
@@ -356,103 +356,103 @@ TEXTURE24                      : 0x84D8,
 TEXTURE25                      : 0x84D9,
 TEXTURE26                      : 0x84DA,
 TEXTURE27                      : 0x84DB,
 TEXTURE28                      : 0x84DC,
 TEXTURE29                      : 0x84DD,
 TEXTURE30                      : 0x84DE,
 TEXTURE31                      : 0x84DF,
 ACTIVE_TEXTURE                 : 0x84E0,
-
+    
     /* TextureWrapMode */
 REPEAT                         : 0x2901,
 CLAMP_TO_EDGE                  : 0x812F,
 MIRRORED_REPEAT                : 0x8370,
-
+    
     /* Uniform Types */
 FLOAT_VEC2                     : 0x8B50,
 FLOAT_VEC3                     : 0x8B51,
 FLOAT_VEC4                     : 0x8B52,
 INT_VEC2                       : 0x8B53,
 INT_VEC3                       : 0x8B54,
 INT_VEC4                       : 0x8B55,
 BOOL                           : 0x8B56,
 BOOL_VEC2                      : 0x8B57,
 BOOL_VEC3                      : 0x8B58,
 BOOL_VEC4                      : 0x8B59,
 FLOAT_MAT2                     : 0x8B5A,
 FLOAT_MAT3                     : 0x8B5B,
 FLOAT_MAT4                     : 0x8B5C,
 SAMPLER_2D                     : 0x8B5E,
 SAMPLER_CUBE                   : 0x8B60,
-
+    
     /* Vertex Arrays */
 VERTEX_ATTRIB_ARRAY_ENABLED        : 0x8622,
 VERTEX_ATTRIB_ARRAY_SIZE           : 0x8623,
 VERTEX_ATTRIB_ARRAY_STRIDE         : 0x8624,
 VERTEX_ATTRIB_ARRAY_TYPE           : 0x8625,
 VERTEX_ATTRIB_ARRAY_NORMALIZED     : 0x886A,
 VERTEX_ATTRIB_ARRAY_POINTER        : 0x8645,
 VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : 0x889F,
-
+    
     /* Shader Source */
 COMPILE_STATUS                 : 0x8B81,
-
+    
     /* Shader Precision-Specified Types */
 LOW_FLOAT                      : 0x8DF0,
 MEDIUM_FLOAT                   : 0x8DF1,
 HIGH_FLOAT                     : 0x8DF2,
 LOW_INT                        : 0x8DF3,
 MEDIUM_INT                     : 0x8DF4,
 HIGH_INT                       : 0x8DF5,
-
+    
     /* Framebuffer Object. */
 FRAMEBUFFER                    : 0x8D40,
 RENDERBUFFER                   : 0x8D41,
-
+    
 RGBA4                          : 0x8056,
 RGB5_A1                        : 0x8057,
 RGB565                         : 0x8D62,
 DEPTH_COMPONENT16              : 0x81A5,
 STENCIL_INDEX                  : 0x1901,
 STENCIL_INDEX8                 : 0x8D48,
 DEPTH_STENCIL                  : 0x84F9,
-
+    
 RENDERBUFFER_WIDTH             : 0x8D42,
 RENDERBUFFER_HEIGHT            : 0x8D43,
 RENDERBUFFER_INTERNAL_FORMAT   : 0x8D44,
 RENDERBUFFER_RED_SIZE          : 0x8D50,
 RENDERBUFFER_GREEN_SIZE        : 0x8D51,
 RENDERBUFFER_BLUE_SIZE         : 0x8D52,
 RENDERBUFFER_ALPHA_SIZE        : 0x8D53,
 RENDERBUFFER_DEPTH_SIZE        : 0x8D54,
 RENDERBUFFER_STENCIL_SIZE      : 0x8D55,
-
+    
 FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE           : 0x8CD0,
 FRAMEBUFFER_ATTACHMENT_OBJECT_NAME           : 0x8CD1,
 FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL         : 0x8CD2,
 FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE : 0x8CD3,
-
+    
 COLOR_ATTACHMENT0              : 0x8CE0,
 DEPTH_ATTACHMENT               : 0x8D00,
 STENCIL_ATTACHMENT             : 0x8D20,
 DEPTH_STENCIL_ATTACHMENT       : 0x821A,
-
+    
 NONE                           : 0,
-
+    
 FRAMEBUFFER_COMPLETE                      : 0x8CD5,
 FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : 0x8CD6,
 FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : 0x8CD7,
 FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : 0x8CD9,
 FRAMEBUFFER_UNSUPPORTED                   : 0x8CDD,
-
+  
 FRAMEBUFFER_BINDING            : 0x8CA6,
 RENDERBUFFER_BINDING           : 0x8CA7,
 MAX_RENDERBUFFER_SIZE          : 0x84E8,
-
+    
 INVALID_FRAMEBUFFER_OPERATION  : 0x0506,
 
 IMPLEMENTATION_COLOR_READ_TYPE : 0x8B9A,
 IMPLEMENTATION_COLOR_READ_FORMAT : 0x8B9B,
 
 /* WebGL-specific enums */
 UNPACK_FLIP_Y_WEBGL                : 0x9240,
 UNPACK_PREMULTIPLY_ALPHA_WEBGL     : 0x9241,
@@ -710,23 +710,36 @@ CONDITION_SATISFIED : 0x911C,
 WAIT_FAILED : 0x911D,
 SYNC_FLUSH_COMMANDS_BIT : 0x00000001,
 TIMEOUT_IGNORED : -1,
 VERTEX_ATTRIB_ARRAY_DIVISOR : 0x88FE,
 ANY_SAMPLES_PASSED : 0x8C2F,
 ANY_SAMPLES_PASSED_CONSERVATIVE : 0x8D6A,
 SAMPLER_BINDING : 0x8919,
 RGB10_A2UI : 0x906F,
+GREEN : 0x1904,
+BLUE : 0x1905,
 INT_2_10_10_10_REV : 0x8D9F,
 TRANSFORM_FEEDBACK : 0x8E22,
 TRANSFORM_FEEDBACK_PAUSED : 0x8E23,
 TRANSFORM_FEEDBACK_ACTIVE : 0x8E24,
 TRANSFORM_FEEDBACK_BINDING : 0x8E25,
+COMPRESSED_R11_EAC : 0x9270,
+COMPRESSED_SIGNED_R11_EAC : 0x9271,
+COMPRESSED_RG11_EAC : 0x9272,
+COMPRESSED_SIGNED_RG11_EAC : 0x9273,
+COMPRESSED_RGB8_ETC2 : 0x9274,
+COMPRESSED_SRGB8_ETC2 : 0x9275,
+COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9276,
+COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9277,
+COMPRESSED_RGBA8_ETC2_EAC : 0x9278,
+COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : 0x9279,
 TEXTURE_IMMUTABLE_FORMAT : 0x912F,
 MAX_ELEMENT_INDEX : 0x8D6B,
+NUM_SAMPLE_COUNTS : 0x9380,
 TEXTURE_IMMUTABLE_LEVELS : 0x82DF,
 
 /* WebGL-specific enums */
 MAX_CLIENT_WAIT_TIMEOUT_WEBGL: 0x9247
 };
 
 // Other non-function properties on the WebGL object
 var otherProperties = {
--- a/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/invalidate-framebuffer.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/invalidate-framebuffer.html
@@ -80,43 +80,43 @@ if (!gl) {
   invalidateIncompleteAttachment(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT);
   gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[0], gl.DEPTH_COMPONENT16, canvas.width, canvas.height);
   gl.clear(gl.DEPTH_BUFFER_BIT);
   wtu.glErrorShouldBe(gl, gl.NO_ERROR,
       "should be no errors after attaching a renderbuffer to fbo.");
 
   // in real world case, after some drawing, we can invalidate the depth attachment of the bound fbo
   invalidation(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.STENCIL_ATTACHMENT);
-
-  // set up framebuffer to blit to and read back from
+ 
+  // set up framebuffer to blit to and read back from 
   var fb = gl.createFramebuffer();
   gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
   var buffer = gl.createRenderbuffer();
   gl.bindRenderbuffer(gl.RENDERBUFFER, buffer);
   gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, canvas.width, canvas.height);
   gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, buffer);
   gl.clear(gl.COLOR_BUFFER_BIT);
   wtu.glErrorShouldBe(gl, gl.NO_ERROR,
       "should be no errors after attaching a renderbuffer to fbo.");
 
   gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb_m);
   gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb);
   gl.blitFramebuffer(0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
   wtu.glErrorShouldBe(gl, gl.NO_ERROR,
       "should be no errors after bliting framebuffer.");
-
+ 
   // invalidate the multi-sampled color attachment of the bound read framebuffer after blitFramebuffer.
   invalidation(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.DEPTH_ATTACHMENT);
 
   var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
   gl.invalidateSubFramebuffer(gl.READ_FRAMEBUFFER, [gl.COLOR_ATTACHMENT0 + maxColorAttachments], 5, 5, 10, 10);
-  wtu.glErrorShouldBe(gl, [gl.INVALID_OPERATION, gl.INVALID_ENUM],
+  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION,
       "calling invalidateSubFramebuffer to invalidate a COLOR_ATTACHMENT that exceeds MAX_COLOR_ATTACHMENT should generate INVALID_OPERATION.");
   gl.invalidateFramebuffer(gl.READ_FRAMEBUFFER, [gl.COLOR_ATTACHMENT0 + maxColorAttachments]);
-  wtu.glErrorShouldBe(gl, [gl.INVALID_OPERATION, gl.INVALID_ENUM],
+  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION,
       "calling invalidateFramebuffer to invalidate a COLOR_ATTACHMENT that exceeds MAX_COLOR_ATTACHMENT should generate INVALID_OPERATION.");
 
   // invalidate the default framebuffer
   gl.bindFramebuffer(gl.FRAMEBUFFER, null);
   invalidation(gl.FRAMEBUFFER, gl.DEPTH, gl.STENCIL);
 
   gl.deleteFramebuffer(fb_m);
   gl.deleteRenderbuffer(rb_m);
--- a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js
@@ -310,18 +310,18 @@ var standardFrag = wtu.loadStandardFragm
 var standardProgram = gl.createProgram();
 gl.attachShader(standardProgram, standardVert);
 gl.attachShader(standardProgram, standardFrag);
 gl.linkProgram(standardProgram);
 var shaders = gl.getAttachedShaders(standardProgram);
 shouldBe('shaders.length', '2');
 shouldBeTrue('shaders[0] == standardVert && shaders[1] == standardFrag || shaders[1] == standardVert && shaders[0] == standardFrag');
 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
-shouldThrow('gl.getAttachedShaders(null)');
-wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+gl.getAttachedShaders(null);
+wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
 shouldThrow('gl.getAttachedShaders(standardVert)');
 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
 
 debug("");
 debug("Test getProgramParameter");
 shouldBe('gl.getProgramParameter(standardProgram, gl.DELETE_STATUS)', 'false');
 shouldBe('gl.getProgramParameter(standardProgram, gl.LINK_STATUS)', 'true');
 shouldBe('typeof gl.getProgramParameter(standardProgram, gl.VALIDATE_STATUS)', '"boolean"');
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -6023,16 +6023,17 @@ fail-if = (os == 'android')
 [generated/test_conformance__extensions__oes-texture-half-float-with-video.html]
 skip-if = (os == 'win' && os_version == '6.1')
 fail-if = (os == 'android')
 [generated/test_conformance__extensions__oes-texture-half-float.html]
 fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
 [generated/test_conformance__extensions__oes-vertex-array-object-bufferData.html]
 [generated/test_conformance__extensions__oes-vertex-array-object.html]
 skip-if = (os == 'mac' && os_version == '10.6')
+fail-if = (os == 'win') || (os == 'mac') || (os == 'android') || (os == 'linux')
 [generated/test_conformance__extensions__webgl-compressed-texture-atc.html]
 [generated/test_conformance__extensions__webgl-compressed-texture-pvrtc.html]
 [generated/test_conformance__extensions__webgl-compressed-texture-s3tc.html]
 [generated/test_conformance__extensions__webgl-compressed-texture-size-limit.html]
 skip-if = (os == 'win')
 [generated/test_conformance__extensions__webgl-debug-renderer-info.html]
 [generated/test_conformance__extensions__webgl-debug-shaders.html]
 [generated/test_conformance__extensions__webgl-depth-texture.html]
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -124,16 +124,17 @@ skip-if = (os == 'android') || (os == 'b
 fail-if = (os == 'android')
 # void mozilla::gl::GLContext::fDetachShader(GLuint, GLuint): Generated unexpected GL_INVALID_VALUE error. (0x0501)
 skip-if = (os == 'android' && debug)
 
 [generated/test_conformance__extensions__oes-vertex-array-object.html]
 # 10.6 crash:
 # PROCESS-CRASH | dom/canvas/test/webgl-conf/generated/test_conformance__extensions__oes-vertex-array-object.html | application crashed [@ gleRunVertexSubmitImmediate + 0xf24]
 skip-if = (os == 'mac' && os_version == '10.6')
+fail-if = (os == 'win') || (os == 'mac') || (os == 'android') || (os == 'linux')
 [generated/test_conformance__textures__misc__texture-size.html]
 # application crashed [@ mozilla::gl::GLContext::AfterGLCall]
 skip-if = (os == 'android') || (os == 'win')
 
 [generated/test_2_conformance__textures__misc__cube-incomplete-fbo.html]
 fail-if = (os == 'mac')
 skip-if = (os == 'win')
 [generated/test_2_conformance__extensions__webgl-compressed-texture-s3tc.html]
--- a/dom/canvas/test/webgl-mochitest/test_sab_with_webgl.html
+++ b/dom/canvas/test/webgl-mochitest/test_sab_with_webgl.html
@@ -94,19 +94,19 @@ function TestScreenColor(gl, r, g, b, a)
   gl.useProgram(prog);
 
   // Test gl.bufferData(), gl.bufferSubData() and gl.readPixels() APIs with SAB as input.
   var arr = new SharedArrayBuffer(8*4);
   var view = new Float32Array(arr);
   view.set(new Float32Array([-1, -1, 1, -1, -1,  1, 1,  1]));
   var vb = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, vb);
-  gl.bufferData(gl.ARRAY_BUFFER, view, gl.STATIC_DRAW);
+  gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
   ok(gl.getError() == 0, 'bufferData with SAB as input parameter works ok.');
-  gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
+  gl.bufferSubData(gl.ARRAY_BUFFER, 0, arr);
   ok(gl.getError() == 0, 'bufferSubData with SAB as input parameter works ok.');
   gl.enableVertexAttribArray(0);
   gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
   gl.clearColor(0, 0, 0, 1.0);
   gl.clear(gl.COLOR_BUFFER_BIT);
   gl.uniform4f(prog.uFragColor, 0.2, 0.4, 0.6, 1.0);
   gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
   var arr = new Uint8Array(4);
@@ -148,17 +148,17 @@ function TestScreenColor(gl, r, g, b, a)
     return;
   }
 
   var arr = new SharedArrayBuffer(8*4);
   var view = new Float32Array(arr);
   view.set(new Float32Array([-1, -1, 1, -1, -1,  1, 1,  1]));
   var vb = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, vb);
-  gl.bufferData(gl.ARRAY_BUFFER, view, gl.STATIC_DRAW);
+  gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
 
   var arr2 = new SharedArrayBuffer(8*4);
   var view2 = new Float32Array(arr2);
   gl.getBufferSubData(gl.ARRAY_BUFFER, 0, view2);
   var equal = true;
   for(var i = 0; i < 8; ++i) {
     if (view[i] != view2[i]) equal = false;
   }
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -602,17 +602,16 @@ private:
   DECL_GFX_PREF(Once, "webgl.force-layers-readback",           WebGLForceLayersReadback, 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);
 
   DECL_GFX_PREF(Live, "webgl.webgl2-compat-mode",              WebGL2CompatMode, bool, false);
 
   // WARNING:
   // Please make sure that you've added your new preference to the list above in alphabetical order.
   // Please do not just append it to the end of the list.
 
 public:
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4477,17 +4477,16 @@ pref("webgl.lose-context-on-memory-press
 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);
 pref("webgl.disable-DOM-blit-uploads", false);
-pref("webgl.allow-fb-invalidation", false);
 pref("webgl.webgl2-compat-mode", false);
 
 pref("webgl.enable-webgl2", true);
 
 #ifdef RELEASE_OR_BETA
 // Keep this disabled on Release and Beta for now. (see bug 1171228)
 pref("webgl.enable-debug-renderer-info", false);
 #else